hbviewerautomation.cpp 341 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987139881398913990139911399213993139941399513996139971399813999140001400114002140031400414005140061400714008140091401014011140121401314014140151401614017140181401914020140211402214023140241402514026140271402814029140301403114032140331403414035140361403714038140391404014041140421404314044140451404614047140481404914050140511405214053140541405514056140571405814059140601406114062140631406414065140661406714068140691407014071140721407314074140751407614077140781407914080140811408214083140841408514086140871408814089140901409114092140931409414095140961409714098140991410014101141021410314104141051410614107141081410914110141111411214113141141411514116141171411814119141201412114122141231412414125141261412714128141291413014131141321413314134141351413614137141381413914140141411414214143141441414514146141471414814149141501415114152141531415414155141561415714158141591416014161141621416314164141651416614167141681416914170141711417214173141741417514176141771417814179141801418114182141831418414185141861418714188141891419014191141921419314194141951419614197141981419914200142011420214203142041420514206142071420814209142101421114212142131421414215142161421714218142191422014221142221422314224142251422614227142281422914230142311423214233142341423514236142371423814239142401424114242142431424414245142461424714248142491425014251142521425314254142551425614257142581425914260142611426214263142641426514266142671426814269142701427114272142731427414275142761427714278142791428014281142821428314284142851428614287142881428914290142911429214293142941429514296142971429814299143001430114302143031430414305143061430714308143091431014311143121431314314143151431614317143181431914320143211432214323143241432514326143271432814329143301433114332143331433414335143361433714338143391434014341143421434314344143451434614347143481434914350143511435214353143541435514356143571435814359143601436114362143631436414365143661436714368143691437014371143721437314374143751437614377143781437914380143811438214383143841438514386143871438814389143901439114392143931439414395143961439714398143991440014401144021440314404144051440614407144081440914410144111441214413144141441514416144171441814419144201442114422144231442414425144261442714428144291443014431144321443314434144351443614437144381443914440144411444214443144441444514446144471444814449144501445114452144531445414455144561445714458144591446014461144621446314464144651446614467144681446914470144711447214473144741447514476144771447814479144801448114482144831448414485144861448714488144891449014491144921449314494144951449614497144981449914500145011450214503145041450514506145071450814509145101451114512145131451414515145161451714518145191452014521145221452314524145251452614527145281452914530145311453214533145341453514536145371453814539145401454114542145431454414545145461454714548145491455014551145521455314554145551455614557145581455914560145611456214563145641456514566145671456814569145701457114572145731457414575145761457714578145791458014581145821458314584145851458614587145881458914590145911459214593145941459514596145971459814599146001460114602146031460414605146061460714608146091461014611146121461314614146151461614617146181461914620146211462214623146241462514626146271462814629146301463114632146331463414635146361463714638146391464014641146421464314644146451464614647146481464914650146511465214653146541465514656146571465814659146601466114662146631466414665146661466714668146691467014671146721467314674146751467614677146781467914680146811468214683146841468514686146871468814689146901469114692146931469414695146961469714698146991470014701147021470314704147051470614707147081470914710147111471214713147141471514716147171471814719147201472114722147231472414725147261472714728
  1. /**
  2. * @file hbviewerautomation.cpp
  3. * @brief HBViewerAutomation class implementation
  4. *
  5. * $LicenseInfo:firstyear=2016&license=viewergpl$
  6. *
  7. * Copyright (c) 2016-2024, Henri Beauchamp.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "llviewerprecompiledheaders.h"
  33. #include <deque>
  34. #include <map>
  35. #include "boost/algorithm/string.hpp"
  36. #include "lua.hpp"
  37. #include "hbviewerautomation.h"
  38. #include "imageids.h"
  39. #include "llalertdialog.h"
  40. #include "llatomic.h"
  41. #include "llaudioengine.h"
  42. #include "llbase64.h"
  43. #include "llbutton.h"
  44. #include "llcachename.h"
  45. #include "llcallbacklist.h"
  46. #include "llcheckboxctrl.h"
  47. #include "llclipboard.h"
  48. #include "llcombobox.h"
  49. #include "lldir.h"
  50. #include "lleconomy.h"
  51. #include "hbfastmap.h"
  52. #include "hbfileselector.h"
  53. #include "llfasttimer.h"
  54. #include "lllineeditor.h"
  55. #include "llnamelistctrl.h"
  56. #include "llnotifications.h"
  57. #include "llradiogroup.h"
  58. #include "llscrolllistctrl.h"
  59. #include "llsdserialize.h"
  60. #include "llsliderctrl.h"
  61. #include "llspinctrl.h"
  62. #include "lltexteditor.h"
  63. #include "llthread.h"
  64. #include "lltrans.h"
  65. #include "lluictrlfactory.h"
  66. #include "llmessage.h"
  67. #include "llagent.h"
  68. #include "llagentpilot.h"
  69. #include "llagentwearables.h"
  70. #include "llappearancemgr.h"
  71. #include "llappviewer.h"
  72. #include "llavatartracker.h"
  73. #include "llchatbar.h"
  74. #include "llenvironment.h"
  75. #include "llenvsettings.h"
  76. #include "llfloateractivespeakers.h"
  77. #include "hbfloaterareasearch.h"
  78. #include "llfloateravatarinfo.h"
  79. #include "llfloateravatarpicker.h"
  80. #include "llfloateravatartextures.h"
  81. #include "llfloaterbeacons.h"
  82. #include "hbfloaterbump.h"
  83. #include "llfloatercamera.h"
  84. #include "llfloaterchat.h"
  85. #include "llfloaterchatterbox.h"
  86. #include "llfloaterdebugsettings.h"
  87. #include "hbfloaterdebugtags.h"
  88. #include "llfloaterexperiences.h"
  89. #include "llfloaterfriends.h"
  90. #include "llfloatergesture.h"
  91. #include "llfloatergroupinfo.h"
  92. #include "llfloatergroups.h"
  93. #include "llfloaterim.h"
  94. #include "llfloaterinspect.h"
  95. #include "llfloaterinventory.h"
  96. #include "hbfloaterinvitemspicker.h"
  97. #include "llfloaterland.h"
  98. #include "llfloaterlandholdings.h"
  99. #include "slfloatermediafilter.h"
  100. #include "llfloaterminimap.h"
  101. #include "llfloatermove.h"
  102. #include "llfloatermute.h"
  103. #include "llfloaternearbymedia.h"
  104. #include "llfloaternotificationsconsole.h"
  105. #include "llfloaterpathfindingcharacters.h"
  106. #include "llfloaterpathfindinglinksets.h"
  107. #include "llfloaterpreference.h"
  108. #include "hbfloaterradar.h"
  109. #include "llfloaterregioninfo.h"
  110. #include "hbfloatersearch.h"
  111. #include "llfloatersnapshot.h"
  112. #include "hbfloatersoundslist.h"
  113. #include "llfloaterstats.h"
  114. #include "hbfloaterteleporthistory.h"
  115. #include "llfloatertools.h"
  116. #include "llfloaterworldmap.h"
  117. #include "llfolderview.h"
  118. #include "llgridmanager.h"
  119. #include "llgroupmgr.h"
  120. #include "llimmgr.h"
  121. #include "llinventorymodelfetch.h"
  122. #include "llmutelist.h"
  123. #include "llnotify.h"
  124. #include "lloverlaybar.h"
  125. #include "llpipeline.h"
  126. #include "hbpreprocessor.h"
  127. #include "llpuppetmodule.h"
  128. #include "llpuppetmotion.h"
  129. //MK
  130. #include "mkrlinterface.h"
  131. //mk
  132. #include "llselectmgr.h"
  133. #include "llstartup.h"
  134. #include "llstatusbar.h"
  135. #include "lltooldraganddrop.h"
  136. #include "llurldispatcher.h"
  137. #include "llvieweraudio.h" // For get_valid_sounds()
  138. #include "llviewercontrol.h"
  139. #include "llviewerinventory.h"
  140. #include "llviewermenu.h"
  141. #include "llviewerobjectlist.h"
  142. #include "llviewerparcelmgr.h"
  143. #include "llviewerregion.h"
  144. #include "llviewerwindow.h"
  145. #include "llvoavatarself.h"
  146. #include "llweb.h"
  147. #include "llwlskyparammgr.h"
  148. #include "llwlwaterparammgr.h"
  149. #include "llworldmap.h"
  150. using namespace LLAvatarAppearanceDefines;
  151. HBViewerAutomation* gAutomationp = NULL;
  152. // Note: keep in sync with LLSettingsType::EType
  153. static const std::string sEnvSettingsTypes[] = { "sky", "water", "day" };
  154. enum Picked_types
  155. {
  156. PICKED_LAND = 0,
  157. PICKED_PARTICLE,
  158. PICKED_OBJECT,
  159. PICKED_ATTACHMENT,
  160. PICKED_AVATAR,
  161. PICKED_SELF,
  162. PICKED_INVALID
  163. };
  164. enum Notification_types
  165. {
  166. NOTIFYTIP,
  167. NOTIFICATION,
  168. ALERT,
  169. };
  170. ///////////////////////////////////////////////////////////////////////////////
  171. // HBLuaDialog class (generic usage floater for Lua scripts)
  172. ///////////////////////////////////////////////////////////////////////////////
  173. class HBLuaDialog final : public LLFloater
  174. {
  175. protected:
  176. LOG_CLASS(HBLuaDialog);
  177. public:
  178. static HBLuaDialog* create(const std::string& title,
  179. const std::string& text,
  180. const std::string& suggestion,
  181. const std::string& btn1,
  182. const std::string& btn2,
  183. const std::string& btn3,
  184. const std::string& command1,
  185. const std::string& command2,
  186. const std::string& command3);
  187. private:
  188. // Use the create() method to create the floater.
  189. HBLuaDialog(const LLSD& parameters);
  190. ~HBLuaDialog() override;
  191. bool postBuild() override;
  192. // Returns true when the dialog shall be closed
  193. bool evalLuaCommand(const std::string& command);
  194. static void onButton(LLUICtrl* ctrl, void* userdata);
  195. private:
  196. LLLineEditor* mInputLine;
  197. S32 mPressedButton;
  198. LLSD mParameters;
  199. };
  200. //static
  201. HBLuaDialog* HBLuaDialog::create(const std::string& title,
  202. const std::string& text,
  203. const std::string& suggestion,
  204. const std::string& btn1,
  205. const std::string& btn2,
  206. const std::string& btn3,
  207. const std::string& command1,
  208. const std::string& command2,
  209. const std::string& command3)
  210. {
  211. LLSD parameters = LLSD::emptyMap();
  212. parameters["title"] = title;
  213. parameters["suggestion"] = suggestion;
  214. if (!text.empty())
  215. {
  216. parameters["text"] = text;
  217. }
  218. if (!btn1.empty())
  219. {
  220. parameters["btn1"] = btn1;
  221. parameters["command1"] = command1;
  222. }
  223. if (!btn2.empty())
  224. {
  225. parameters["btn2"] = btn2;
  226. parameters["command2"] = command2;
  227. }
  228. if (!btn3.empty())
  229. {
  230. parameters["btn3"] = btn3;
  231. parameters["command3"] = command3;
  232. }
  233. LL_DEBUGS("Lua") << "Creating new Lua dialog with parameters:\n";
  234. std::stringstream str;
  235. LLSDSerialize::toPrettyXML(parameters, str);
  236. LL_CONT << "\n" << str.str() << LL_ENDL;
  237. return new HBLuaDialog(parameters);
  238. }
  239. HBLuaDialog::HBLuaDialog(const LLSD& parameters)
  240. : mParameters(parameters),
  241. mPressedButton(0)
  242. {
  243. LLUICtrlFactory::getInstance()->buildFloater(this,
  244. "floater_lua_dialog.xml");
  245. // If the user did not yet change the floater position, center the latter.
  246. LLControlVariable* controlp =
  247. gSavedSettings.getControl(getRectControl().c_str());
  248. if (!controlp || controlp->isDefault())
  249. {
  250. center();
  251. }
  252. }
  253. //virtual
  254. HBLuaDialog::~HBLuaDialog()
  255. {
  256. if (gAutomationp)
  257. {
  258. gAutomationp->onLuaDialogClose(mParameters["title"].asString(),
  259. mPressedButton, mInputLine->getText());
  260. }
  261. }
  262. //virtual
  263. bool HBLuaDialog::postBuild()
  264. {
  265. setTitle(mParameters["title"].asString());
  266. LLButton* button = getChild<LLButton>("btn1");
  267. if (mParameters.has("btn1"))
  268. {
  269. button->setLabel(mParameters["btn1"].asString());
  270. button->setCommitCallback(onButton);
  271. button->setCallbackUserData(this);
  272. }
  273. else
  274. {
  275. button->setEnabled(false);
  276. button->setVisible(false);
  277. }
  278. button = getChild<LLButton>("btn2");
  279. if (mParameters.has("btn2"))
  280. {
  281. button->setLabel(mParameters["btn2"].asString());
  282. button->setCommitCallback(onButton);
  283. button->setCallbackUserData(this);
  284. }
  285. else
  286. {
  287. button->setEnabled(false);
  288. button->setVisible(false);
  289. }
  290. button = getChild<LLButton>("btn3");
  291. if (mParameters.has("btn3"))
  292. {
  293. button->setLabel(mParameters["btn3"].asString());
  294. button->setCommitCallback(onButton);
  295. button->setCallbackUserData(this);
  296. }
  297. else
  298. {
  299. button->setEnabled(false);
  300. button->setVisible(false);
  301. }
  302. LLTextEditor* textedit = getChild<LLTextEditor>("text");
  303. textedit->setBorderVisible(false);
  304. if (mParameters.has("text"))
  305. {
  306. std::string text = mParameters["text"].asString();
  307. textedit->setParseHTML(true);
  308. textedit->appendColoredText(text, false, false,
  309. gColors.getColor("TextFgReadOnlyColor"));
  310. }
  311. mInputLine = getChild<LLLineEditor>("input");
  312. std::string suggestion = mParameters["suggestion"].asString();
  313. if (suggestion == " ")
  314. {
  315. mInputLine->setEnabled(false);
  316. mInputLine->setVisible(false);
  317. }
  318. else if (suggestion == "*")
  319. {
  320. mInputLine->setDrawAsterixes(true);
  321. }
  322. else if (!suggestion.empty())
  323. {
  324. mInputLine->setText(suggestion);
  325. }
  326. return true;
  327. }
  328. bool HBLuaDialog::evalLuaCommand(const std::string& command)
  329. {
  330. bool close = false;
  331. // Setup dialog-specific Lua global variables
  332. std::string functions = "V_DIALOG_CLOSE=false;V_DIALOG_INPUT=\"";
  333. std::string text = mInputLine->getText();
  334. LLStringUtil::replaceString(text, "\"", "\\\"");
  335. functions += text + "\";";
  336. // Setup dialog-specific Lua functions using the global variables
  337. functions += "function DialogClose();V_DIALOG_CLOSE=true;end;";
  338. functions += "function GetDialogInput();return V_DIALOG_INPUT;end;";
  339. functions += "function SetDialogInput(text);V_DIALOG_INPUT=text;end;";
  340. HBViewerAutomation lua;
  341. lua_State* state = lua.mLuaState;
  342. if (state && lua.loadString(functions + command))
  343. {
  344. // Retreive and interpret the global variables values
  345. lua_getglobal(state, "V_DIALOG_INPUT");
  346. text = lua_tostring(state, -1);
  347. if (mInputLine->getText() != text)
  348. {
  349. mInputLine->setText(text);
  350. }
  351. lua_getglobal(state, "V_DIALOG_CLOSE");
  352. close = lua_toboolean(state, -1);
  353. }
  354. return close;
  355. }
  356. //static
  357. void HBLuaDialog::onButton(LLUICtrl* ctrl, void* userdata)
  358. {
  359. HBLuaDialog* self = (HBLuaDialog*)userdata;
  360. if (!self || !ctrl) return;
  361. std::string command;
  362. std::string name = ctrl->getName();
  363. if (name == "btn1")
  364. {
  365. self->mPressedButton = 1;
  366. command = self->mParameters["command1"].asString();
  367. }
  368. else if (name == "btn2")
  369. {
  370. self->mPressedButton = 2;
  371. command = self->mParameters["command2"].asString();
  372. }
  373. else if (name == "btn3")
  374. {
  375. self->mPressedButton = 3;
  376. command = self->mParameters["command3"].asString();
  377. }
  378. if (!command.empty() && self->evalLuaCommand(command))
  379. {
  380. self->close();
  381. }
  382. else
  383. {
  384. self->mPressedButton = 0;
  385. }
  386. }
  387. ///////////////////////////////////////////////////////////////////////////////
  388. // HBLuaFloater class (custom floaters support for the Lua scripts)
  389. ///////////////////////////////////////////////////////////////////////////////
  390. class HBLuaFloater final : public LLFloater
  391. {
  392. protected:
  393. LOG_CLASS(HBLuaFloater);
  394. public:
  395. LL_INLINE HBLuaFloater* asLuaFloater() override { return this; }
  396. static HBLuaFloater* create(const std::string& name,
  397. const std::string& parameter,
  398. const std::string& position, bool open);
  399. static bool setVisible(const std::string& name, bool show);
  400. static void destroy(const std::string& name, bool excute_callback);
  401. static bool setControlCallback(const std::string& floater_name,
  402. const std::string& ctrl_name,
  403. const std::string& lua_command);
  404. static void registerUICommand(LLUICtrl* ctrlp, LLView* parentp,
  405. const std::string& command);
  406. static bool getControlValue(const std::string& floater_name,
  407. const std::string& ctrl_name,
  408. std::string& value);
  409. static bool getControlValues(const std::string& floater_name,
  410. const std::string& ctrl_name,
  411. std::vector<std::string>& values);
  412. static bool setControlValue(const std::string& floater_name,
  413. const std::string& ctrl_name,
  414. const std::string& value);
  415. static bool setInvFilter(const std::string& floater_name,
  416. const std::string& ctrl_name,
  417. const std::string& value);
  418. static bool setControlEnabled(const std::string& floater_name,
  419. const std::string& ctrl_name, bool enable);
  420. static bool setControlVisible(const std::string& floater_name,
  421. const std::string& ctrl_name, bool visible);
  422. private:
  423. // Use the create() method to create the floater.
  424. HBLuaFloater(const std::string& name, const std::string& parameter);
  425. ~HBLuaFloater() override;
  426. bool postBuild() override;
  427. void onOpen() override;
  428. void onClose(bool app_quitting) override;
  429. bool evalLuaCommand(const std::string& command, std::string value,
  430. bool with_close = false);
  431. bool setControlCallback(LLUICtrl* ctrlp, const std::string& lua_command);
  432. static std::string getCtrlValue(LLUICtrl* ctrlp);
  433. static void getCtrlValues(LLUICtrl* ctrlp,
  434. std::vector<std::string>& values);
  435. static bool setCtrlValue(LLUICtrl* ctrlp, const std::string& value);
  436. static void onCommitCallback(LLUICtrl* ctrlp, void* userdata);
  437. static void onSearchEdit(const std::string& search_string, void* userdata);
  438. static void onInventorySelect(LLFolderView* ctrlp, bool user_action,
  439. void* userdata);
  440. private:
  441. std::string mLuaName;
  442. std::string mParameter;
  443. typedef fast_hmap<LLUICtrl*, std::string> commands_map_t;
  444. commands_map_t mCommands;
  445. bool mInitOK;
  446. typedef std::map<std::string, HBLuaFloater*> instances_map_t;
  447. static instances_map_t sInstances;
  448. };
  449. HBLuaFloater::instances_map_t HBLuaFloater::sInstances;
  450. //static
  451. HBLuaFloater* HBLuaFloater::create(const std::string& name,
  452. const std::string& parameter,
  453. const std::string& position,
  454. bool open)
  455. {
  456. // Refuse to open two floaters with "dialog" as the name since the
  457. // corresponding XML file name is already used by our HBLuaDialog class.
  458. if (name == "dialog" || name == "console")
  459. {
  460. llwarns << "The '" << name
  461. << "' Lua floater name is reserved. Aborted." << llendl;
  462. return NULL;
  463. }
  464. // Sanitize the name to remove forbidden file name characters
  465. std::string fname = LLDir::getScrubbedFileName(name);
  466. // Refuse to open two floaters with the same name
  467. if (sInstances.count(fname))
  468. {
  469. llwarns << "Floater '" << fname
  470. << "'is already opened, not opening a second instance."
  471. << llendl;
  472. return NULL;
  473. }
  474. HBLuaFloater* self = new HBLuaFloater(fname, parameter);
  475. fname = "floater_lua_" + fname + ".xml";
  476. if (!LLUICtrlFactory::getInstance()->buildFloater(self, fname, NULL, open))
  477. {
  478. self->mInitOK = false;
  479. delete self;
  480. return NULL;
  481. }
  482. if (position.empty() || position == "center")
  483. {
  484. self->center();
  485. return self;
  486. }
  487. const LLRect& view = gFloaterViewp->getRect();
  488. LLRect r = self->getRect();
  489. if (position == "top" || position == "top-center")
  490. {
  491. r.setLeftTopAndSize((view.getWidth() - r.getWidth()) / 2,
  492. view.getHeight(), r.getWidth(), r.getHeight());
  493. }
  494. else if (position == "bottom" || position == "bottom-center")
  495. {
  496. r.setOriginAndSize((view.getWidth() - r.getWidth()) / 2, view.mBottom,
  497. r.getWidth(), r.getHeight());
  498. }
  499. else if (position == "left" || position == "left-center")
  500. {
  501. r.setLeftTopAndSize(0,
  502. view.getHeight() -
  503. (view.getHeight() - r.getHeight()) / 2,
  504. r.getWidth(), r.getHeight());
  505. }
  506. else if (position == "right" || position == "right-center")
  507. {
  508. r.setLeftTopAndSize(view.getWidth() - r.getWidth(),
  509. view.getHeight() -
  510. (view.getHeight() - r.getHeight()) / 2,
  511. r.getWidth(), r.getHeight());
  512. }
  513. else if (position == "top-left")
  514. {
  515. r.setLeftTopAndSize(0, view.getHeight(), r.getWidth(), r.getHeight());
  516. }
  517. else if (position == "top-right")
  518. {
  519. r.setLeftTopAndSize(view.getWidth() - r.getWidth(), view.getHeight(),
  520. r.getWidth(), r.getHeight());
  521. }
  522. else if (position == "bottom-left")
  523. {
  524. r.setOriginAndSize(0, view.mBottom, r.getWidth(), r.getHeight());
  525. }
  526. else if (position == "bottom-right")
  527. {
  528. r.setOriginAndSize(view.getWidth() - r.getWidth(), view.mBottom,
  529. r.getWidth(), r.getHeight());
  530. }
  531. else
  532. {
  533. llwarns << "Unrecognized position parameter '" << position
  534. << "' for floater: " << name << llendl;
  535. }
  536. self->translateIntoRect(r, false);
  537. return self;
  538. }
  539. //static
  540. bool HBLuaFloater::setVisible(const std::string& name, bool show)
  541. {
  542. instances_map_t::iterator it = sInstances.find(name);
  543. if (it == sInstances.end())
  544. {
  545. return false;
  546. }
  547. LLFloater* self = (LLFloater*)it->second;
  548. bool visible = self->getVisible();
  549. if (show && !visible)
  550. {
  551. self->open();
  552. }
  553. else if (!show && visible)
  554. {
  555. self->setVisible(false);
  556. }
  557. return true;
  558. }
  559. //static
  560. void HBLuaFloater::destroy(const std::string& name, bool excute_callback)
  561. {
  562. instances_map_t::iterator it = sInstances.find(name);
  563. if (it != sInstances.end())
  564. {
  565. HBLuaFloater* self = it->second;
  566. if (!excute_callback)
  567. {
  568. // Do not call the OnLuaFloaterClose() callback:
  569. self->mInitOK = false;
  570. }
  571. self->close();
  572. }
  573. }
  574. bool HBLuaFloater::setControlCallback(LLUICtrl* ctrlp,
  575. const std::string& lua_command)
  576. {
  577. mCommands[ctrlp] = lua_command;
  578. // For inventory panels, we use a special commit on selection callback
  579. LLInventoryPanel* invp = dynamic_cast<LLInventoryPanel*>(ctrlp);
  580. if (invp)
  581. {
  582. invp->setSelectCallback(onInventorySelect, this);
  583. return true;
  584. }
  585. // For search editors, use a special commit callback too.
  586. LLSearchEditor* searcheditp = dynamic_cast<LLSearchEditor*>(ctrlp);
  587. if (searcheditp)
  588. {
  589. searcheditp->setSearchCallback(onSearchEdit, searcheditp);
  590. return true;
  591. }
  592. // For all other control types, use the LLUICtrl commit callback
  593. ctrlp->setCommitCallback(onCommitCallback);
  594. ctrlp->setCallbackUserData(this);
  595. // For line and text editors controls, we commit on lost focus
  596. LLLineEditor* lineeditp = dynamic_cast<LLLineEditor*>(ctrlp);
  597. if (lineeditp)
  598. {
  599. lineeditp->setCommitOnFocusLost(true);
  600. return true;
  601. }
  602. LLTextEditor* texteditp = dynamic_cast<LLTextEditor*>(ctrlp);
  603. if (texteditp)
  604. {
  605. texteditp->setCommitOnFocusLost(true);
  606. return true;
  607. }
  608. // For scroll list controls (and derived classes such as name list), we
  609. // commit on selection change
  610. LLScrollListCtrl* listp = dynamic_cast<LLScrollListCtrl*>(ctrlp);
  611. if (listp)
  612. {
  613. listp->setCommitOnSelectionChange(true);
  614. }
  615. return true;
  616. }
  617. //static
  618. bool HBLuaFloater::setControlCallback(const std::string& floater_name,
  619. const std::string& ctrl_name,
  620. const std::string& lua_command)
  621. {
  622. instances_map_t::iterator it = sInstances.find(floater_name);
  623. if (it == sInstances.end())
  624. {
  625. return false;
  626. }
  627. HBLuaFloater* self = it->second;
  628. LLUICtrl* ctrlp = self->getChild<LLUICtrl>(ctrl_name.c_str(), true, false);
  629. if (!ctrlp)
  630. {
  631. return false;
  632. }
  633. return self->setControlCallback(ctrlp, lua_command);
  634. }
  635. //static
  636. void HBLuaFloater::registerUICommand(LLUICtrl* ctrlp, LLView* parentp,
  637. const std::string& lua_command)
  638. {
  639. if (!ctrlp || !parentp || lua_command.empty())
  640. {
  641. return;
  642. }
  643. // Search for the Lua floater this UI control pertains to, if any.
  644. HBLuaFloater* self = NULL;
  645. while (!self && parentp)
  646. {
  647. self = parentp->asLuaFloater();
  648. parentp = parentp->getParent();
  649. }
  650. if (!self)
  651. {
  652. llwarns << "Control " << ctrlp->getName()
  653. << " is not part of a Lua floater: 'lua_command' attribute ignored."
  654. << llendl;
  655. return;
  656. }
  657. if (!self->setControlCallback(ctrlp, lua_command))
  658. {
  659. llwarns << "Failed to set Lua command for control: "
  660. << ctrlp->getName() << llendl;
  661. }
  662. }
  663. // A mere wrapper function to avoid declaring HBLuaFloater in the
  664. // hbviewerautomation.h header.
  665. void register_ui_lua_command(LLUICtrl* ctrlp, LLView* parentp,
  666. const std::string& command)
  667. {
  668. HBLuaFloater::registerUICommand(ctrlp, parentp, command);
  669. }
  670. //static
  671. bool HBLuaFloater::getControlValue(const std::string& floater_name,
  672. const std::string& ctrl_name,
  673. std::string& value)
  674. {
  675. instances_map_t::iterator it = sInstances.find(floater_name);
  676. if (it == sInstances.end())
  677. {
  678. return false;
  679. }
  680. HBLuaFloater* self = it->second;
  681. LLUICtrl* ctrl = self->getChild<LLUICtrl>(ctrl_name.c_str(), true, false);
  682. if (!ctrl)
  683. {
  684. return false;
  685. }
  686. value.assign(getCtrlValue(ctrl));
  687. return true;
  688. }
  689. //static
  690. bool HBLuaFloater::getControlValues(const std::string& floater_name,
  691. const std::string& ctrl_name,
  692. std::vector<std::string>& values)
  693. {
  694. instances_map_t::iterator it = sInstances.find(floater_name);
  695. if (it == sInstances.end())
  696. {
  697. return false;
  698. }
  699. HBLuaFloater* self = it->second;
  700. LLUICtrl* ctrl = self->getChild<LLUICtrl>(ctrl_name.c_str(), true, false);
  701. if (!ctrl)
  702. {
  703. return false;
  704. }
  705. getCtrlValues(ctrl, values);
  706. return true;
  707. }
  708. //static
  709. bool HBLuaFloater::setControlValue(const std::string& floater_name,
  710. const std::string& ctrl_name,
  711. const std::string& value)
  712. {
  713. instances_map_t::iterator it = sInstances.find(floater_name);
  714. if (it == sInstances.end())
  715. {
  716. return false;
  717. }
  718. HBLuaFloater* self = it->second;
  719. LLUICtrl* ctrlp = self->getChild<LLUICtrl>(ctrl_name.c_str(), true, false);
  720. if (!ctrlp)
  721. {
  722. return false;
  723. }
  724. return setCtrlValue(ctrlp, value);
  725. }
  726. //static
  727. bool HBLuaFloater::setInvFilter(const std::string& floater_name,
  728. const std::string& ctrl_name,
  729. const std::string& value)
  730. {
  731. instances_map_t::iterator it = sInstances.find(floater_name);
  732. if (it == sInstances.end())
  733. {
  734. return false;
  735. }
  736. HBLuaFloater* self = it->second;
  737. LLInventoryPanel* invp =
  738. self->getChild<LLInventoryPanel>(ctrl_name.c_str(), true, false);
  739. if (!invp)
  740. {
  741. return false;
  742. }
  743. invp->setFilterSubString(value);
  744. return true;
  745. }
  746. //static
  747. bool HBLuaFloater::setControlEnabled(const std::string& floater_name,
  748. const std::string& ctrl_name, bool enable)
  749. {
  750. instances_map_t::iterator it = sInstances.find(floater_name);
  751. if (it == sInstances.end())
  752. {
  753. return false;
  754. }
  755. HBLuaFloater* self = it->second;
  756. LLUICtrl* ctrlp = self->getChild<LLUICtrl>(ctrl_name.c_str(), true, false);
  757. if (!ctrlp)
  758. {
  759. return false;
  760. }
  761. ctrlp->setEnabled(enable);
  762. return true;
  763. }
  764. //static
  765. bool HBLuaFloater::setControlVisible(const std::string& floater_name,
  766. const std::string& ctrl_name,
  767. bool visible)
  768. {
  769. instances_map_t::iterator it = sInstances.find(floater_name);
  770. if (it == sInstances.end())
  771. {
  772. return false;
  773. }
  774. HBLuaFloater* self = it->second;
  775. LLUICtrl* ctrlp = self->getChild<LLUICtrl>(ctrl_name.c_str(), true, false);
  776. if (!ctrlp)
  777. {
  778. return false;
  779. }
  780. ctrlp->setVisible(visible);
  781. return true;
  782. }
  783. HBLuaFloater::HBLuaFloater(const std::string& name,
  784. const std::string& parameter)
  785. : mLuaName(name),
  786. mParameter(parameter),
  787. mInitOK(false)
  788. {
  789. sInstances[mLuaName] = this;
  790. }
  791. //virtual
  792. HBLuaFloater::~HBLuaFloater()
  793. {
  794. sInstances.erase(mLuaName);
  795. }
  796. //virtual
  797. bool HBLuaFloater::postBuild()
  798. {
  799. std::string name = getTitle();
  800. LLStringUtil::trimHead(name);
  801. LLStringUtil::toLower(name);
  802. if (name.compare(0, 3, "lua") != 0)
  803. {
  804. setTitle("Lua: " + getTitle());
  805. }
  806. U32 i = 0;
  807. LLButton* buttonp;
  808. while ((buttonp = getChild<LLButton>(llformat("button%d", ++i).c_str(),
  809. true, false)))
  810. {
  811. buttonp->setCommitCallback(onCommitCallback);
  812. buttonp->setCallbackUserData(this);
  813. }
  814. i = 0;
  815. LLCheckBoxCtrl* checkp;
  816. while ((checkp = getChild<LLCheckBoxCtrl>(llformat("check%d", ++i).c_str(),
  817. true, false)))
  818. {
  819. checkp->setCommitCallback(onCommitCallback);
  820. checkp->setCallbackUserData(this);
  821. }
  822. i = 0;
  823. LLRadioGroup* radiop;
  824. while ((radiop = getChild<LLRadioGroup>(llformat("radio%d", ++i).c_str(),
  825. true, false)))
  826. {
  827. radiop->setCommitCallback(onCommitCallback);
  828. radiop->setCallbackUserData(this);
  829. }
  830. i = 0;
  831. LLComboBox* combop;
  832. while ((combop = getChild<LLComboBox>(llformat("combo%d", ++i).c_str(),
  833. true, false)))
  834. {
  835. combop->setCommitCallback(onCommitCallback);
  836. combop->setCallbackUserData(this);
  837. }
  838. i = 0;
  839. LLFlyoutButton* flyp;
  840. while ((flyp = getChild<LLFlyoutButton>(llformat("flyout%d", ++i).c_str(),
  841. true, false)))
  842. {
  843. flyp->setCommitCallback(onCommitCallback);
  844. flyp->setCallbackUserData(this);
  845. }
  846. i = 0;
  847. LLSliderCtrl* sliderp;
  848. while ((sliderp = getChild<LLSliderCtrl>(llformat("slider%d", ++i).c_str(),
  849. true, false)))
  850. {
  851. sliderp->setCommitCallback(onCommitCallback);
  852. sliderp->setCallbackUserData(this);
  853. }
  854. i = 0;
  855. LLSpinCtrl* spinp;
  856. while ((spinp = getChild<LLSpinCtrl>(llformat("spin%d", ++i).c_str(), true,
  857. false)))
  858. {
  859. spinp->setCommitCallback(onCommitCallback);
  860. spinp->setCallbackUserData(this);
  861. }
  862. i = 0;
  863. LLSearchEditor* searchp;
  864. while ((searchp = getChild<LLSearchEditor>(llformat("searchedit%d",
  865. ++i).c_str(),
  866. true, false)))
  867. {
  868. searchp->setSearchCallback(onSearchEdit, searchp);
  869. name = mLuaName + " " + searchp->getName();
  870. searchp->setCustomMenuType(name.c_str());
  871. }
  872. i = 0;
  873. LLLineEditor* linep;
  874. while ((linep = getChild<LLLineEditor>(llformat("lineedit%d", ++i).c_str(),
  875. true, false)))
  876. {
  877. linep->setCommitCallback(onCommitCallback);
  878. linep->setCallbackUserData(this);
  879. linep->setCommitOnFocusLost(true);
  880. name = mLuaName + " " + linep->getName();
  881. linep->setCustomMenuType(name.c_str());
  882. }
  883. i = 0;
  884. LLTextEditor* textp;
  885. while ((textp = getChild<LLTextEditor>(llformat("textedit%d", ++i).c_str(),
  886. true, false)))
  887. {
  888. textp->setCommitCallback(onCommitCallback);
  889. textp->setCallbackUserData(this);
  890. textp->setCommitOnFocusLost(true);
  891. name = mLuaName + " " + textp->getName();
  892. textp->setCustomMenuType(name.c_str());
  893. }
  894. i = 0;
  895. LLScrollListCtrl* listp;
  896. while ((listp = getChild<LLScrollListCtrl>(llformat("list%d", ++i).c_str(),
  897. true, false)))
  898. {
  899. listp->setCommitCallback(onCommitCallback);
  900. listp->setCallbackUserData(this);
  901. listp->setCommitOnSelectionChange(true);
  902. }
  903. i = 0;
  904. LLScrollListCtrl* namep;
  905. while ((namep = getChild<LLNameListCtrl>(llformat("namelist%d",
  906. ++i).c_str(),
  907. true, false)))
  908. {
  909. namep->setCommitCallback(onCommitCallback);
  910. namep->setCallbackUserData(this);
  911. namep->setCommitOnSelectionChange(true);
  912. }
  913. i = 0;
  914. LLInventoryPanel* invp;
  915. while ((invp = getChild<LLInventoryPanel>(llformat("inventory%d",
  916. ++i).c_str(),
  917. true, false)))
  918. {
  919. invp->setSelectCallback(onInventorySelect, this);
  920. }
  921. mInitOK = true;
  922. return true;
  923. }
  924. //virtual
  925. void HBLuaFloater::onOpen()
  926. {
  927. if (mInitOK && gAutomationp)
  928. {
  929. gAutomationp->onLuaFloaterOpen(mLuaName, mParameter);
  930. }
  931. }
  932. //virtual
  933. void HBLuaFloater::onClose(bool app_quitting)
  934. {
  935. if (mInitOK && gAutomationp)
  936. {
  937. gAutomationp->onLuaFloaterClose(mLuaName, mParameter);
  938. }
  939. LLFloater::onClose(app_quitting); // Calls LLFloater::destroy()
  940. }
  941. bool HBLuaFloater::evalLuaCommand(const std::string& command,
  942. std::string value, bool with_close)
  943. {
  944. bool close = false;
  945. // Setup floater-specific Lua global variables and functions
  946. std::string functions = "V_UICTRL_VALUE=\"";
  947. LLStringUtil::replaceString(value, "\"", "\\\"");
  948. functions += value + "\";";
  949. functions += "V_FLOATER_NAME=\"" + mLuaName + "\";";
  950. value = mParameter;
  951. LLStringUtil::replaceString(value, "\"", "\\\"");
  952. functions += "V_FLOATER_PARAM=\"" + value + "\";";
  953. functions += "function GetValue();return V_UICTRL_VALUE;end;";
  954. functions += "function GetFloaterName();return V_FLOATER_NAME;end;";
  955. functions += "function GetFloaterParam();return V_FLOATER_PARAM;end;";
  956. if (with_close)
  957. {
  958. functions += "V_FLOATER_CLOSE=false;";
  959. functions += "function FloaterClose();V_FLOATER_CLOSE=true;end;";
  960. }
  961. HBViewerAutomation lua;
  962. bool success = lua.loadString(functions + command);
  963. if (success && with_close)
  964. {
  965. lua_State* state = lua.mLuaState;
  966. if (state)
  967. {
  968. // Retreive and interpret the global variable value
  969. lua_getglobal(state, "V_FLOATER_CLOSE");
  970. close = lua_toboolean(state, -1);
  971. }
  972. }
  973. return close;
  974. }
  975. //static
  976. std::string HBLuaFloater::getCtrlValue(LLUICtrl* ctrlp)
  977. {
  978. LLInventoryPanel* panelp = dynamic_cast<LLInventoryPanel*>(ctrlp);
  979. if (panelp)
  980. {
  981. ctrlp = panelp->getRootFolder();
  982. if (!ctrlp) return "";
  983. }
  984. LLFolderView* invp = dynamic_cast<LLFolderView*>(ctrlp);
  985. if (invp)
  986. {
  987. std::string result;
  988. const LLFolderView::selected_items_t& items = invp->getSelectedItems();
  989. LLFolderView::selected_items_t::const_iterator it = items.begin();
  990. if (it != items.end())
  991. {
  992. const LLFolderViewEventListener* listenerp = (*it)->getListener();
  993. if (listenerp)
  994. {
  995. result = listenerp->getUUID().asString();
  996. }
  997. }
  998. return result;
  999. }
  1000. LLCheckBoxCtrl* checkp = dynamic_cast<LLCheckBoxCtrl*>(ctrlp);
  1001. if (checkp)
  1002. {
  1003. return checkp->get() ? "true": "false";
  1004. }
  1005. return ctrlp->getValue().asString();
  1006. }
  1007. //static
  1008. void HBLuaFloater::getCtrlValues(LLUICtrl* ctrlp,
  1009. std::vector<std::string>& values)
  1010. {
  1011. LLInventoryPanel* panelp = dynamic_cast<LLInventoryPanel*>(ctrlp);
  1012. if (panelp)
  1013. {
  1014. ctrlp = panelp->getRootFolder();
  1015. if (!ctrlp) return;
  1016. }
  1017. LLFolderView* invp = dynamic_cast<LLFolderView*>(ctrlp);
  1018. if (invp)
  1019. {
  1020. const LLFolderView::selected_items_t& items = invp->getSelectedItems();
  1021. for (LLFolderView::selected_items_t::const_iterator it = items.begin(),
  1022. end = items.end();
  1023. it != end; ++it)
  1024. {
  1025. const LLFolderViewEventListener* listenerp = (*it)->getListener();
  1026. if (listenerp)
  1027. {
  1028. values.emplace_back(listenerp->getUUID().asString());
  1029. }
  1030. }
  1031. return;
  1032. }
  1033. // Note: name list controls share this code, LLNameListCtrl being a derived
  1034. // class of LLScrollListCtrl.
  1035. LLScrollListCtrl* listp = dynamic_cast<LLScrollListCtrl*>(ctrlp);
  1036. if (listp)
  1037. {
  1038. std::vector<LLScrollListItem*> items = listp->getAllSelected();
  1039. for (S32 i = 0, count = items.size(); i < count; ++i)
  1040. {
  1041. values.emplace_back(items[i]->getValue().asString());
  1042. }
  1043. return;
  1044. }
  1045. LLCheckBoxCtrl* checkp = dynamic_cast<LLCheckBoxCtrl*>(ctrlp);
  1046. if (checkp)
  1047. {
  1048. values.emplace_back(checkp->get() ? "true": "false");
  1049. return;
  1050. }
  1051. // Valid for other UI element types.
  1052. values.emplace_back(ctrlp->getValue().asString());
  1053. }
  1054. //static
  1055. bool HBLuaFloater::setCtrlValue(LLUICtrl* ctrlp, const std::string& value)
  1056. {
  1057. // For line and text editors controls, we set their text
  1058. LLLineEditor* lineeditp = dynamic_cast<LLLineEditor*>(ctrlp);
  1059. if (lineeditp)
  1060. {
  1061. lineeditp->setText(value);
  1062. return true;
  1063. }
  1064. LLTextEditor* texteditp = dynamic_cast<LLTextEditor*>(ctrlp);
  1065. if (texteditp)
  1066. {
  1067. texteditp->setText(value);
  1068. return true;
  1069. }
  1070. // For inventory panels, we set the filter to open a corresponding folder
  1071. // and its descendents only.
  1072. LLInventoryPanel* panelp = dynamic_cast<LLInventoryPanel*>(ctrlp);
  1073. if (panelp)
  1074. {
  1075. LLFolderView* invp = panelp->getRootFolder();
  1076. if (!invp) return false;
  1077. bool is_category = false;
  1078. const LLUUID& cat_id =
  1079. HBViewerAutomation::getInventoryObjectId(value, is_category);
  1080. if (!is_category) return false;
  1081. LLInventoryFilter* filterp = panelp->getFilter();
  1082. if (!filterp) return false;
  1083. if (filterp->isActive())
  1084. {
  1085. // If our filter is active we may be the first thing requiring a
  1086. // fetch in this folder, so we better start it here.
  1087. LLInventoryModelFetch::getInstance()->start(cat_id);
  1088. }
  1089. // Do not open recursively all sub-folders in the target folder.
  1090. invp->setCanAutoSelect(false);
  1091. // But open all folders on the path from root to the target folder.
  1092. LLFolderViewFolder* folderp =
  1093. dynamic_cast<LLFolderViewFolder*>(invp->getItemByID(cat_id));
  1094. LLFolderViewFolder* rootp = dynamic_cast<LLFolderViewFolder*>(invp);
  1095. if (rootp) // Paranoia
  1096. {
  1097. while (folderp && folderp != rootp)
  1098. {
  1099. invp->setSelection(folderp, false, false);
  1100. folderp->setOpen(true);
  1101. folderp = folderp->getParentFolder();
  1102. }
  1103. }
  1104. panelp->setLastOpenLocked(true);
  1105. panelp->setFilterLastOpen(true);
  1106. panelp->setFilterShowLinks(true);
  1107. filterp->markDefault();
  1108. filterp->setLastOpenID(cat_id);
  1109. filterp->setModified(LLInventoryFilter::FILTER_RESTART);
  1110. return true;
  1111. }
  1112. // For name lists, we support only simple ones (with just one column), and
  1113. // set the new value by UUID, with <GROUP> as a group tag marker.
  1114. LLNameListCtrl* namelistp = dynamic_cast<LLNameListCtrl*>(ctrlp);
  1115. if (namelistp)
  1116. {
  1117. if (value.empty())
  1118. {
  1119. namelistp->clearRows();
  1120. return true;
  1121. }
  1122. bool is_group = false;
  1123. std::string uuid_str = value;
  1124. if (uuid_str.compare(0, 7, "<GROUP>") == 0)
  1125. {
  1126. uuid_str = uuid_str.substr(7);
  1127. is_group = true;
  1128. }
  1129. if (!LLUUID::validate(uuid_str))
  1130. {
  1131. return false;
  1132. }
  1133. if (is_group)
  1134. {
  1135. namelistp->addGroupNameItem(LLUUID(uuid_str));
  1136. }
  1137. else
  1138. {
  1139. namelistp->addNameItem(LLUUID(uuid_str));
  1140. }
  1141. return true;
  1142. }
  1143. // For scroll lists, the case is more complex... We split the string using
  1144. // the pipe character as a separator, to get the various columns from the
  1145. // 'value' string, and set them as a new line for the list.
  1146. LLScrollListCtrl* listp = dynamic_cast<LLScrollListCtrl*>(ctrlp);
  1147. if (listp)
  1148. {
  1149. if (value.empty())
  1150. {
  1151. listp->clearRows();
  1152. return true;
  1153. }
  1154. LLSD element;
  1155. std::vector<std::string> cols;
  1156. boost::split(cols, value, boost::is_any_of("|"));
  1157. std::string col, style;
  1158. for (S32 i = 0, count = cols.size(); i < count; ++i)
  1159. {
  1160. element["columns"][i]["column"] = llformat("col%d", i);
  1161. col = cols[i];
  1162. // Check for font style "<BOLD>" and/or "<ITALIC>" markers
  1163. style.clear();
  1164. if (col.compare(0, 6, "<BOLD>") == 0)
  1165. {
  1166. col = col.substr(6);
  1167. style = "BOLD";
  1168. }
  1169. if (col.compare(0, 8, "<ITALIC>") == 0)
  1170. {
  1171. col = col.substr(8);
  1172. if (!style.empty())
  1173. {
  1174. style += '|';
  1175. }
  1176. style += "ITALIC";
  1177. }
  1178. if (!style.empty())
  1179. {
  1180. element["columns"][i]["font-style"] = style;
  1181. }
  1182. // Check for color <name> or <r,g,b> marker
  1183. if (col.compare(0, 1, "<") == 0)
  1184. {
  1185. size_t j = col.find('>');
  1186. if (j != std::string::npos)
  1187. {
  1188. LLColor4 color;
  1189. if (LLColor4::parseColor(col.substr(1, j - 1), &color))
  1190. {
  1191. col = col.substr(j + 1);
  1192. element["columns"][i]["color"] = color.getValue();
  1193. }
  1194. }
  1195. }
  1196. element["columns"][i]["value"] = col;
  1197. }
  1198. element["id"] = listp->getItemCount();
  1199. listp->addElement(element, ADD_BOTTOM);
  1200. return true;
  1201. }
  1202. // The other control types set with a LLSD-converted value (which may not
  1203. // have any effect with some controls, but we report a success anyway).
  1204. ctrlp->setValue(LLSD(value));
  1205. return true;
  1206. }
  1207. //static
  1208. void HBLuaFloater::onCommitCallback(LLUICtrl* ctrlp, void* userdata)
  1209. {
  1210. HBLuaFloater* self = (HBLuaFloater*)userdata;
  1211. if (!self || !ctrlp || !self->mInitOK) return;
  1212. bool close = false;
  1213. std::string value = getCtrlValue(ctrlp);
  1214. commands_map_t::iterator it = self->mCommands.find(ctrlp);
  1215. if (it != self->mCommands.end())
  1216. {
  1217. bool with_close = dynamic_cast<LLButton*>(ctrlp) != NULL;
  1218. close = self->evalLuaCommand(it->second, value, with_close);
  1219. }
  1220. if (gAutomationp)
  1221. {
  1222. // We want the name of the parent inventory panel, not the name
  1223. // of the folder view (selected) item...
  1224. std::string ctrl_name;
  1225. LLFolderView* folderp = dynamic_cast<LLFolderView*>(ctrlp);
  1226. if (folderp)
  1227. {
  1228. LLPanel* panelp = folderp->getParentPanel();
  1229. if (panelp)
  1230. {
  1231. ctrl_name = panelp->getName();
  1232. }
  1233. }
  1234. else
  1235. {
  1236. ctrl_name = ctrlp->getName();
  1237. }
  1238. gAutomationp->onLuaFloaterAction(self->mLuaName, ctrl_name, value);
  1239. }
  1240. if (close)
  1241. {
  1242. self->close();
  1243. }
  1244. }
  1245. //static
  1246. void HBLuaFloater::onSearchEdit(const std::string& search_string,
  1247. void* userdata)
  1248. {
  1249. LLSearchEditor* editp = (LLSearchEditor*)userdata;
  1250. if (!editp) return;
  1251. // Search the Lua floater this editor pertains to.
  1252. HBLuaFloater* self = NULL;
  1253. LLView* parentp = editp->getParent();
  1254. while (!self && parentp)
  1255. {
  1256. self = parentp->asLuaFloater();
  1257. parentp = parentp->getParent();
  1258. }
  1259. if (!self || !self->mInitOK)
  1260. {
  1261. return;
  1262. }
  1263. commands_map_t::iterator it = self->mCommands.find(editp);
  1264. if (it != self->mCommands.end())
  1265. {
  1266. self->evalLuaCommand(it->second, search_string);
  1267. }
  1268. if (gAutomationp)
  1269. {
  1270. gAutomationp->onLuaFloaterAction(self->mLuaName, editp->getName(),
  1271. search_string);
  1272. }
  1273. }
  1274. //static
  1275. void HBLuaFloater::onInventorySelect(LLFolderView* ctrlp,
  1276. bool user_action, void* userdata)
  1277. {
  1278. // Do the Lua callback only if the commit is the result of a user's action
  1279. // (e.g. a selection with the mouse); avoids callback storms when filtering
  1280. // the inventory, for example...
  1281. if (user_action)
  1282. {
  1283. onCommitCallback(ctrlp, userdata);
  1284. }
  1285. }
  1286. ///////////////////////////////////////////////////////////////////////////////
  1287. // HBAutomationThread class
  1288. ///////////////////////////////////////////////////////////////////////////////
  1289. // For now, a maximum of eight concurrent threads are permitted.
  1290. constexpr S32 MAX_LUA_THREADS = 8;
  1291. class HBAutomationThread final : public HBViewerAutomation, public LLThread
  1292. {
  1293. protected:
  1294. LOG_CLASS(HBAutomationThread);
  1295. public:
  1296. LL_INLINE HBAutomationThread()
  1297. : HBViewerAutomation(true),
  1298. LLThread("Lua thread"),
  1299. mLuaThreadID(++sThreadID),
  1300. mHasSignal(false),
  1301. mRunning(true)
  1302. {
  1303. // Update the LLThread name with our Lua thread Id
  1304. mName = llformat("Lua thread %d", mLuaThreadID);
  1305. }
  1306. // HBViewerAutomation override
  1307. LL_INLINE bool isThreaded() const override { return true; }
  1308. LL_INLINE U32 getLuaThreadID() const override { return mLuaThreadID; }
  1309. // LLThread overrides
  1310. void run() override;
  1311. LL_INLINE bool runCondition() override { return mRunning; }
  1312. LL_INLINE bool isRunning() { return mRunning; }
  1313. LL_INLINE void setRunning()
  1314. {
  1315. mRunning = true;
  1316. wake();
  1317. }
  1318. LL_INLINE void setSignal()
  1319. {
  1320. mHasSignal = true;
  1321. wake();
  1322. }
  1323. LL_INLINE void threadStart()
  1324. {
  1325. LLThread::start();
  1326. }
  1327. LL_INLINE void threadStop()
  1328. {
  1329. mWatchdogTimer.start();
  1330. mWatchdogTimer.setTimerExpirySec(0.01f);
  1331. mRunning = true;
  1332. setQuitting();
  1333. }
  1334. LL_INLINE const std::string& getName() const { return mName; }
  1335. LL_INLINE bool hasFuncCall() const
  1336. {
  1337. return !mMainFuncCall.empty();
  1338. }
  1339. LL_INLINE const std::string& getFuncCall() const
  1340. {
  1341. return mMainFuncCall;
  1342. }
  1343. LL_INLINE void setFuncCallError(const std::string& err)
  1344. {
  1345. mFuncCallError = err;
  1346. }
  1347. LL_INLINE void appendSignal(const std::string& sig_str)
  1348. {
  1349. mSignals.emplace_back(sig_str);
  1350. }
  1351. int callMainFunction(const std::string& func_name);
  1352. static int getThreadID(lua_State* state);
  1353. static int sleep(lua_State* state);
  1354. private:
  1355. // This method is to be called to process pending signals. Returns true
  1356. // (and an unchanged Lua stack) on success or false on failure (with the
  1357. // error message on the Lua stack).
  1358. bool processSignals();
  1359. private:
  1360. // Set to the name of the function to call by the thread (*before* setting
  1361. // mRunning to false) to signal it is waiting for that call to a function
  1362. // of the automation script. Reset by the thread (after mRunning is reset
  1363. // to true by the automation script) after the call is completed with the
  1364. // result pushed on the thread stack.
  1365. std::string mMainFuncCall;
  1366. std::string mFuncCallError;
  1367. // Filled up by the automation idle loop (while mRunning is false), and
  1368. // consummed in run() (while mRunning is true).
  1369. typedef std::vector<std::string> signals_vec_t;
  1370. signals_vec_t mSignals;
  1371. U32 mLuaThreadID;
  1372. // NOTE: we cannot use the mPaused variable of LLThread, because is is not
  1373. // protected by a mutex and is not atomic either, while we need to pause
  1374. // (mRunning = false) from inside the thread and un-pause (mRunning = true)
  1375. // from the main loop...
  1376. LLAtomicBool mRunning;
  1377. // Set by the automation script idle loop when the thread is caught running
  1378. // (mRunning = true) while we have signals for it. Reset in run() by the
  1379. // thread, after it acknowledged it and put itself in pause mode
  1380. // (mRunning = false).
  1381. LLAtomicBool mHasSignal;
  1382. static U32 sThreadID;
  1383. };
  1384. //static
  1385. U32 HBAutomationThread::sThreadID = 0;
  1386. //virtual
  1387. void HBAutomationThread::run()
  1388. {
  1389. bool loop;
  1390. do
  1391. {
  1392. // At each loop, sleep 1ms and yield to the OS for threads rescheduling
  1393. ms_sleep(1);
  1394. // This will block until runCondition() returns true or the thread
  1395. // leaves the RUNNING state.
  1396. checkPause();
  1397. if (isQuitting() || !mLuaState)
  1398. {
  1399. break;
  1400. }
  1401. if (mHasSignal)
  1402. {
  1403. // Pause and wait for the automation idle loop to send us the
  1404. // pending signal(s)
  1405. mRunning = false;
  1406. mHasSignal = false; // Acknowledged !
  1407. continue;
  1408. }
  1409. if (!mPrintBuffer.empty())
  1410. {
  1411. // Pause and wait for the automation idle loop to print our stuff
  1412. mRunning = false;
  1413. continue;
  1414. }
  1415. // Process our signals, now...
  1416. if (!processSignals())
  1417. {
  1418. reportError();
  1419. break;
  1420. }
  1421. {
  1422. LL_TRACY_TIMER(TRC_LUA_THREAD_LOOP);
  1423. // Run our main Lua function at each loop
  1424. lua_getglobal(mLuaState, "ThreadRun");
  1425. resetTimer();
  1426. if (lua_pcall(mLuaState, 0, LUA_MULTRET, 0) != LUA_OK)
  1427. {
  1428. reportError();
  1429. break;
  1430. }
  1431. if (lua_gettop(mLuaState) != 1 ||
  1432. lua_type(mLuaState, 1) != LUA_TBOOLEAN)
  1433. {
  1434. lua_settop(mLuaState, 0); // Sanitize stack by emptying it
  1435. lua_pushliteral(mLuaState,
  1436. "ThreadRun() did not return an unique boolean");
  1437. reportError();
  1438. break;
  1439. }
  1440. loop = lua_toboolean(mLuaState, 1);
  1441. lua_pop(mLuaState, 1);
  1442. }
  1443. }
  1444. while (loop);
  1445. llinfos << "Exiting " << mName << llendl;
  1446. }
  1447. // This method is used to call viewer-specific Lua functions that are not
  1448. // thread-safe and must therefore be executed from the main thread (in an idle
  1449. // loop callback) on our thread's behalf.
  1450. int HBAutomationThread::callMainFunction(const std::string& func_name)
  1451. {
  1452. LL_TRACY_TIMER(TRC_LUA_THREAD_CALL_MAIN_FN);
  1453. // Clear any previous error message (since mFuncCallError is also used as a
  1454. // flag do denote an error during the function call by the automation
  1455. // script).
  1456. mFuncCallError.clear();
  1457. // Signal to the automation idle callback that we have work for it by
  1458. // filling up mMainFuncCall with the name of the function to call.
  1459. mMainFuncCall = func_name;
  1460. // Set the thread as "not running" (Lua processing paused), which will
  1461. // allow the automation script idle callback to process our request.
  1462. mRunning = false;
  1463. // Sleep until allowed to resume running by the idle callback, or quitting
  1464. while (!mRunning && !isQuitting())
  1465. {
  1466. // Since the idle callback is called once per frame, there is no use in
  1467. // sleeping less than 5ms (= 1/2 frame at 100fps) at each loop...
  1468. ms_sleep(5);
  1469. }
  1470. // Reset this now that we are done
  1471. mMainFuncCall.clear();
  1472. if (isQuitting())
  1473. {
  1474. std::string err = getName() + " aborted.";
  1475. luaL_error(mLuaState, err.c_str());
  1476. }
  1477. if (!mFuncCallError.empty())
  1478. {
  1479. luaL_error(mLuaState, mFuncCallError.c_str());
  1480. }
  1481. // Return whatever the idle callback left onto our stack.
  1482. return lua_gettop(mLuaState);
  1483. }
  1484. bool HBAutomationThread::processSignals()
  1485. {
  1486. LL_TRACY_TIMER(TRC_LUA_THREAD_PROCESS_SIG);
  1487. if (mSignals.empty())
  1488. {
  1489. // Nothing to do, report a success.
  1490. return true;
  1491. }
  1492. if (!mHasOnSignal)
  1493. {
  1494. // No OnSignal() callback, so no need to bother and report a success.
  1495. mSignals.clear();
  1496. return true;
  1497. }
  1498. // Copy mSignals on stack (and clear it), because OnSignal() could call
  1499. // custom Lua functions that would make us enter the mRunning = false
  1500. // state, which could, in turn, allow the modification of mSignals by the
  1501. // automation script idle loop...
  1502. signals_vec_t signals_copy;
  1503. signals_copy.swap(mSignals); // This also empties mSignals
  1504. for (U32 s = 0, count = signals_copy.size(); s < count; ++s)
  1505. {
  1506. std::string& signal_str = signals_copy[s];
  1507. LL_DEBUGS("Lua") << "Processing signal: " << signal_str << LL_ENDL;
  1508. // A signal string is always in the following form:
  1509. // from_lua_thread_id;time_stamp_seconds|serialized_Lua_table
  1510. size_t i = signal_str.find("|");
  1511. std::string temp = signal_str.substr(0, i);
  1512. signal_str = "_V_SIGNAL_TABLE=" + signal_str.substr(i + 1);
  1513. lua_getglobal(mLuaState, "OnSignal");
  1514. i = temp.find(";");
  1515. lua_pushnumber(mLuaState, atoi(temp.substr(0, i).c_str()));
  1516. lua_pushnumber(mLuaState, atof(temp.substr(i + 1).c_str()));
  1517. if (luaL_dostring(mLuaState, signal_str.c_str()) == LUA_OK)
  1518. {
  1519. lua_getglobal(mLuaState, "_V_SIGNAL_TABLE");
  1520. lua_pushnil(mLuaState);
  1521. lua_setglobal(mLuaState, "_V_SIGNAL_TABLE");
  1522. }
  1523. else
  1524. {
  1525. lua_pushliteral(mLuaState, "Could not evaluate the signal table");
  1526. return false;
  1527. }
  1528. resetTimer();
  1529. if (lua_pcall(mLuaState, 3, 0, 0) != LUA_OK)
  1530. {
  1531. return false;
  1532. }
  1533. // Check that we did not get killed during the signal processing...
  1534. if (isQuitting())
  1535. {
  1536. lua_pushliteral(mLuaState, "Thread aborted");
  1537. return false;
  1538. }
  1539. }
  1540. if (lua_gettop(mLuaState))
  1541. {
  1542. lua_pushliteral(mLuaState,
  1543. "OnSignal() returned something when it should not !");
  1544. return false;
  1545. }
  1546. return true;
  1547. }
  1548. //static
  1549. int HBAutomationThread::getThreadID(lua_State* state)
  1550. {
  1551. HBAutomationThread* self = (HBAutomationThread*)findInstance(state);
  1552. if (!self)
  1553. {
  1554. return 0;
  1555. }
  1556. S32 n = lua_gettop(state);
  1557. if (n)
  1558. {
  1559. luaL_error(state, "%d arguments passed; expected 0.", n);
  1560. }
  1561. lua_pushinteger(state, self->mLuaThreadID);
  1562. return 1;
  1563. }
  1564. //static
  1565. int HBAutomationThread::sleep(lua_State* state)
  1566. {
  1567. LL_TRACY_TIMER(TRC_LUA_THREAD_SLEEP);
  1568. HBAutomationThread* self = (HBAutomationThread*)findInstance(state);
  1569. if (!self)
  1570. {
  1571. return 0;
  1572. }
  1573. S32 n = lua_gettop(state);
  1574. if (n != 1)
  1575. {
  1576. luaL_error(state, "%d arguments passed; expected 1.", n);
  1577. }
  1578. S32 sleep_time = lua_tointeger(state, 1);
  1579. lua_pop(state, 1);
  1580. if (sleep_time < 0)
  1581. {
  1582. luaL_error(state, "Invalid (negative) sleep time");
  1583. }
  1584. // Always set ourselves as "not running" to let the automation idle loop
  1585. // send us any pending signal and/or print whatever is in our print buffer.
  1586. self->mRunning = false;
  1587. if (self->mHasSignal)
  1588. {
  1589. self->mHasSignal = false; // Acknowledged !
  1590. }
  1591. // Now wait for at least our sleep time and until permitted to run again.
  1592. do
  1593. {
  1594. // Sleep by 10ms maximum slices (so that we check often enough for any
  1595. // thread abortion), until we exhaust our sleep time
  1596. if (sleep_time > 0)
  1597. {
  1598. if (sleep_time > 10)
  1599. {
  1600. sleep_time -= 10;
  1601. ms_sleep(10);
  1602. }
  1603. else
  1604. {
  1605. ms_sleep(sleep_time);
  1606. sleep_time = 0;
  1607. }
  1608. }
  1609. else if (!self->mRunning)
  1610. {
  1611. // Sleep some more if not yet allowed to run by the automation
  1612. // idle loop...
  1613. ms_sleep(10);
  1614. }
  1615. // Check for any thread abortion request
  1616. if (self->isQuitting())
  1617. {
  1618. std::string err = self->getName() + " aborted.";
  1619. luaL_error(state, err.c_str());
  1620. }
  1621. // Extend our grace period since we just checked for exit conditions
  1622. self->resetTimer();
  1623. }
  1624. while (sleep_time > 0 || !self->mRunning);
  1625. // Process pending signals, if any.
  1626. if (!self->processSignals())
  1627. {
  1628. // Let's use luaL_error() so to abort the Lua script.
  1629. std::string message(lua_tostring(state, -1));
  1630. luaL_error(state, message.c_str());
  1631. }
  1632. return 0;
  1633. }
  1634. ///////////////////////////////////////////////////////////////////////////////
  1635. // HBFriendsStatusObserver helper class
  1636. // Used for the automation script to observe friends-related events and call
  1637. // the OnFriendsStatus() Lua callback in consequence.
  1638. ///////////////////////////////////////////////////////////////////////////////
  1639. class HBFriendsStatusObserver final : public LLFriendObserver
  1640. {
  1641. protected:
  1642. LOG_CLASS(HBFriendsStatusObserver);
  1643. public:
  1644. HBFriendsStatusObserver()
  1645. : mMask(0)
  1646. {
  1647. gAvatarTracker.addObserver(this);
  1648. }
  1649. ~HBFriendsStatusObserver() override
  1650. {
  1651. gAvatarTracker.removeObserver(this);
  1652. }
  1653. LL_INLINE void changed(U32 mask) override
  1654. {
  1655. mMask = mask;
  1656. }
  1657. void changedBuddies(const uuid_list_t& buddies) override
  1658. {
  1659. if (!gAutomationp)
  1660. {
  1661. return;
  1662. }
  1663. for (uuid_list_t::const_iterator it = buddies.begin(),
  1664. end = buddies.end();
  1665. it != end; ++it)
  1666. {
  1667. const LLUUID& id = *it;
  1668. bool online = gAvatarTracker.isBuddyOnline(id);
  1669. gAutomationp->onFriendStatusChange(id, mMask, online);
  1670. }
  1671. }
  1672. private:
  1673. U32 mMask;
  1674. };
  1675. ///////////////////////////////////////////////////////////////////////////////
  1676. // HBGroupTitlesObserver helper class
  1677. // Used by setAgentGroup() to set asynchronously the group title after
  1678. // receiving the appropriate data.
  1679. ///////////////////////////////////////////////////////////////////////////////
  1680. class HBGroupTitlesObserver final : public LLGroupMgrObserver
  1681. {
  1682. protected:
  1683. LOG_CLASS(HBGroupTitlesObserver);
  1684. public:
  1685. ~HBGroupTitlesObserver() override
  1686. {
  1687. gGroupMgr.removeObserver(this);
  1688. sObservers.erase(mGroupId);
  1689. }
  1690. void changed(LLGroupChange gc) override
  1691. {
  1692. bool success = false;
  1693. LLGroupMgrGroupData* gdatap = gGroupMgr.getGroupData(mGroupId);
  1694. if (gdatap) // Still a member of this group ?
  1695. {
  1696. if (gc != GC_TITLES)
  1697. {
  1698. return; // Not interested in this type of changes...
  1699. }
  1700. for (U32 i = 0, count = gdatap->mTitles.size(); i < count; ++i)
  1701. {
  1702. const LLGroupTitle& title = gdatap->mTitles[i];
  1703. if (title.mTitle == mTitleName)
  1704. {
  1705. if (gAgent.setGroup(mGroupId))
  1706. {
  1707. LL_DEBUGS("Lua") << "Setting requested agent group and role ("
  1708. << mTitleName << ")" << LL_ENDL;
  1709. gGroupMgr.sendGroupTitleUpdate(mGroupId,
  1710. title.mRoleID);
  1711. success = true;
  1712. }
  1713. break;
  1714. }
  1715. }
  1716. }
  1717. if (!success)
  1718. {
  1719. LL_DEBUGS("Lua") << "Failed to set agent group and role ("
  1720. << mTitleName << ")" << LL_ENDL;
  1721. }
  1722. // Commit suicide once we are no more needed.
  1723. delete this;
  1724. }
  1725. static HBGroupTitlesObserver* addObserver(const LLUUID& group_id,
  1726. const std::string& title)
  1727. {
  1728. group_obs_map_t::iterator it = sObservers.find(group_id);
  1729. if (it != sObservers.end())
  1730. {
  1731. // If we already got an observer, just update the desired group
  1732. // title for it...
  1733. it->second->mTitleName = title;
  1734. return it->second;
  1735. }
  1736. // Create a new observer
  1737. return new HBGroupTitlesObserver(group_id, title);
  1738. }
  1739. static void deleteObservers()
  1740. {
  1741. if (!sObservers.empty())
  1742. {
  1743. for (group_obs_map_t::iterator it = sObservers.begin(),
  1744. end = sObservers.end();
  1745. it != end; ++it)
  1746. {
  1747. delete it->second;
  1748. }
  1749. sObservers.clear();
  1750. }
  1751. }
  1752. private:
  1753. // Use addObserver() to construct instances of this class
  1754. HBGroupTitlesObserver(const LLUUID& group_id, const std::string& title)
  1755. : LLGroupMgrObserver(group_id),
  1756. mGroupId(group_id),
  1757. mTitleName(title)
  1758. {
  1759. sObservers.emplace(group_id, this);
  1760. gGroupMgr.addObserver(this);
  1761. }
  1762. private:
  1763. LLUUID mGroupId;
  1764. std::string mTitleName;
  1765. typedef fast_hmap<LLUUID, HBGroupTitlesObserver*> group_obs_map_t;
  1766. static group_obs_map_t sObservers;
  1767. };
  1768. HBGroupTitlesObserver::group_obs_map_t HBGroupTitlesObserver::sObservers;
  1769. ///////////////////////////////////////////////////////////////////////////////
  1770. // HBIgnoreCallback helper class to prevent infinite loops in Lua callbacks
  1771. ///////////////////////////////////////////////////////////////////////////////
  1772. class HBIgnoreCallback
  1773. {
  1774. protected:
  1775. LOG_CLASS(HBIgnoreCallback);
  1776. public:
  1777. HBIgnoreCallback(S32 callback_code)
  1778. : mCallbackCode(callback_code)
  1779. {
  1780. ++HBViewerAutomation::sIgnoredCallbacks[callback_code];
  1781. }
  1782. ~HBIgnoreCallback()
  1783. {
  1784. if (--HBViewerAutomation::sIgnoredCallbacks[mCallbackCode] < 0)
  1785. {
  1786. llwarns << "Invocations count mismatch for callback: "
  1787. << mCallbackCode << llendl;
  1788. llassert(false);
  1789. HBViewerAutomation::sIgnoredCallbacks[mCallbackCode] = 0;
  1790. }
  1791. }
  1792. private:
  1793. S32 mCallbackCode;
  1794. };
  1795. ///////////////////////////////////////////////////////////////////////////////
  1796. // HBViewerAutomation class
  1797. ///////////////////////////////////////////////////////////////////////////////
  1798. //static
  1799. HBViewerAutomation::instances_map_t HBViewerAutomation::sInstances;
  1800. LLMutex HBViewerAutomation::sThreadsMutex;
  1801. HBViewerAutomation::threads_list_t HBViewerAutomation::sThreadsInstances;
  1802. HBViewerAutomation::threads_list_t HBViewerAutomation::sDeadThreadsInstances;
  1803. HBViewerAutomation::signals_map_t HBViewerAutomation::sThreadsSignals;
  1804. std::string HBViewerAutomation::sLastAutomationScriptFile;
  1805. uuid_list_t HBViewerAutomation::sMuteObjectRequests;
  1806. uuid_list_t HBViewerAutomation::sUnmuteObjectRequests;
  1807. S32 HBViewerAutomation::sIgnoredCallbacks[HBViewerAutomation::E_IGN_CB_COUNT];
  1808. LLFriendObserver* HBViewerAutomation::sFriendsObserver = NULL;
  1809. HBViewerAutomation::pos_history_t HBViewerAutomation::sPositionsHistory;
  1810. #if LL_LINUX
  1811. LLUUID HBViewerAutomation::sLuaDBusFakeObjectId;
  1812. #endif
  1813. //static
  1814. void HBViewerAutomation::start(std::string file_name)
  1815. {
  1816. if (file_name.empty())
  1817. {
  1818. file_name = sLastAutomationScriptFile;
  1819. }
  1820. if (file_name.empty())
  1821. {
  1822. llwarns << "No file name given for automation script. Aborted."
  1823. << llendl;
  1824. return;
  1825. }
  1826. sLastAutomationScriptFile = file_name;
  1827. if (gAutomationp)
  1828. {
  1829. cleanup();
  1830. llinfos << "Restarting Lua automation..." << llendl;
  1831. }
  1832. else
  1833. {
  1834. llinfos << "Initializing Lua automation..." << llendl;
  1835. }
  1836. gAutomationp = new HBViewerAutomation();
  1837. if (gAutomationp->load(file_name))
  1838. {
  1839. if (gAutomationp->mHasCallbacks)
  1840. {
  1841. for (S32 i = 0; i < E_IGN_CB_COUNT; ++i)
  1842. {
  1843. sIgnoredCallbacks[i] = 0;
  1844. }
  1845. llinfos << "Initialisation successful." << llendl;
  1846. if (LLStartUp::isLoggedIn())
  1847. {
  1848. gAutomationp->onLogin();
  1849. }
  1850. return;
  1851. }
  1852. else
  1853. {
  1854. llinfos << "Lua script executed successfully, no callback found. Closing."
  1855. << llendl;
  1856. }
  1857. }
  1858. else
  1859. {
  1860. llwarns << "Initialisation failed !" << llendl;
  1861. }
  1862. LLEditMenuHandler::setCustomCallback(NULL);
  1863. delete gAutomationp;
  1864. gAutomationp = NULL;
  1865. }
  1866. //static
  1867. void HBViewerAutomation::cleanup()
  1868. {
  1869. if (gAutomationp)
  1870. {
  1871. llinfos << "Stopping Lua automation." << llendl;
  1872. LLEditMenuHandler::setCustomCallback(NULL);
  1873. delete gAutomationp;
  1874. gAutomationp = NULL;
  1875. }
  1876. if (!sDeadThreadsInstances.empty())
  1877. {
  1878. llinfos << "Trying to clean-up dead thread instances..." << llendl;
  1879. for (threads_list_t::iterator it = sDeadThreadsInstances.begin(),
  1880. end = sDeadThreadsInstances.end();
  1881. it != end; )
  1882. {
  1883. threads_list_t::iterator curit = it++;
  1884. HBAutomationThread* threadp = curit->second;
  1885. bool stopped = threadp->isStopped();
  1886. for (U32 i = 0; !stopped && i < 10; ++i)
  1887. {
  1888. // It was already set quitting, but this will also wake it up
  1889. threadp->threadStop();
  1890. // Give it some more time...
  1891. ms_sleep(10);
  1892. stopped = threadp->isStopped();
  1893. }
  1894. if (stopped)
  1895. {
  1896. LL_DEBUGS("Lua") << "Deleting stopped thread: "
  1897. << threadp->getName() << LL_ENDL;
  1898. delete threadp;
  1899. sDeadThreadsInstances.erase(curit);
  1900. }
  1901. else
  1902. {
  1903. llwarns << "Timed out waiting for '" << threadp->getName()
  1904. << "' to stop" << llendl;
  1905. }
  1906. }
  1907. if (sDeadThreadsInstances.empty())
  1908. {
  1909. llinfos << "All dead threads successfully removed." << llendl;
  1910. }
  1911. }
  1912. }
  1913. //static
  1914. std::string HBViewerAutomation::eval(const std::string& chunk,
  1915. bool use_print_buffer,
  1916. const LLUUID& id, const std::string& name)
  1917. {
  1918. LL_TRACY_TIMER(TRC_LUA_EVAL);
  1919. if (chunk.empty())
  1920. {
  1921. return "";
  1922. }
  1923. LL_DEBUGS("Lua") << "Executing Lua command line: " << chunk << LL_ENDL;
  1924. HBViewerAutomation self(use_print_buffer);
  1925. if (id.notNull())
  1926. {
  1927. LL_DEBUGS("Lua") << "Originator object: " << name << " (" << id
  1928. << ")" << LL_ENDL;
  1929. self.mFromObjectId = id;
  1930. self.mFromObjectName = name;
  1931. }
  1932. self.loadString(chunk);
  1933. print(self.mLuaState);
  1934. return self.mPrintBuffer;
  1935. }
  1936. //static
  1937. bool HBViewerAutomation::checkLuaCommand(const std::string& message,
  1938. const LLUUID& from_object_id,
  1939. const std::string& from_object_name)
  1940. {
  1941. static LLCachedControl<bool> scripts_cmd(gSavedSettings,
  1942. "LuaAcceptScriptCommands");
  1943. if (!scripts_cmd)
  1944. {
  1945. return false;
  1946. }
  1947. static LLCachedControl<std::string> prefix(gSavedSettings,
  1948. "LuaScriptCommandPrefix");
  1949. size_t len = std::string(prefix).size();
  1950. if (!len)
  1951. {
  1952. return false;
  1953. }
  1954. if (message.compare(0, len, prefix) != 0)
  1955. {
  1956. return false;
  1957. }
  1958. eval(message.substr(len), false, from_object_id, from_object_name);
  1959. return true;
  1960. }
  1961. //static
  1962. void HBViewerAutomation::execute(const std::string& file_name)
  1963. {
  1964. HBViewerAutomation self;
  1965. // Allow a relaxed watchdog timeout for one-shot scripts loaded from files.
  1966. static LLCachedControl<F32> timeout(gSavedSettings,
  1967. "LuaTimeoutForScriptFile");
  1968. self.mWatchdogTimeout = llclamp((F32)timeout, 0.01f, 30.f);
  1969. if (self.load(file_name))
  1970. {
  1971. llinfos << "Lua script '" << file_name << "' executed successfully."
  1972. << llendl;
  1973. }
  1974. else
  1975. {
  1976. llwarns << "Lua script '" << file_name << "' failed !" << llendl;
  1977. }
  1978. }
  1979. //static
  1980. HBViewerAutomation* HBViewerAutomation::findInstance(lua_State* state)
  1981. {
  1982. if (state)
  1983. {
  1984. instances_map_t::iterator it = sInstances.find(state);
  1985. if (it != sInstances.end())
  1986. {
  1987. return it->second;
  1988. }
  1989. }
  1990. return NULL;
  1991. }
  1992. HBViewerAutomation::HBViewerAutomation(bool use_print_buffer)
  1993. : mUsePrintBuffer(use_print_buffer),
  1994. mUseConsoleOutput(false),
  1995. mPausedWarnings(false),
  1996. mForceWarningsToChat(false),
  1997. mFromObjectName("Lua script"),
  1998. mFromObjectId(gAgentID)
  1999. {
  2000. if (isThreaded())
  2001. {
  2002. mUsePrintBuffer = true;
  2003. mWatchdogTimeout = 0.5f;
  2004. }
  2005. else
  2006. {
  2007. static LLCachedControl<F32> lua_timeout(gSavedSettings, "LuaTimeout");
  2008. mWatchdogTimeout = llclamp((F32)lua_timeout, 0.01f, 2.f);
  2009. }
  2010. resetCallbackFlags();
  2011. mLuaState = luaL_newstate();
  2012. if (mLuaState)
  2013. {
  2014. luaL_requiref(mLuaState, "_G", luaopen_base, 1);
  2015. luaL_requiref(mLuaState, LUA_TABLIBNAME, luaopen_table, 1);
  2016. luaL_requiref(mLuaState, LUA_STRLIBNAME, luaopen_string, 1);
  2017. luaL_requiref(mLuaState, LUA_MATHLIBNAME, luaopen_math, 1);
  2018. luaL_requiref(mLuaState, LUA_UTF8LIBNAME, luaopen_utf8, 1);
  2019. lua_settop(mLuaState, 0);
  2020. sInstances[mLuaState] = this;
  2021. LL_DEBUGS("Lua") << "Created new Lua state: " << std::hex << mLuaState
  2022. << std::dec << LL_ENDL;
  2023. }
  2024. else
  2025. {
  2026. llwarns << "Failure to allocate a new Lua state !" << llendl;
  2027. llassert(false);
  2028. }
  2029. }
  2030. HBViewerAutomation::~HBViewerAutomation()
  2031. {
  2032. if (mHasOnAlertDialog)
  2033. {
  2034. // Un-register the Lua callback for alert dialogs. HB
  2035. LLAlertDialog::setLuaCallback(NULL);
  2036. }
  2037. if (mHasOnFailedTPSimChange)
  2038. {
  2039. gIdleCallbacks.deleteFunction(onIdleSimChange, this);
  2040. }
  2041. if (mRegionChangedConnection.connected())
  2042. {
  2043. mRegionChangedConnection.disconnect();
  2044. }
  2045. if (mParcelChangedConnection.connected())
  2046. {
  2047. mParcelChangedConnection.disconnect();
  2048. }
  2049. if (mPositionChangedConnection.connected())
  2050. {
  2051. mPositionChangedConnection.disconnect();
  2052. }
  2053. if (mLuaState)
  2054. {
  2055. sInstances.erase(mLuaState);
  2056. lua_settop(mLuaState, 0);
  2057. lua_close(mLuaState);
  2058. mLuaState = NULL;
  2059. }
  2060. if (this != gAutomationp)
  2061. {
  2062. // If we are not the automation script instance, then we are done !
  2063. return;
  2064. }
  2065. if (sFriendsObserver)
  2066. {
  2067. delete sFriendsObserver;
  2068. sFriendsObserver = NULL;
  2069. }
  2070. HBGroupTitlesObserver::deleteObservers();
  2071. // Do not close the opened UI elements if the automation script does not
  2072. // have any callback (it was likely just used to setup those UI elements).
  2073. if (mHasCallbacks)
  2074. {
  2075. if (gLuaSideBarp)
  2076. {
  2077. gLuaSideBarp->removeAllButtons();
  2078. }
  2079. if (gLuaPiep)
  2080. {
  2081. gLuaPiep->removeAllSlices();
  2082. }
  2083. if (gOverlayBarp)
  2084. {
  2085. gOverlayBarp->setLuaFunctionButton("", "", "");
  2086. }
  2087. if (gStatusBarp)
  2088. {
  2089. gStatusBarp->setLuaFunctionButton("", "");
  2090. }
  2091. }
  2092. sThreadsMutex.lock();
  2093. if (!sThreadsInstances.empty())
  2094. {
  2095. gIdleCallbacks.deleteFunction(onIdleThread, this);
  2096. sThreadsSignals.clear(); // Abort any pending signal
  2097. for (threads_list_t::iterator it = sThreadsInstances.begin(),
  2098. end = sThreadsInstances.end();
  2099. it != end; ++it)
  2100. {
  2101. HBAutomationThread* threadp = it->second;
  2102. if (!threadp->isStopped())
  2103. {
  2104. threadp->threadStop();
  2105. }
  2106. }
  2107. mWatchdogTimer.start();
  2108. mWatchdogTimer.setTimerExpirySec(0.1f);
  2109. while (!sThreadsInstances.empty() && !mWatchdogTimer.hasExpired())
  2110. {
  2111. for (threads_list_t::iterator it = sThreadsInstances.begin(),
  2112. end = sThreadsInstances.end();
  2113. it != end; )
  2114. {
  2115. threads_list_t::iterator curit = it++;
  2116. HBAutomationThread* threadp = curit->second;
  2117. if (threadp->isStopped())
  2118. {
  2119. LL_DEBUGS("Lua") << "Deleting stopped thread: "
  2120. << threadp->getName() << LL_ENDL;
  2121. delete threadp;
  2122. sThreadsInstances.erase(curit);
  2123. }
  2124. }
  2125. ms_sleep(1);
  2126. }
  2127. if (!sThreadsInstances.empty())
  2128. {
  2129. llwarns << "Could not stop all running threads before timeout..."
  2130. << llendl;
  2131. sDeadThreadsInstances.clear();
  2132. sDeadThreadsInstances.swap(sThreadsInstances);
  2133. }
  2134. }
  2135. sThreadsMutex.unlock();
  2136. }
  2137. void HBViewerAutomation::resetCallbackFlags()
  2138. {
  2139. mHasCallbacks = mHasOnSignal = mHasOnLogin = mHasOnRegionChange =
  2140. mHasOnParcelChange = mHasOnPositionChange =
  2141. mHasOnAveragedFPS = mHasOnAgentOccupationChange =
  2142. mHasOnAgentPush = mHasOnSendChat = mHasOnReceivedChat =
  2143. mHasOnChatTextColoring = mHasOnInstantMsg =
  2144. mHasOnAlertDialog = mHasOnScriptDialog =
  2145. mHasOnNotification = mHasOnSLURLDispatch =
  2146. mHasOnURLDispatch = mHasOnFriendStatusChange =
  2147. mHasOnAvatarRezzing = mHasOnAgentBaked = mHasOnRadar =
  2148. mHasOnRadarSelection = mHasOnRadarMark = mHasOnRadarTrack =
  2149. mHasOnLuaDialogClose = mHasOnSideBarVisibilityChange =
  2150. mHasOnLuaFloaterAction = mHasOnLuaFloaterOpen =
  2151. mHasOnLuaFloaterClose = mHasOnAutomationMessage =
  2152. mHasOnAutomationRequest = mHasOnAutoPilotFinished =
  2153. mHasOnTPStateChange = mHasOnFailedTPSimChange =
  2154. mHasOnWindlightChange = mHasOnCameraModeChange =
  2155. mHasOnJoystickButtons = mHasOnLuaPieMenu =
  2156. mHasOnContextMenu = mHasOnRLVHandleCommand =
  2157. mHasOnRLVAnswerOnChat = mHasOnObjectInfoReply =
  2158. mHasOnPickInventoryItem = mHasOnPickAvatar = false;
  2159. }
  2160. void HBViewerAutomation::reportError()
  2161. {
  2162. if (!mLuaState) // Paranoia
  2163. {
  2164. return;
  2165. }
  2166. std::string message(lua_tostring(mLuaState, -1));
  2167. lua_settop(mLuaState, 0); // Sanitize stack by emptying it
  2168. llwarns << "Lua error: " << message << llendl;
  2169. // NOTE: we need verify we have logged in before printing in chat, since
  2170. // we otherwise could crash due to LLFloaterChat not yet being constructed.
  2171. if (mUsePrintBuffer || !LLStartUp::isLoggedIn())
  2172. {
  2173. // Overwrite any existing contents with the error message
  2174. mPrintBuffer = message;
  2175. return;
  2176. }
  2177. if (!mUseConsoleOutput || !HBLuaConsole::print(message))
  2178. {
  2179. LLChat chat;
  2180. chat.mFromName = "Lua";
  2181. chat.mText = "Lua: " + message;
  2182. chat.mSourceType = CHAT_SOURCE_SYSTEM;
  2183. LLFloaterChat::addChat(chat, false, false);
  2184. }
  2185. }
  2186. //static
  2187. void HBViewerAutomation::reportWarning(void* data, const char* msg,
  2188. int to_continue)
  2189. {
  2190. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  2191. lua_State* state = (lua_State*)data;
  2192. HBViewerAutomation* self = findInstance(state);
  2193. if (!self || !msg || !*msg)
  2194. {
  2195. return;
  2196. }
  2197. std::string message(msg);
  2198. // Check for Lua warning system control messages: only "@on" and "@off" are
  2199. // standard messages.
  2200. if (message[0] == '@')
  2201. {
  2202. if (message == "@on")
  2203. {
  2204. self->mPausedWarnings = false;
  2205. }
  2206. else if (message == "@off")
  2207. {
  2208. self->mPausedWarnings = true;
  2209. }
  2210. else if (message == "@prefix")
  2211. {
  2212. self->mWarningPrefix.clear();
  2213. }
  2214. else if (message.compare(0, 8, "@prefix:") == 0)
  2215. {
  2216. if (message.size() > 8)
  2217. {
  2218. self->mWarningPrefix = message.substr(8);
  2219. LLStringUtil::trim(self->mWarningPrefix);
  2220. }
  2221. else
  2222. {
  2223. self->mWarningPrefix.clear();
  2224. }
  2225. }
  2226. else if (message == "@tochat")
  2227. {
  2228. self->mForceWarningsToChat = !self->isThreaded();
  2229. }
  2230. else if (message.compare(0, 8, "@tochat:") == 0)
  2231. {
  2232. self->mForceWarningsToChat = !self->isThreaded() &&
  2233. message != "@tochat:0" &&
  2234. message != "@tochat:false" &&
  2235. message != "@tochat:off";
  2236. }
  2237. if (to_continue || self->mPausedWarnings ||
  2238. self->mPendingWarningText.empty())
  2239. {
  2240. return; // Nothing to print right now.
  2241. }
  2242. message.clear(); // Do not print the control message itself !
  2243. }
  2244. if (to_continue || self->mPausedWarnings)
  2245. {
  2246. self->mPendingWarningText += message;
  2247. return;
  2248. }
  2249. if (!self->mPendingWarningText.empty())
  2250. {
  2251. message = self->mPendingWarningText + message;
  2252. self->mPendingWarningText.clear();
  2253. }
  2254. LL_DEBUGS("Lua") << "Lua warning: " << message << LL_ENDL;
  2255. if (self->mWarningPrefix.empty())
  2256. {
  2257. message = "WARNING: " + message;
  2258. }
  2259. else
  2260. {
  2261. message = self->mWarningPrefix + ": " + message;
  2262. }
  2263. if ((self->mUsePrintBuffer && !self->mForceWarningsToChat) ||
  2264. !LLStartUp::isLoggedIn())
  2265. {
  2266. if (!self->mPrintBuffer.empty())
  2267. {
  2268. #if LL_WINDOWS
  2269. self->mPrintBuffer += "\r\n";
  2270. #else
  2271. self->mPrintBuffer += '\n';
  2272. #endif
  2273. }
  2274. self->mPrintBuffer += message;
  2275. return;
  2276. }
  2277. if (!self->mUseConsoleOutput || !HBLuaConsole::print(message))
  2278. {
  2279. LLChat chat;
  2280. chat.mFromName = "Lua";
  2281. chat.mText = "Lua: " + message;
  2282. chat.mSourceType = CHAT_SOURCE_SYSTEM;
  2283. LLFloaterChat::addChat(chat, false, false);
  2284. }
  2285. }
  2286. bool HBViewerAutomation::registerCFunctions()
  2287. {
  2288. static const struct luaL_Reg printlib[] = {
  2289. { "print", HBViewerAutomation::print },
  2290. { NULL, NULL }
  2291. };
  2292. if (!mLuaState) // Paranoia
  2293. {
  2294. return false;
  2295. }
  2296. // Register a warning callback
  2297. lua_setwarnf(mLuaState, reportWarning, mLuaState);
  2298. // This registers our custom print(), overriding Lua's, and disables
  2299. // load(), loadfile() and dofile().
  2300. lua_getglobal(mLuaState, "_G");
  2301. luaL_setfuncs(mLuaState, printlib, 0);
  2302. lua_pushnil(mLuaState);
  2303. lua_setfield(mLuaState, -2, "load");
  2304. lua_pushnil(mLuaState);
  2305. lua_setfield(mLuaState, -2, "loadfile");
  2306. lua_pushnil(mLuaState);
  2307. lua_setfield(mLuaState, -2, "dofile");
  2308. lua_setglobal(mLuaState, "_G");
  2309. // Set some useful global variables so that Lua scripts know what viewer
  2310. // they are running within.
  2311. lua_pushstring(mLuaState, gSecondLife.c_str());
  2312. lua_setglobal(mLuaState, "VIEWER_NAME");
  2313. lua_pushstring(mLuaState, gViewerVersionString.c_str());
  2314. lua_setglobal(mLuaState, "VIEWER_VERSION");
  2315. lua_pushinteger(mLuaState, gViewerVersionNumber);
  2316. lua_setglobal(mLuaState, "VIEWER_VERNUM");
  2317. // We setup Lua so that it calls our watchdog every 500 operations (which
  2318. // should be small enough a number, even on slow computers).
  2319. lua_sethook(mLuaState, watchdog, LUA_MASKCOUNT, 500);
  2320. // Register our custom Lua functions
  2321. lua_register(mLuaState, "GetSourceFileName", getSourceFileName);
  2322. lua_register(mLuaState, "GetWatchdogState", getWatchdogState);
  2323. lua_register(mLuaState, "IsUUID", isUUID);
  2324. lua_register(mLuaState, "IsAvatar", isAvatar);
  2325. lua_register(mLuaState, "IsObject", isObject);
  2326. lua_register(mLuaState, "IsAgentFriend", isAgentFriend);
  2327. lua_register(mLuaState, "IsAgentGroup", isAgentGroup);
  2328. lua_register(mLuaState, "GetAvatarName", getAvatarName);
  2329. lua_register(mLuaState, "GetGroupName", getGroupName);
  2330. lua_register(mLuaState, "IsAdmin", isAdmin);
  2331. lua_register(mLuaState, "GetRadarList", getRadarList);
  2332. lua_register(mLuaState, "GetRadarData", getRadarData);
  2333. lua_register(mLuaState, "SetRadarTracking", setRadarTracking);
  2334. lua_register(mLuaState, "SetRadarToolTip", setRadarToolTip);
  2335. lua_register(mLuaState, "SetRadarMarkChar", setRadarMarkChar);
  2336. lua_register(mLuaState, "SetRadarMarkColor", setRadarMarkColor);
  2337. lua_register(mLuaState, "SetRadarNameColor", setRadarNameColor);
  2338. lua_register(mLuaState, "SetAvatarMinimapColor", setAvatarMinimapColor);
  2339. lua_register(mLuaState, "SetAvatarNameTagColor", setAvatarNameTagColor);
  2340. lua_register(mLuaState, "GetAgentPosHistory", getAgentPosHistory);
  2341. lua_register(mLuaState, "GetAgentInfo", getAgentInfo);
  2342. lua_register(mLuaState, "SetAgentOccupation", setAgentOccupation);
  2343. lua_register(mLuaState, "GetAgentGroupData", getAgentGroupData);
  2344. lua_register(mLuaState, "SetAgentGroup", setAgentGroup);
  2345. lua_register(mLuaState, "AgentGroupInvite", agentGroupInvite);
  2346. lua_register(mLuaState, "AgentSit", agentSit);
  2347. lua_register(mLuaState, "AgentStand", agentStand);
  2348. lua_register(mLuaState, "SetAgentTyping", setAgentTyping);
  2349. lua_register(mLuaState, "SendChat", sendChat);
  2350. lua_register(mLuaState, "GetIMSession", getIMSession);
  2351. lua_register(mLuaState, "SendIM", sendIM);
  2352. lua_register(mLuaState, "AlertDialogResponse", alertDialogResponse);
  2353. lua_register(mLuaState, "ScriptDialogResponse", scriptDialogResponse);
  2354. lua_register(mLuaState, "NotificationResponse", scriptDialogResponse);
  2355. lua_register(mLuaState, "CancelNotification", cancelNotification);
  2356. lua_register(mLuaState, "BrowseToURL", browseToURL);
  2357. lua_register(mLuaState, "DispatchSLURL", dispatchSLURL);
  2358. lua_register(mLuaState, "ExecuteRLV", executeRLV);
  2359. lua_register(mLuaState, "OpenNotification", openNotification);
  2360. lua_register(mLuaState, "OpenFloater", openFloater);
  2361. lua_register(mLuaState, "CloseFloater", closeFloater);
  2362. lua_register(mLuaState, "MakeDialog", makeDialog);
  2363. lua_register(mLuaState, "OpenLuaFloater", openLuaFloater);
  2364. lua_register(mLuaState, "ShowLuaFloater", showLuaFloater);
  2365. lua_register(mLuaState, "SetLuaFloaterCommand", setLuaFloaterCommand);
  2366. lua_register(mLuaState, "GetLuaFloaterValue", getLuaFloaterValue);
  2367. lua_register(mLuaState, "GetLuaFloaterValues", getLuaFloaterValues);
  2368. lua_register(mLuaState, "SetLuaFloaterValue", setLuaFloaterValue);
  2369. lua_register(mLuaState, "SetLuaFloaterInvFilter", setLuaFloaterInvFilter);
  2370. lua_register(mLuaState, "SetLuaFloaterEnabled", setLuaFloaterEnabled);
  2371. lua_register(mLuaState, "SetLuaFloaterVisible", setLuaFloaterVisible);
  2372. lua_register(mLuaState, "CloseLuaFloater", closeLuaFloater);
  2373. lua_register(mLuaState, "OverlayBarLuaButton", overlayBarLuaButton);
  2374. lua_register(mLuaState, "StatusBarLuaIcon", statusBarLuaIcon);
  2375. lua_register(mLuaState, "SideBarButton", sideBarButton);
  2376. lua_register(mLuaState, "SideBarButtonToggle", sideBarButtonToggle);
  2377. lua_register(mLuaState, "SideBarHide", sideBarHide);
  2378. lua_register(mLuaState, "SideBarHideOnRightClick",
  2379. sideBarHideOnRightClick);
  2380. lua_register(mLuaState, "SideBarButtonHide", sideBarButtonHide);
  2381. lua_register(mLuaState, "SideBarButtonDisable", sideBarButtonDisable);
  2382. lua_register(mLuaState, "LuaPieMenuSlice", luaPieMenuSlice);
  2383. lua_register(mLuaState, "LuaContextMenu", luaContextMenu);
  2384. lua_register(mLuaState, "PasteToContextHandler", pasteToContextHandler);
  2385. lua_register(mLuaState, "PlayUISound", playUISound);
  2386. lua_register(mLuaState, "RenderDebugInfo", renderDebugInfo);
  2387. lua_register(mLuaState, "GetDebugSetting", getDebugSetting);
  2388. lua_register(mLuaState, "SetDebugSetting", setDebugSetting);
  2389. lua_register(mLuaState, "GetFrameTimeSeconds", getFrameTimeSeconds);
  2390. lua_register(mLuaState, "GetTimeStamp", getTimeStamp);
  2391. lua_register(mLuaState, "GetClipBoardString", getClipBoardString);
  2392. lua_register(mLuaState, "SetClipBoardString", setClipBoardString);
  2393. lua_register(mLuaState, "FindInventoryObject", findInventoryObject);
  2394. lua_register(mLuaState, "GiveInventory", giveInventory);
  2395. lua_register(mLuaState, "MakeInventoryLink", makeInventoryLink);
  2396. lua_register(mLuaState, "DeleteInventoryLink", deleteInventoryLink);
  2397. lua_register(mLuaState, "NewInventoryFolder", newInventoryFolder);
  2398. lua_register(mLuaState, "ListInventoryFolder", listInventoryFolder);
  2399. lua_register(mLuaState, "GetAgentAttachments", getAgentAttachments);
  2400. lua_register(mLuaState, "GetAgentWearables", getAgentWearables);
  2401. lua_register(mLuaState, "AgentAutoPilotToPos", agentAutoPilotToPos);
  2402. lua_register(mLuaState, "AgentAutoPilotFollow", agentAutoPilotFollow);
  2403. lua_register(mLuaState, "AgentAutoPilotStop", agentAutoPilotStop);
  2404. lua_register(mLuaState, "AgentAutoPilotLoad", agentAutoPilotLoad);
  2405. lua_register(mLuaState, "AgentAutoPilotSave", agentAutoPilotSave);
  2406. lua_register(mLuaState, "AgentAutoPilotRemove", agentAutoPilotRemove);
  2407. lua_register(mLuaState, "AgentAutoPilotRecord", agentAutoPilotRecord);
  2408. lua_register(mLuaState, "AgentAutoPilotReplay", agentAutoPilotReplay);
  2409. lua_register(mLuaState, "AgentRotate", agentRotate);
  2410. lua_register(mLuaState, "GetAgentRotation", getAgentRotation);
  2411. lua_register(mLuaState, "TeleportAgentHome", teleportAgentHome);
  2412. lua_register(mLuaState, "TeleportAgentToPos", teleportAgentToPos);
  2413. lua_register(mLuaState, "GetGridSimAndPos", getGridSimAndPos);
  2414. lua_register(mLuaState, "GetParcelInfo", getParcelInfo);
  2415. lua_register(mLuaState, "GetCameraMode", getCameraMode);
  2416. lua_register(mLuaState, "SetCameraMode", setCameraMode);
  2417. lua_register(mLuaState, "SetCameraFocus", setCameraFocus);
  2418. lua_register(mLuaState, "SetVisualMute", setVisualMute);
  2419. lua_register(mLuaState, "AddMute", addMute);
  2420. lua_register(mLuaState, "RemoveMute", removeMute);
  2421. lua_register(mLuaState, "IsMuted", isMuted);
  2422. lua_register(mLuaState, "BlockSound", blockSound);
  2423. lua_register(mLuaState, "IsBlockedSound", isBlockedSound);
  2424. lua_register(mLuaState, "GetBlockedSounds", getBlockedSounds);
  2425. lua_register(mLuaState, "DerenderObject", derenderObject);
  2426. lua_register(mLuaState, "GetDerenderedObjects", getDerenderedObjects);
  2427. lua_register(mLuaState, "GetAgentPushes", getAgentPushes);
  2428. lua_register(mLuaState, "ApplyDaySettings", applyDaySettings);
  2429. lua_register(mLuaState, "ApplySkySettings", applySkySettings);
  2430. lua_register(mLuaState, "ApplyWaterSettings", applyWaterSettings);
  2431. lua_register(mLuaState, "SetDayTime", setDayTime);
  2432. lua_register(mLuaState, "GetEESettingsList", getEESettingsList);
  2433. lua_register(mLuaState, "GetWLSettingsList", getWLSettingsList);
  2434. lua_register(mLuaState, "GetEnvironmentStatus", getEnvironmentStatus);
  2435. if (isThreaded())
  2436. {
  2437. lua_register(mLuaState, "GetThreadID",
  2438. HBAutomationThread::getThreadID);
  2439. lua_register(mLuaState, "Sleep", HBAutomationThread::sleep);
  2440. lua_register(mLuaState, "HasThread", hasThread);
  2441. lua_register(mLuaState, "SendSignal", sendSignal);
  2442. // Also allow CloseIMSession() and GetObjectInfo() in threads
  2443. lua_register(mLuaState, "CloseIMSession", closeIMSession);
  2444. lua_register(mLuaState, "GetAgentFriends", getAgentFriends);
  2445. lua_register(mLuaState, "GetAgentGroups", getAgentGroups);
  2446. lua_register(mLuaState, "GetObjectInfo", getObjectInfo);
  2447. lua_register(mLuaState, "GetFloaterInstances", getFloaterInstances);
  2448. lua_register(mLuaState, "GetFloaterControls", getFloaterControls);
  2449. lua_register(mLuaState, "GetFloaterCtrlState", getFloaterCtrlState);
  2450. lua_register(mLuaState, "GetFloaterList", getFloaterList);
  2451. lua_register(mLuaState, "ShowFloater", showFloater);
  2452. }
  2453. else if (this == gAutomationp || mFromObjectId == gAgentID)
  2454. {
  2455. #if LL_PUPPETRY
  2456. lua_register(mLuaState, "AgentPuppetryStart", agentPuppetryStart);
  2457. lua_register(mLuaState, "AgentPuppetryStop", agentPuppetryStop);
  2458. #endif
  2459. lua_register(mLuaState, "CloseIMSession", closeIMSession);
  2460. lua_register(mLuaState, "GetAgentFriends", getAgentFriends);
  2461. lua_register(mLuaState, "GetAgentGroups", getAgentGroups);
  2462. lua_register(mLuaState, "GetObjectInfo", getObjectInfo);
  2463. lua_register(mLuaState, "GetGlobalData", getGlobalData);
  2464. lua_register(mLuaState, "SetGlobalData", setGlobalData);
  2465. lua_register(mLuaState, "GetPerAccountData", getPerAccountData);
  2466. lua_register(mLuaState, "SetPerAccountData", setPerAccountData);
  2467. lua_register(mLuaState, "PickAvatar", pickAvatar);
  2468. lua_register(mLuaState, "MoveToInventoryFolder",
  2469. moveToInventoryFolder);
  2470. lua_register(mLuaState, "PickInventoryItem", pickInventoryItem);
  2471. lua_register(mLuaState, "GetFloaterInstances", getFloaterInstances);
  2472. lua_register(mLuaState, "GetFloaterControls", getFloaterControls);
  2473. lua_register(mLuaState, "GetFloaterCtrlState", getFloaterCtrlState);
  2474. lua_register(mLuaState, "GetFloaterList", getFloaterList);
  2475. lua_register(mLuaState, "ShowFloater", showFloater);
  2476. if (this == gAutomationp)
  2477. {
  2478. lua_register(mLuaState, "CallbackAfter", callbackAfter);
  2479. lua_register(mLuaState, "HasThread", hasThread);
  2480. lua_register(mLuaState, "StartThread", startThread);
  2481. lua_register(mLuaState, "StopThread", stopThread);
  2482. lua_register(mLuaState, "SendSignal", sendSignal);
  2483. lua_register(mLuaState, "ForceQuit", forceQuit);
  2484. lua_register(mLuaState, "MinimizeWindow", minimizeWindow);
  2485. }
  2486. else
  2487. {
  2488. lua_register(mLuaState, "AutomationMessage", automationMessage);
  2489. lua_register(mLuaState, "AutomationRequest", automationRequest);
  2490. }
  2491. }
  2492. else
  2493. {
  2494. lua_register(mLuaState, "AutomationMessage", automationMessage);
  2495. lua_register(mLuaState, "AutomationRequest", automationRequest);
  2496. }
  2497. return true;
  2498. }
  2499. //static
  2500. void HBViewerAutomation::preprocessorMessageCB(const std::string& message,
  2501. bool is_warning, void*)
  2502. {
  2503. LLChat chat;
  2504. chat.mFromName = "Lua";
  2505. chat.mText = "Lua preprocessor ";
  2506. chat.mText += is_warning ? "warning: " : "error: ";
  2507. chat.mText += message;
  2508. chat.mSourceType = CHAT_SOURCE_SYSTEM;
  2509. // NOTE: we need verify we have logged in before printing in chat, since
  2510. // we otherwise could crash due to LLFloaterChat not yet being constructed.
  2511. if (LLStartUp::isLoggedIn())
  2512. {
  2513. LLFloaterChat::addChat(chat, false, false);
  2514. }
  2515. else // Just warn/report error in the log
  2516. {
  2517. llwarns << chat.mText << llendl;
  2518. }
  2519. }
  2520. //static
  2521. S32 HBViewerAutomation::loadInclude(std::string& include_name,
  2522. const std::string& default_path,
  2523. std::string& buffer, void*)
  2524. {
  2525. if (include_name.empty())
  2526. {
  2527. return HBPreprocessor::FAILURE;
  2528. }
  2529. std::string file;
  2530. if (default_path.compare(0, 2, "~/") == 0)
  2531. {
  2532. // Search in user "home" directory, without fallback sub-directory
  2533. file = gDirUtil.getUserFilename(default_path, "", include_name);
  2534. }
  2535. else
  2536. {
  2537. file = gDirUtil.getUserFilename(default_path, "include", include_name);
  2538. }
  2539. if (file.empty())
  2540. {
  2541. return HBPreprocessor::FAILURE;
  2542. }
  2543. llifstream include_file(file.c_str());
  2544. if (!include_file.is_open())
  2545. {
  2546. llwarns << "Failure to open file: " << file << llendl;
  2547. return HBPreprocessor::FAILURE;
  2548. }
  2549. // Return the full path of the include file we opened successfully
  2550. include_name = file;
  2551. while (!include_file.eof())
  2552. {
  2553. getline(include_file, file);
  2554. buffer += file + "\n";
  2555. }
  2556. include_file.close();
  2557. return HBPreprocessor::SUCCESS;
  2558. }
  2559. std::string HBViewerAutomation::preprocess(const std::string& file_name)
  2560. {
  2561. llifstream source_file(file_name.c_str());
  2562. if (!source_file.is_open())
  2563. {
  2564. return "";
  2565. }
  2566. bool first_line = true;
  2567. std::string sources, line;
  2568. while (!source_file.eof())
  2569. {
  2570. getline(source_file, line);
  2571. if (first_line && line.compare(0, 4, "\x1bLua") == 0)
  2572. {
  2573. // This is a Lua compiled file: cannot pre-process it !
  2574. source_file.close();
  2575. return "";
  2576. }
  2577. first_line = false;
  2578. sources += line + "\n";
  2579. }
  2580. source_file.close();
  2581. if (!HBPreprocessor::needsPreprocessing(sources))
  2582. {
  2583. // No known preprocesor directive in the file, so nothing to do here !
  2584. return "";
  2585. }
  2586. HBPreprocessor pp(file_name, loadInclude);
  2587. pp.setMessageCallback(preprocessorMessageCB);
  2588. pp.addForbiddenToken("_G"); // This shall not be overridden !
  2589. if (pp.preprocess(sources) != HBPreprocessor::SUCCESS)
  2590. {
  2591. // In case of error return an empty sources string.
  2592. return "";
  2593. }
  2594. return pp.getResult();
  2595. }
  2596. bool HBViewerAutomation::load(const std::string& file_name)
  2597. {
  2598. LL_TRACY_TIMER(TRC_LUA_LOAD);
  2599. resetCallbackFlags();
  2600. if (!mLuaState)
  2601. {
  2602. llwarns << "No Lua state defined. Aborted." << llendl;
  2603. llassert(false);
  2604. return false;
  2605. }
  2606. mSourceFileName = file_name;
  2607. llinfos << "Loading Lua script file: " << file_name << llendl;
  2608. S32 ret = luaL_loadfile(mLuaState, file_name.c_str());
  2609. if (ret == LUA_ERRSYNTAX)
  2610. {
  2611. std::string err(lua_tostring(mLuaState, -1));
  2612. llinfos << "Loading failure, attempting to pre-process the file..."
  2613. << llendl;
  2614. std::string preprocessed = preprocess(file_name);
  2615. if (preprocessed.empty())
  2616. {
  2617. // Any pre-processing error already got reported via the
  2618. // preprocessorMessageCB() callback. Report the initial Lua error
  2619. // (which is still on stack), in case the file did not need
  2620. // pre-processing anyway and the error was a Lua one.
  2621. reportError();
  2622. return false;
  2623. }
  2624. lua_settop(mLuaState, 0); // Sanitize stack by emptying it
  2625. llinfos << "Loading pre-processed Lua script..." << llendl;
  2626. if (luaL_loadstring(mLuaState, preprocessed.c_str()) != LUA_OK)
  2627. {
  2628. // Report the two errors we encountered: before and after
  2629. // pre-processing
  2630. err = "Before preprocesing: " + err + "\nAfter preprocessing: ";
  2631. err += lua_tostring(mLuaState, -1);
  2632. lua_pushstring(mLuaState, err.c_str());
  2633. reportError();
  2634. return false;
  2635. }
  2636. }
  2637. else if (ret != LUA_OK)
  2638. {
  2639. reportError();
  2640. return false;
  2641. }
  2642. if (!registerCFunctions())
  2643. {
  2644. return false;
  2645. }
  2646. resetTimer();
  2647. if (lua_pcall(mLuaState, 0, LUA_MULTRET, 0) != LUA_OK)
  2648. {
  2649. reportError();
  2650. return false;
  2651. }
  2652. if (isThreaded())
  2653. {
  2654. if (getGlobal("ThreadRun") != LUA_TFUNCTION)
  2655. {
  2656. lua_settop(mLuaState, 0); // Sanitize stack by emptying it
  2657. lua_pushliteral(mLuaState,
  2658. "Missing ThreadRun() function in thread code");
  2659. reportError();
  2660. return false;
  2661. }
  2662. lua_settop(mLuaState, 0);
  2663. if (gAutomationp)
  2664. {
  2665. // Register the idle callback for our thead
  2666. LL_DEBUGS("Lua") << "Registering thread idle callback." << LL_ENDL;
  2667. gIdleCallbacks.addFunction(onIdleThread, gAutomationp);
  2668. }
  2669. mHasOnSignal = lua_getglobal(mLuaState, "OnSignal");
  2670. lua_pop(mLuaState, 1);
  2671. if (mHasOnSignal)
  2672. {
  2673. llinfos << "OnSignal Lua callback found" << llendl;
  2674. }
  2675. // No other callback for threads...
  2676. return true;
  2677. }
  2678. if (this != gAutomationp)
  2679. {
  2680. return true;
  2681. }
  2682. mHasOnSignal = getGlobal("OnSignal") == LUA_TFUNCTION;
  2683. lua_pop(mLuaState, 1);
  2684. if (mHasOnSignal)
  2685. {
  2686. mHasCallbacks = true;
  2687. llinfos << "OnSignal Lua callback found" << llendl;
  2688. }
  2689. mHasOnLogin = getGlobal("OnLogin") == LUA_TFUNCTION;
  2690. lua_pop(mLuaState, 1);
  2691. if (mHasOnLogin)
  2692. {
  2693. mHasCallbacks = true;
  2694. llinfos << "OnLogin Lua callback found" << llendl;
  2695. }
  2696. mHasOnAveragedFPS = getGlobal("OnAveragedFPS") == LUA_TFUNCTION;
  2697. lua_pop(mLuaState, 1);
  2698. if (mHasOnAveragedFPS)
  2699. {
  2700. mHasCallbacks = true;
  2701. llinfos << "OnAveragedFPS Lua callback found" << llendl;
  2702. }
  2703. mHasOnAgentOccupationChange =
  2704. getGlobal("OnAgentOccupationChange") == LUA_TFUNCTION;
  2705. lua_pop(mLuaState, 1);
  2706. if (mHasOnAgentOccupationChange)
  2707. {
  2708. mHasCallbacks = true;
  2709. llinfos << "OnAgentOccupationChange Lua callback found" << llendl;
  2710. }
  2711. mHasOnAgentPush = getGlobal("OnAgentPush") == LUA_TFUNCTION;
  2712. lua_pop(mLuaState, 1);
  2713. if (mHasOnAgentPush)
  2714. {
  2715. mHasCallbacks = true;
  2716. llinfos << "OnAgentPush Lua callback found" << llendl;
  2717. }
  2718. mHasOnSendChat = getGlobal("OnSendChat") == LUA_TFUNCTION;
  2719. lua_pop(mLuaState, 1);
  2720. if (mHasOnSendChat)
  2721. {
  2722. mHasCallbacks = true;
  2723. llinfos << "OnSendChat Lua callback found" << llendl;
  2724. }
  2725. mHasOnReceivedChat = getGlobal("OnReceivedChat") == LUA_TFUNCTION;
  2726. lua_pop(mLuaState, 1);
  2727. if (mHasOnReceivedChat)
  2728. {
  2729. mHasCallbacks = true;
  2730. llinfos << "OnReceivedChat Lua callback found" << llendl;
  2731. }
  2732. mHasOnChatTextColoring = getGlobal("OnChatTextColoring") == LUA_TFUNCTION;
  2733. lua_pop(mLuaState, 1);
  2734. if (mHasOnChatTextColoring)
  2735. {
  2736. mHasCallbacks = true;
  2737. llinfos << "OnChatTextColoring Lua callback found" << llendl;
  2738. }
  2739. mHasOnInstantMsg = getGlobal("OnInstantMsg") == LUA_TFUNCTION;
  2740. lua_pop(mLuaState, 1);
  2741. if (mHasOnInstantMsg)
  2742. {
  2743. mHasCallbacks = true;
  2744. llinfos << "OnInstantMsg Lua callback found" << llendl;
  2745. }
  2746. mHasOnAlertDialog = getGlobal("OnAlertDialog") == LUA_TFUNCTION;
  2747. lua_pop(mLuaState, 1);
  2748. if (mHasOnAlertDialog)
  2749. {
  2750. // Register the Lua callback for alert dialogs. HB
  2751. LLAlertDialog::setLuaCallback(lua_alert_callback);
  2752. mHasCallbacks = true;
  2753. llinfos << "OnAlertDialog Lua callback found" << llendl;
  2754. }
  2755. mHasOnScriptDialog = getGlobal("OnScriptDialog") == LUA_TFUNCTION;
  2756. lua_pop(mLuaState, 1);
  2757. if (mHasOnScriptDialog)
  2758. {
  2759. mHasCallbacks = true;
  2760. llinfos << "OnScriptDialog Lua callback found" << llendl;
  2761. }
  2762. mHasOnNotification = getGlobal("OnNotification") == LUA_TFUNCTION;
  2763. lua_pop(mLuaState, 1);
  2764. if (mHasOnNotification)
  2765. {
  2766. mHasCallbacks = true;
  2767. llinfos << "OnNotification Lua callback found" << llendl;
  2768. }
  2769. mHasOnSLURLDispatch = getGlobal("OnSLURLDispatch") == LUA_TFUNCTION;
  2770. lua_pop(mLuaState, 1);
  2771. if (mHasOnSLURLDispatch)
  2772. {
  2773. mHasCallbacks = true;
  2774. llinfos << "OnSLURLDispatch Lua callback found" << llendl;
  2775. }
  2776. mHasOnURLDispatch = getGlobal("OnURLDispatch") == LUA_TFUNCTION;
  2777. lua_pop(mLuaState, 1);
  2778. if (mHasOnURLDispatch)
  2779. {
  2780. mHasCallbacks = true;
  2781. llinfos << "OnURLDispatch Lua callback found" << llendl;
  2782. }
  2783. mHasOnFriendStatusChange =
  2784. getGlobal("OnFriendStatusChange") == LUA_TFUNCTION;
  2785. lua_pop(mLuaState, 1);
  2786. if (mHasOnFriendStatusChange)
  2787. {
  2788. mHasCallbacks = true;
  2789. llinfos << "OnFriendStatusChange Lua callback found" << llendl;
  2790. if (!sFriendsObserver)
  2791. {
  2792. sFriendsObserver = new HBFriendsStatusObserver;
  2793. }
  2794. }
  2795. mHasOnAvatarRezzing = getGlobal("OnAvatarRezzing") == LUA_TFUNCTION;
  2796. lua_pop(mLuaState, 1);
  2797. if (mHasOnAvatarRezzing)
  2798. {
  2799. mHasCallbacks = true;
  2800. llinfos << "OnAvatarRezzing Lua callback found" << llendl;
  2801. }
  2802. mHasOnAgentBaked = getGlobal("OnAgentBaked") == LUA_TFUNCTION;
  2803. lua_pop(mLuaState, 1);
  2804. if (mHasOnAgentBaked)
  2805. {
  2806. mHasCallbacks = true;
  2807. llinfos << "OnAgentBaked Lua callback found" << llendl;
  2808. }
  2809. mHasOnRadar = getGlobal("OnRadar") == LUA_TFUNCTION;
  2810. lua_pop(mLuaState, 1);
  2811. if (mHasOnRadar)
  2812. {
  2813. mHasCallbacks = true;
  2814. llinfos << "OnRadar Lua callback found" << llendl;
  2815. }
  2816. mHasOnRadarSelection = getGlobal("OnRadarSelection") == LUA_TFUNCTION;
  2817. lua_pop(mLuaState, 1);
  2818. if (mHasOnRadarSelection)
  2819. {
  2820. mHasCallbacks = true;
  2821. llinfos << "OnRadarSelection Lua callback found" << llendl;
  2822. }
  2823. mHasOnRadarMark = getGlobal("OnRadarMark") == LUA_TFUNCTION;
  2824. lua_pop(mLuaState, 1);
  2825. if (mHasOnRadarMark)
  2826. {
  2827. mHasCallbacks = true;
  2828. llinfos << "OnRadarMark Lua callback found" << llendl;
  2829. }
  2830. mHasOnRadarTrack = getGlobal("OnRadarTrack") == LUA_TFUNCTION;
  2831. lua_pop(mLuaState, 1);
  2832. if (mHasOnRadarTrack)
  2833. {
  2834. mHasCallbacks = true;
  2835. llinfos << "OnRadarTrack Lua callback found" << llendl;
  2836. }
  2837. mHasOnLuaDialogClose = getGlobal("OnLuaDialogClose") == LUA_TFUNCTION;
  2838. lua_pop(mLuaState, 1);
  2839. if (mHasOnLuaDialogClose)
  2840. {
  2841. mHasCallbacks = true;
  2842. llinfos << "OnLuaDialogClose Lua callback found" << llendl;
  2843. }
  2844. mHasOnLuaFloaterAction = getGlobal("OnLuaFloaterAction") == LUA_TFUNCTION;
  2845. lua_pop(mLuaState, 1);
  2846. if (mHasOnLuaFloaterAction)
  2847. {
  2848. mHasCallbacks = true;
  2849. llinfos << "OnLuaFloaterAction Lua callback found" << llendl;
  2850. }
  2851. mHasOnLuaFloaterOpen = getGlobal("OnLuaFloaterOpen") == LUA_TFUNCTION;
  2852. lua_pop(mLuaState, 1);
  2853. if (mHasOnLuaFloaterOpen)
  2854. {
  2855. mHasCallbacks = true;
  2856. llinfos << "OnLuaFloaterOpen Lua callback found" << llendl;
  2857. }
  2858. mHasOnLuaFloaterClose = getGlobal("OnLuaFloaterClose") == LUA_TFUNCTION;
  2859. lua_pop(mLuaState, 1);
  2860. if (mHasOnLuaFloaterClose)
  2861. {
  2862. mHasCallbacks = true;
  2863. llinfos << "OnLuaFloaterClose Lua callback found" << llendl;
  2864. }
  2865. mHasOnSideBarVisibilityChange =
  2866. getGlobal("OnSideBarVisibilityChange") == LUA_TFUNCTION;
  2867. lua_pop(mLuaState, 1);
  2868. if (mHasOnSideBarVisibilityChange)
  2869. {
  2870. mHasCallbacks = true;
  2871. llinfos << "OnSideBarVisibilityChange Lua callback found" << llendl;
  2872. }
  2873. mHasOnAutomationMessage =
  2874. getGlobal("OnAutomationMessage") == LUA_TFUNCTION;
  2875. lua_pop(mLuaState, 1);
  2876. if (mHasOnAutomationMessage)
  2877. {
  2878. mHasCallbacks = true;
  2879. llinfos << "OnAutomationMessage Lua callback found" << llendl;
  2880. }
  2881. mHasOnAutomationRequest =
  2882. getGlobal("OnAutomationRequest") == LUA_TFUNCTION;
  2883. lua_pop(mLuaState, 1);
  2884. if (mHasOnAutomationRequest)
  2885. {
  2886. mHasCallbacks = true;
  2887. llinfos << "OnAutomationRequest Lua callback found" << llendl;
  2888. }
  2889. mHasOnAutoPilotFinished =
  2890. getGlobal("OnAutoPilotFinished") == LUA_TFUNCTION;
  2891. lua_pop(mLuaState, 1);
  2892. if (mHasOnAutoPilotFinished)
  2893. {
  2894. mHasCallbacks = true;
  2895. llinfos << "OnAutoPilotFinished Lua callback found" << llendl;
  2896. }
  2897. mHasOnTPStateChange = getGlobal("OnTPStateChange") == LUA_TFUNCTION;
  2898. lua_pop(mLuaState, 1);
  2899. if (mHasOnTPStateChange)
  2900. {
  2901. mHasCallbacks = true;
  2902. llinfos << "OnTPStateChange Lua callback found" << llendl;
  2903. }
  2904. mHasOnFailedTPSimChange =
  2905. getGlobal("OnFailedTPSimChange") == LUA_TFUNCTION;
  2906. lua_pop(mLuaState, 1);
  2907. if (mHasOnFailedTPSimChange)
  2908. {
  2909. mHasCallbacks = true;
  2910. gIdleCallbacks.addFunction(onIdleSimChange, this);
  2911. llinfos << "OnFailedTPSimChange Lua callback found" << llendl;
  2912. }
  2913. mHasOnRegionChange = getGlobal("OnRegionChange") == LUA_TFUNCTION;
  2914. lua_pop(mLuaState, 1);
  2915. if (mHasOnRegionChange)
  2916. {
  2917. mHasCallbacks = true;
  2918. mRegionChangedConnection =
  2919. gAgent.addRegionChangedCB(boost::bind(&HBViewerAutomation::onRegionChange,
  2920. this));
  2921. llinfos << "OnRegionChange Lua callback found" << llendl;
  2922. }
  2923. mHasOnParcelChange = getGlobal("OnParcelChange") == LUA_TFUNCTION;
  2924. lua_pop(mLuaState, 1);
  2925. if (mHasOnParcelChange)
  2926. {
  2927. mHasCallbacks = true;
  2928. mParcelChangedConnection =
  2929. gViewerParcelMgr.addAgentParcelChangedCB(boost::bind(&HBViewerAutomation::onParcelChange,
  2930. this));
  2931. llinfos << "OnParcelChange Lua callback found" << llendl;
  2932. }
  2933. mHasOnPositionChange = getGlobal("OnPositionChange") == LUA_TFUNCTION;
  2934. lua_pop(mLuaState, 1);
  2935. if (mHasOnPositionChange)
  2936. {
  2937. mHasCallbacks = true;
  2938. mPositionChangedConnection =
  2939. gAgent.setPosChangeCallback(boost::bind(&HBViewerAutomation::onPositionChange,
  2940. this, _1, _2));
  2941. llinfos << "OnPositionChange Lua callback found" << llendl;
  2942. }
  2943. mHasOnWindlightChange = getGlobal("OnWindlightChange") == LUA_TFUNCTION;
  2944. lua_pop(mLuaState, 1);
  2945. if (mHasOnWindlightChange)
  2946. {
  2947. mHasCallbacks = true;
  2948. llinfos << "OnWindlightChange Lua callback found" << llendl;
  2949. }
  2950. mHasOnCameraModeChange = getGlobal("OnCameraModeChange") == LUA_TFUNCTION;
  2951. lua_pop(mLuaState, 1);
  2952. if (mHasOnCameraModeChange)
  2953. {
  2954. mHasCallbacks = true;
  2955. llinfos << "OnCameraModeChange Lua callback found" << llendl;
  2956. }
  2957. mHasOnJoystickButtons = getGlobal("OnJoystickButtons") == LUA_TFUNCTION;
  2958. lua_pop(mLuaState, 1);
  2959. if (mHasOnJoystickButtons)
  2960. {
  2961. mHasCallbacks = true;
  2962. llinfos << "OnJoystickButtons Lua callback found" << llendl;
  2963. }
  2964. mHasOnLuaPieMenu = getGlobal("OnLuaPieMenu") == LUA_TFUNCTION;
  2965. lua_pop(mLuaState, 1);
  2966. if (mHasOnLuaPieMenu)
  2967. {
  2968. mHasCallbacks = true;
  2969. llinfos << "OnLuaPieMenu Lua callback found" << llendl;
  2970. }
  2971. mHasOnContextMenu = getGlobal("OnContextMenu") == LUA_TFUNCTION;
  2972. lua_pop(mLuaState, 1);
  2973. if (mHasOnContextMenu)
  2974. {
  2975. mHasCallbacks = true;
  2976. llinfos << "OnContextMenu Lua callback found" << llendl;
  2977. LLEditMenuHandler::setCustomCallback(contextMenuCallback);
  2978. }
  2979. else
  2980. {
  2981. LLEditMenuHandler::setCustomCallback(NULL);
  2982. }
  2983. mHasOnRLVHandleCommand = getGlobal("OnRLVHandleCommand") == LUA_TFUNCTION;
  2984. lua_pop(mLuaState, 1);
  2985. if (mHasOnRLVHandleCommand)
  2986. {
  2987. mHasCallbacks = true;
  2988. llinfos << "OnRLVHandleCommand Lua callback found" << llendl;
  2989. }
  2990. mHasOnRLVAnswerOnChat = getGlobal("OnRLVAnswerOnChat") == LUA_TFUNCTION;
  2991. lua_pop(mLuaState, 1);
  2992. if (mHasOnRLVAnswerOnChat)
  2993. {
  2994. mHasCallbacks = true;
  2995. llinfos << "OnRLVAnswerOnChat Lua callback found" << llendl;
  2996. }
  2997. mHasOnObjectInfoReply = getGlobal("OnObjectInfoReply") == LUA_TFUNCTION;
  2998. lua_pop(mLuaState, 1);
  2999. if (mHasOnObjectInfoReply)
  3000. {
  3001. mHasCallbacks = true;
  3002. llinfos << "OnObjectInfoReply Lua callback found" << llendl;
  3003. }
  3004. mHasOnPickInventoryItem = getGlobal("OnPickInventoryItem") == LUA_TFUNCTION;
  3005. lua_pop(mLuaState, 1);
  3006. if (mHasOnPickInventoryItem)
  3007. {
  3008. mHasCallbacks = true;
  3009. llinfos << "OnPickInventoryItem Lua callback found" << llendl;
  3010. }
  3011. mHasOnPickAvatar = getGlobal("OnPickAvatar") == LUA_TFUNCTION;
  3012. lua_pop(mLuaState, 1);
  3013. if (mHasOnPickAvatar)
  3014. {
  3015. mHasCallbacks = true;
  3016. llinfos << "OnPickAvatar Lua callback found" << llendl;
  3017. }
  3018. return true;
  3019. }
  3020. bool HBViewerAutomation::loadString(const std::string& chunk)
  3021. {
  3022. LL_TRACY_TIMER(TRC_LUA_LOAD_STRING);
  3023. resetCallbackFlags();
  3024. if (!mLuaState)
  3025. {
  3026. llwarns << "No Lua state defined. Aborted." << llendl;
  3027. llassert(false);
  3028. return false;
  3029. }
  3030. if (luaL_loadstring(mLuaState, chunk.c_str()) != LUA_OK)
  3031. {
  3032. reportError();
  3033. return false;
  3034. }
  3035. if (!registerCFunctions())
  3036. {
  3037. return false;
  3038. }
  3039. resetTimer();
  3040. if (lua_pcall(mLuaState, 0, LUA_MULTRET, 0) != LUA_OK)
  3041. {
  3042. reportError();
  3043. return false;
  3044. }
  3045. return true;
  3046. }
  3047. S32 HBViewerAutomation::getGlobal(const std::string& global)
  3048. {
  3049. if (!mLuaState)
  3050. {
  3051. llwarns << "No valid Lua state loaded. Aborted." << llendl;
  3052. llassert(false);
  3053. return LUA_TNONE;
  3054. }
  3055. if (global.empty())
  3056. {
  3057. return LUA_TNONE;
  3058. }
  3059. return lua_getglobal(mLuaState, global.c_str());
  3060. }
  3061. //static
  3062. int HBViewerAutomation::hasThread(lua_State* state)
  3063. {
  3064. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  3065. HBViewerAutomation* self = findInstance(state);
  3066. if (!self)
  3067. {
  3068. return 0;
  3069. }
  3070. S32 n = lua_gettop(state);
  3071. if (n != 1)
  3072. {
  3073. luaL_error(state, "%d arguments passed; expected 1.", n);
  3074. }
  3075. S32 thread_id = lua_tointeger(state, 1);
  3076. lua_pop(state, 1);
  3077. if (thread_id < 0)
  3078. {
  3079. luaL_error(state, "Not a valid thread Id: ", thread_id);
  3080. }
  3081. bool has_thread = false;
  3082. if (thread_id) // 0 = automation script, which is not a thread...
  3083. {
  3084. sThreadsMutex.lock();
  3085. threads_list_t::iterator it = sThreadsInstances.find(thread_id);
  3086. if (it != sThreadsInstances.end())
  3087. {
  3088. has_thread = !it->second->isStopped();
  3089. }
  3090. sThreadsMutex.unlock();
  3091. }
  3092. lua_pushboolean(state, has_thread);
  3093. return 1;
  3094. }
  3095. //static
  3096. int HBViewerAutomation::startThread(lua_State* state)
  3097. {
  3098. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  3099. HBViewerAutomation* self = findInstance(state);
  3100. if (!self || self != gAutomationp)
  3101. {
  3102. return 0;
  3103. }
  3104. S32 n = lua_gettop(state);
  3105. if (n != 1 && n != 2)
  3106. {
  3107. luaL_error(state, "%d arguments passed; expected 1 or 2.", n);
  3108. }
  3109. // The first argument is the file name for the thread code.
  3110. std::string fname(luaL_checkstring(state, 1));
  3111. if (fname.empty())
  3112. {
  3113. luaL_error(state, "Empty thread code file name");
  3114. }
  3115. lua_remove(state, 1);
  3116. // When it exists, the second argument must be a "simple" table that we
  3117. // will use for "argv".
  3118. std::string argv;
  3119. if (n > 1)
  3120. {
  3121. if (!serializeTable(state, 1, &argv))
  3122. {
  3123. luaL_error(state, "Unsupported thread argument format");
  3124. }
  3125. argv = "argv=" + argv;
  3126. }
  3127. std::string fpath;
  3128. if (fname.compare(0, 2, "~/") == 0)
  3129. {
  3130. // Search in user "home" directory, without fallback sub-directory
  3131. fpath = gDirUtil.getUserFilename("~/", "",
  3132. gDirUtil.getBaseFileName(fname));
  3133. }
  3134. else
  3135. {
  3136. // Search in the user_settings application directory, with an "include"
  3137. // fallback sub-directory.
  3138. fpath = gDirUtil.getUserFilename(gDirUtil.getOSUserAppDir(), "include",
  3139. fname);
  3140. }
  3141. if (fpath.empty())
  3142. {
  3143. luaL_error(state, "Cannot find file: %s", fname.c_str());
  3144. }
  3145. sThreadsMutex.lock();
  3146. if (sThreadsInstances.size() >= MAX_LUA_THREADS)
  3147. {
  3148. sThreadsMutex.unlock();
  3149. LL_DEBUGS("Lua") << "Too many running threads to start a new one."
  3150. << LL_ENDL;
  3151. lua_pushboolean(state, false);
  3152. return 1;
  3153. }
  3154. sThreadsMutex.unlock();
  3155. HBAutomationThread* threadp = new HBAutomationThread;
  3156. bool success = threadp->load(fpath);
  3157. if (success && threadp->mLuaState)
  3158. {
  3159. if (!argv.empty())
  3160. {
  3161. if (luaL_dostring(threadp->mLuaState, argv.c_str()))
  3162. {
  3163. success = false;
  3164. llwarns << "Failed to set the thread argv table for thread: "
  3165. << threadp->getName() << llendl;
  3166. }
  3167. }
  3168. }
  3169. else
  3170. {
  3171. success = false; // Paranoia, in case threadp->mLuaState == NULL...
  3172. llwarns << "Failed to load the Lua code for thread: "
  3173. << threadp->getName() << llendl;
  3174. }
  3175. if (success)
  3176. {
  3177. U32 thread_id = threadp->getLuaThreadID();
  3178. sThreadsMutex.lock();
  3179. sThreadsInstances[thread_id] = threadp;
  3180. sThreadsMutex.unlock();
  3181. threadp->threadStart();
  3182. lua_pushnumber(state, thread_id);
  3183. }
  3184. else
  3185. {
  3186. delete threadp;
  3187. lua_pushnil(state);
  3188. }
  3189. return 1;
  3190. }
  3191. //static
  3192. int HBViewerAutomation::stopThread(lua_State* state)
  3193. {
  3194. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  3195. HBViewerAutomation* self = findInstance(state);
  3196. if (!self || self != gAutomationp)
  3197. {
  3198. return 0;
  3199. }
  3200. S32 n = lua_gettop(state);
  3201. if (n != 1)
  3202. {
  3203. luaL_error(state, "%d arguments passed; expected 1.", n);
  3204. }
  3205. S32 thread_id = lua_tointeger(state, 1);
  3206. lua_pop(state, 1);
  3207. if (thread_id <= 0)
  3208. {
  3209. luaL_error(state, "Not a valid thread Id: ", thread_id);
  3210. }
  3211. sThreadsMutex.lock();
  3212. threads_list_t::iterator it = sThreadsInstances.find(thread_id);
  3213. if (it == sThreadsInstances.end())
  3214. {
  3215. sThreadsMutex.unlock();
  3216. lua_pushboolean(state, false);
  3217. return 1;
  3218. }
  3219. HBAutomationThread* threadp = it->second;
  3220. LL_DEBUGS("Lua") << "Stopping the running thread: " << threadp->getName()
  3221. << LL_ENDL;
  3222. threadp->threadStop();
  3223. sThreadsMutex.unlock();
  3224. lua_pushboolean(state, true);
  3225. return 1;
  3226. }
  3227. //static
  3228. int HBViewerAutomation::sendSignal(lua_State* state)
  3229. {
  3230. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  3231. HBViewerAutomation* self = findInstance(state);
  3232. if (!self)
  3233. {
  3234. return 0;
  3235. }
  3236. S32 n = lua_gettop(state);
  3237. if (n != 2)
  3238. {
  3239. luaL_error(state, "%d arguments passed; expected 2.", n);
  3240. }
  3241. S32 thread_id = lua_tointeger(state, 1);
  3242. if (thread_id < 0)
  3243. {
  3244. luaL_error(state, "Not a valid thread Id: ", thread_id);
  3245. }
  3246. if ((U32)thread_id == self->getLuaThreadID())
  3247. {
  3248. luaL_error(state, "Cannot send a signal to self !");
  3249. }
  3250. lua_remove(state, 1);
  3251. if (lua_type(state, 1) != LUA_TTABLE)
  3252. {
  3253. luaL_error(state,
  3254. "Invalid type pased as second argument: table expected");
  3255. }
  3256. // Particular case for sending a signal from a thread to the automation
  3257. // script itself.
  3258. if (thread_id == 0 && self->isThreaded())
  3259. {
  3260. if (!gAutomationp || !gAutomationp->mHasOnSignal)
  3261. {
  3262. lua_pop(state, 1);
  3263. lua_pushboolean(state, false);
  3264. return 1;
  3265. }
  3266. // Push our thread Id on the stack...
  3267. lua_pushnumber(state, self->getLuaThreadID());
  3268. // ... and move it above the table in the stack.
  3269. lua_insert(state, 1);
  3270. // Push the time stamp on stack...
  3271. lua_pushnumber(state, gFrameTimeSeconds);
  3272. // ... and move it above the table in the stack.
  3273. lua_insert(state, 2);
  3274. HBAutomationThread* threadp = (HBAutomationThread*)self;
  3275. // Send the signal to the automation script via callAutomationFunc() by
  3276. // calling its OnSignal() callback instead of reentering this method.
  3277. threadp->callMainFunction("OnSignal");
  3278. lua_pushboolean(state, true);
  3279. return 1;
  3280. }
  3281. std::string signal_str;
  3282. if (!serializeTable(state, 1, &signal_str))
  3283. {
  3284. luaL_error(state, "Unsupported thread signal format");
  3285. }
  3286. signal_str = llformat("%d;%f|", self->getLuaThreadID(),
  3287. gFrameTimeSeconds) + signal_str;
  3288. LL_DEBUGS("Lua") << "Serialized signal string: " << signal_str << LL_ENDL;
  3289. sThreadsMutex.lock();
  3290. threads_list_t::iterator tit = sThreadsInstances.find(thread_id);
  3291. if (tit == sThreadsInstances.end())
  3292. {
  3293. sThreadsMutex.unlock();
  3294. lua_pushboolean(state, false);
  3295. return 1;
  3296. }
  3297. HBAutomationThread* threadp = tit->second;
  3298. if (!threadp->mHasOnSignal)
  3299. {
  3300. sThreadsMutex.unlock();
  3301. lua_pushboolean(state, false);
  3302. return 1;
  3303. }
  3304. HBThreadSignals* signals;
  3305. signals_map_t::iterator sit = sThreadsSignals.find(threadp);
  3306. if (sit == sThreadsSignals.end())
  3307. {
  3308. LL_DEBUGS("Lua") << "Creating new signal queue for thread: "
  3309. << thread_id << LL_ENDL;
  3310. signals = new HBThreadSignals;
  3311. signals->mThreadID = thread_id;
  3312. sThreadsSignals[threadp] = signals;
  3313. }
  3314. else
  3315. {
  3316. LL_DEBUGS("Lua") << "Existing signal queue found for thread: "
  3317. << thread_id << LL_ENDL;
  3318. signals = sit->second;
  3319. if (signals->mThreadID != (U32)thread_id)
  3320. {
  3321. llwarns << "Dead thread signals found, removing them." << llendl;
  3322. signals->mThreadID = thread_id;
  3323. signals->mSignals.clear();
  3324. }
  3325. }
  3326. signals->mSignals.emplace_back(signal_str);
  3327. sThreadsMutex.unlock();
  3328. lua_pushboolean(state, true);
  3329. return 1;
  3330. }
  3331. //static
  3332. bool HBViewerAutomation::callAutomationFunc(HBAutomationThread* threadp)
  3333. {
  3334. lua_State* astate = gAutomationp->mLuaState;
  3335. lua_State* tstate = threadp->mLuaState;
  3336. // Get the function name and the corresponding global in the automation
  3337. // script.
  3338. const std::string& function = threadp->getFuncCall();
  3339. lua_getglobal(astate, function.c_str());
  3340. if (lua_type(astate, -1) != LUA_TFUNCTION)
  3341. {
  3342. lua_settop(astate, 0); // Clear the automation script stack
  3343. threadp->setFuncCallError("No function named '" + function +
  3344. "' in automation script");
  3345. return false;
  3346. }
  3347. // Process the paramaters present on the thread state stack, copying them
  3348. // onto the automation script state stack...
  3349. S32 n = lua_gettop(tstate);
  3350. for (S32 i = 1; i <= n; ++i)
  3351. {
  3352. int type = lua_type(tstate, i);
  3353. switch (type)
  3354. {
  3355. case LUA_TBOOLEAN:
  3356. lua_pushboolean(astate, lua_toboolean(tstate, i));
  3357. break;
  3358. case LUA_TNUMBER:
  3359. lua_pushnumber(astate, lua_tonumber(tstate, i));
  3360. break;
  3361. case LUA_TSTRING:
  3362. lua_pushstring(astate, lua_tostring(tstate, i));
  3363. break;
  3364. case LUA_TNIL:
  3365. lua_pushnil(astate);
  3366. break;
  3367. case LUA_TTABLE:
  3368. {
  3369. std::string table;
  3370. if (serializeTable(tstate, i, &table))
  3371. {
  3372. table = "_V_TABLE_PARAM=" + table;
  3373. if (luaL_dostring(astate, table.c_str()) == LUA_OK)
  3374. {
  3375. lua_getglobal(astate, "_V_TABLE_PARAM");
  3376. lua_pushnil(astate);
  3377. lua_setglobal(astate, "_V_TABLE_PARAM");
  3378. break;
  3379. }
  3380. }
  3381. lua_settop(tstate, 0); // Clear the thread script stack
  3382. lua_settop(astate, 0); // Clear the automation script stack
  3383. threadp->setFuncCallError("Failed to copy a table parameter");
  3384. return false;
  3385. }
  3386. default:
  3387. {
  3388. lua_settop(tstate, 0); // Clear the thread script stack
  3389. lua_settop(astate, 0); // Clear the automation script stack
  3390. std::string err = "Unsupported parameter type: ";
  3391. err += lua_typename(tstate, type);
  3392. threadp->setFuncCallError(err);
  3393. return false;
  3394. }
  3395. }
  3396. }
  3397. lua_settop(tstate, 0); // Clear the thread script stack
  3398. gAutomationp->resetTimer();
  3399. if (lua_pcall(astate, n, LUA_MULTRET, 0) != LUA_OK)
  3400. {
  3401. threadp->setFuncCallError(lua_tostring(astate, -1));
  3402. lua_settop(astate, 0); // Clear the automation script stack
  3403. return false;
  3404. }
  3405. n = lua_gettop(astate); // Number or returned results
  3406. if (!n)
  3407. {
  3408. return true; // We are done !
  3409. }
  3410. for (S32 i = 1; i <= n; ++i)
  3411. {
  3412. int type = lua_type(astate, i);
  3413. switch (type)
  3414. {
  3415. case LUA_TBOOLEAN:
  3416. lua_pushboolean(tstate, lua_toboolean(astate, i));
  3417. break;
  3418. case LUA_TNUMBER:
  3419. lua_pushnumber(tstate, lua_tonumber(astate, i));
  3420. break;
  3421. case LUA_TSTRING:
  3422. lua_pushstring(tstate, lua_tostring(astate, i));
  3423. break;
  3424. case LUA_TNIL:
  3425. lua_pushnil(tstate);
  3426. break;
  3427. case LUA_TTABLE:
  3428. {
  3429. std::string table;
  3430. if (serializeTable(astate, i, &table))
  3431. {
  3432. table = "_V_RET_TABLE=" + table;
  3433. if (luaL_dostring(tstate, table.c_str()) == LUA_OK)
  3434. {
  3435. lua_getglobal(tstate, "_V_RET_TABLE");
  3436. lua_pushnil(tstate);
  3437. lua_setglobal(tstate, "_V_RET_TABLE");
  3438. break;
  3439. }
  3440. }
  3441. lua_settop(tstate, 0); // Clear the thread script stack
  3442. lua_settop(astate, 0); // Clear the automation script stack
  3443. threadp->setFuncCallError("Failed to copy a returned table");
  3444. return false;
  3445. }
  3446. default:
  3447. {
  3448. lua_settop(tstate, 0); // Clear the thread script stack
  3449. lua_settop(astate, 0); // Clear the automation script stack
  3450. std::string err = "Unsupported return type: ";
  3451. err += lua_typename(astate, type);
  3452. threadp->setFuncCallError(err);
  3453. return false;
  3454. }
  3455. }
  3456. }
  3457. lua_settop(astate, 0); // Clear the automation script stack
  3458. return true;
  3459. }
  3460. //static
  3461. void HBViewerAutomation::onIdleThread(void* userdata)
  3462. {
  3463. LL_FAST_TIMER(FTM_IDLE_LUA_THREAD);
  3464. HBViewerAutomation* self = (HBViewerAutomation*)userdata;
  3465. if (!self || self != gAutomationp) // Paranoia
  3466. {
  3467. return;
  3468. }
  3469. // Note: no need to lock sThreadsMutex at this point, since only the
  3470. // automation thread can change sThreadsInstances, either in startThread()
  3471. // or here.
  3472. if (sThreadsInstances.empty())
  3473. {
  3474. LL_DEBUGS("Lua") << "No thread left, unregistering idle callback."
  3475. << LL_ENDL;
  3476. gIdleCallbacks.deleteFunction(onIdleThread, self);
  3477. sThreadsSignals.clear(); // Clear any signal leftover
  3478. return;
  3479. }
  3480. // This will be used to store pointers to threads waiting for a custom Lua
  3481. // function call.
  3482. std::vector<HBAutomationThread*> waiting_threads;
  3483. for (threads_list_t::iterator it = sThreadsInstances.begin(),
  3484. end = sThreadsInstances.end();
  3485. it != end; )
  3486. {
  3487. threads_list_t::iterator curit = it++;
  3488. HBAutomationThread* threadp = curit->second;
  3489. // Only intervene after the thread sets itself to "not running" (i.e.
  3490. // got locked on its run condition, or is executing a sleeping loop) or
  3491. // exited... When it is, it is also safe to use/change its member
  3492. // variables and Lua state.
  3493. // Note: isRunning() usually returns true after the thread is actually
  3494. // stopped (i.e. running loop exited after receiving a threadStop()
  3495. // request)...
  3496. if (threadp->isRunning() && !threadp->isStopped())
  3497. {
  3498. // Check for any pending signals to send to this thread.
  3499. sThreadsMutex.lock();
  3500. if (sThreadsSignals.count(threadp))
  3501. {
  3502. // Let it know that it has got signals and should pause so that
  3503. // we can send them to it !
  3504. threadp->setSignal();
  3505. }
  3506. sThreadsMutex.unlock();
  3507. continue;
  3508. }
  3509. // If the thread print buffer contains something, print it now.
  3510. if (!threadp->mPrintBuffer.empty() && LLStartUp::isLoggedIn())
  3511. {
  3512. LLChat chat;
  3513. chat.mFromName = threadp->getName();
  3514. chat.mText = chat.mFromName + ": " + threadp->mPrintBuffer;
  3515. chat.mSourceType = CHAT_SOURCE_SYSTEM;
  3516. LLFloaterChat::addChat(chat, false, false);
  3517. threadp->mPrintBuffer.clear();
  3518. }
  3519. // If the thread is stopped, remove it.
  3520. if (threadp->isStopped())
  3521. {
  3522. LL_DEBUGS("Lua") << "Thread '" << threadp->getName()
  3523. << "' stopped, deleting it." << LL_ENDL;
  3524. // Protect sThreadsSignals and sThreadsInstances, in case some
  3525. // other running thread would try and access them (via hasThread()
  3526. // or sendSignal()) while we are deleting this thread.
  3527. sThreadsMutex.lock();
  3528. sThreadsInstances.erase(curit);
  3529. signals_map_t::iterator sit = sThreadsSignals.find(threadp);
  3530. if (sit != sThreadsSignals.end())
  3531. {
  3532. delete sit->second;
  3533. sThreadsSignals.erase(sit);
  3534. }
  3535. sThreadsMutex.unlock();
  3536. delete threadp;
  3537. continue;
  3538. }
  3539. // Check for any pending signals to send to this thread.
  3540. sThreadsMutex.lock();
  3541. signals_map_t::iterator sit = sThreadsSignals.find(threadp);
  3542. if (sit != sThreadsSignals.end())
  3543. {
  3544. HBThreadSignals* signals = sit->second;
  3545. // Current thread Id and Id stored in signals table should match !
  3546. if (signals->mThreadID == threadp->getLuaThreadID())
  3547. {
  3548. // Copy the signal strings in the proper (chronological) order
  3549. // into the thread's own signals vector.
  3550. std::vector<std::string>& sigs_vec = signals->mSignals;
  3551. for (U32 i = 0, count = sigs_vec.size(); i < count; ++i)
  3552. {
  3553. const std::string& sig_str = sigs_vec[i];
  3554. LL_DEBUGS("Lua") << "Copying signal string: " << sig_str
  3555. << LL_ENDL;
  3556. threadp->appendSignal(sig_str);
  3557. }
  3558. }
  3559. // Stale signals from a dead (crashed ?) thread which old address
  3560. // got reaffected to a new thread (unlikely but possible)...
  3561. else
  3562. {
  3563. llwarns << "Non-matching thread Id " << signals->mThreadID
  3564. << " found for signals queue associated with thread "
  3565. << threadp->getLuaThreadID()
  3566. << ": deleting stale queue." << llendl;
  3567. }
  3568. delete signals;
  3569. sThreadsSignals.erase(sit);
  3570. }
  3571. sThreadsMutex.unlock();
  3572. // If the thread is waiting for an automation script function call, we
  3573. // must perform it on its behalf... But later (see below).
  3574. if (threadp->hasFuncCall())
  3575. {
  3576. waiting_threads.push_back(threadp);
  3577. }
  3578. else
  3579. {
  3580. // Let the thread run again
  3581. threadp->setRunning();
  3582. }
  3583. }
  3584. // Now that we cleaned-up sThreadsInstances and sThreadsSignals, we can
  3585. // proceed with performing our custom Lua function calls on behalf of the
  3586. // waiting threads (since these calls could result in changes to either of
  3587. // sThreadsInstances or sThreadsSignals via callbacks they would trigger in
  3588. // the automation script)...
  3589. for (U32 i = 0, count = waiting_threads.size(); i < count; ++i)
  3590. {
  3591. HBAutomationThread* threadp = waiting_threads[i];
  3592. callAutomationFunc(threadp);
  3593. // We can let this thread run again now
  3594. threadp->setRunning();
  3595. }
  3596. }
  3597. void HBViewerAutomation::pushGridSimAndPos()
  3598. {
  3599. LLViewerRegion* regionp = gAgent.getRegion();
  3600. if (regionp)
  3601. {
  3602. lua_newtable(mLuaState);
  3603. lua_pushliteral(mLuaState, "grid");
  3604. lua_pushstring(mLuaState,
  3605. LLGridManager::getInstance()->getGridLabel().c_str());
  3606. lua_rawset(mLuaState, -3);
  3607. lua_pushliteral(mLuaState, "region");
  3608. lua_pushstring(mLuaState, regionp->getName().c_str());
  3609. lua_rawset(mLuaState, -3);
  3610. lua_pushliteral(mLuaState, "version");
  3611. lua_pushstring(mLuaState, gLastVersionChannel.c_str());
  3612. lua_rawset(mLuaState, -3);
  3613. lua_pushliteral(mLuaState, "width");
  3614. lua_pushnumber(mLuaState, regionp->getWidth());
  3615. lua_rawset(mLuaState, -3);
  3616. lua_pushliteral(mLuaState, "water_height");
  3617. lua_pushnumber(mLuaState, regionp->getWaterHeight());
  3618. lua_rawset(mLuaState, -3);
  3619. lua_pushliteral(mLuaState, "flags");
  3620. lua_pushinteger(mLuaState, regionp->getRegionFlags());
  3621. lua_rawset(mLuaState, -3);
  3622. std::vector<S32> neighbors;
  3623. regionp->getNeighboringRegionsStatus(neighbors);
  3624. lua_pushliteral(mLuaState, "neighbors");
  3625. lua_pushinteger(mLuaState, neighbors.size());
  3626. lua_rawset(mLuaState, -3);
  3627. const LLVector3d& pos_global = gAgent.getPositionGlobal();
  3628. lua_pushliteral(mLuaState, "global_x");
  3629. lua_pushnumber(mLuaState, pos_global.mdV[VX]);
  3630. lua_rawset(mLuaState, -3);
  3631. lua_pushliteral(mLuaState, "global_y");
  3632. lua_pushnumber(mLuaState, pos_global.mdV[VY]);
  3633. lua_rawset(mLuaState, -3);
  3634. const LLVector3& pos_local = gAgent.getPositionAgent();
  3635. lua_pushliteral(mLuaState, "local_x");
  3636. lua_pushnumber(mLuaState, pos_local.mV[VX]);
  3637. lua_rawset(mLuaState, -3);
  3638. lua_pushliteral(mLuaState, "local_y");
  3639. lua_pushnumber(mLuaState, pos_local.mV[VY]);
  3640. lua_rawset(mLuaState, -3);
  3641. lua_pushliteral(mLuaState, "altitude");
  3642. lua_pushnumber(mLuaState, pos_local.mV[VZ]);
  3643. lua_rawset(mLuaState, -3);
  3644. lua_pushliteral(mLuaState, "navmesh");
  3645. const char* navmesh;
  3646. if (!regionp->hasDynamicPathfinding())
  3647. {
  3648. navmesh = "none";
  3649. }
  3650. else if (gOverlayBarp && gOverlayBarp->isNavmeshDirty())
  3651. {
  3652. navmesh = "dirty";
  3653. }
  3654. else if (gOverlayBarp && gOverlayBarp->isNavmeshRebaking())
  3655. {
  3656. navmesh = "rebaking";
  3657. }
  3658. else if (regionp->dynamicPathfindingEnabled())
  3659. {
  3660. navmesh = "enabled";
  3661. }
  3662. else
  3663. {
  3664. navmesh = "disabled";
  3665. }
  3666. lua_pushstring(mLuaState, navmesh);
  3667. lua_rawset(mLuaState, -3);
  3668. }
  3669. else
  3670. {
  3671. lua_pushnil(mLuaState);
  3672. }
  3673. }
  3674. void HBViewerAutomation::onLogin()
  3675. {
  3676. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  3677. if (this != gAutomationp) // Paranoia
  3678. {
  3679. return;
  3680. }
  3681. // Ensure mFromObjectId is properly initialized for gAutomationp which is
  3682. // created on viewer launch while gAgentID was still a null UUID...
  3683. mFromObjectId = gAgentID;
  3684. // Print anything that got printed from the automation script before login.
  3685. if (!mPrintBuffer.empty())
  3686. {
  3687. LLChat chat;
  3688. chat.mFromName = "Lua";
  3689. chat.mSourceType = CHAT_SOURCE_SYSTEM;
  3690. chat.mText = "Lua: " + mPrintBuffer;
  3691. mPrintBuffer.clear();
  3692. LLFloaterChat::addChat(chat, false, false);
  3693. }
  3694. if (!mHasOnLogin || !mLuaState) return;
  3695. LL_DEBUGS("Lua") << "Invoking OnLogin Lua callback." << LL_ENDL;
  3696. lua_getglobal(mLuaState, "OnLogin");
  3697. pushGridSimAndPos();
  3698. lua_pushboolean(mLuaState, gAvatarMovedOnLogin);
  3699. lua_pushboolean(mLuaState, gSavedSettings.getBool("AutoLogin"));
  3700. resetTimer();
  3701. if (lua_pcall(mLuaState, 3, 0, 0) != LUA_OK)
  3702. {
  3703. reportError();
  3704. }
  3705. }
  3706. void HBViewerAutomation::onRegionChange()
  3707. {
  3708. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  3709. if (!mHasOnRegionChange || !mLuaState)
  3710. {
  3711. return;
  3712. }
  3713. LL_DEBUGS("Lua") << "Invoking OnRegionChange Lua callback." << LL_ENDL;
  3714. lua_getglobal(mLuaState, "OnRegionChange");
  3715. pushGridSimAndPos();
  3716. resetTimer();
  3717. if (lua_pcall(mLuaState, 1, 0, 0) != LUA_OK)
  3718. {
  3719. reportError();
  3720. }
  3721. }
  3722. void HBViewerAutomation::pushParcelInfo()
  3723. {
  3724. LLViewerRegion* region = gAgent.getRegion();
  3725. LLParcel* parcel = gViewerParcelMgr.getAgentParcel();
  3726. if (region && parcel)
  3727. {
  3728. lua_newtable(mLuaState);
  3729. lua_pushliteral(mLuaState, "name");
  3730. lua_pushstring(mLuaState, parcel->getName().c_str());
  3731. lua_rawset(mLuaState, -3);
  3732. lua_pushliteral(mLuaState, "description");
  3733. lua_pushstring(mLuaState, parcel->getDesc().c_str());
  3734. lua_rawset(mLuaState, -3);
  3735. lua_pushliteral(mLuaState, "flags");
  3736. lua_pushinteger(mLuaState, parcel->getParcelFlags());
  3737. lua_rawset(mLuaState, -3);
  3738. lua_pushliteral(mLuaState, "build");
  3739. lua_pushboolean(mLuaState, gViewerParcelMgr.allowAgentBuild());
  3740. lua_rawset(mLuaState, -3);
  3741. lua_pushliteral(mLuaState, "damage");
  3742. lua_pushboolean(mLuaState,
  3743. gViewerParcelMgr.allowAgentDamage(region, parcel));
  3744. lua_rawset(mLuaState, -3);
  3745. lua_pushliteral(mLuaState, "fly");
  3746. lua_pushboolean(mLuaState,
  3747. gViewerParcelMgr.allowAgentFly(region, parcel));
  3748. lua_rawset(mLuaState, -3);
  3749. lua_pushliteral(mLuaState, "push");
  3750. lua_pushboolean(mLuaState,
  3751. gViewerParcelMgr.allowAgentPush(region, parcel));
  3752. lua_rawset(mLuaState, -3);
  3753. lua_pushliteral(mLuaState, "scripts");
  3754. lua_pushboolean(mLuaState,
  3755. gViewerParcelMgr.allowAgentScripts(region, parcel));
  3756. lua_rawset(mLuaState, -3);
  3757. lua_pushliteral(mLuaState, "see");
  3758. lua_pushboolean(mLuaState,
  3759. !parcel->getHaveNewParcelLimitData() ||
  3760. parcel->getSeeAVs());
  3761. lua_rawset(mLuaState, -3);
  3762. lua_pushliteral(mLuaState, "voice");
  3763. lua_pushboolean(mLuaState,
  3764. gIsInSecondLife ? gViewerParcelMgr.allowAgentVoice()
  3765. : parcel->getParcelFlagAllowVoice());
  3766. lua_rawset(mLuaState, -3);
  3767. }
  3768. else
  3769. {
  3770. lua_pushnil(mLuaState);
  3771. }
  3772. }
  3773. void HBViewerAutomation::onParcelChange()
  3774. {
  3775. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  3776. if (!mHasOnParcelChange || !mLuaState)
  3777. {
  3778. return;
  3779. }
  3780. LL_DEBUGS("Lua") << "Invoking OnParcelChange Lua callback." << LL_ENDL;
  3781. lua_getglobal(mLuaState, "OnParcelChange");
  3782. pushParcelInfo();
  3783. resetTimer();
  3784. if (lua_pcall(mLuaState, 1, 0, 0) != LUA_OK)
  3785. {
  3786. reportError();
  3787. }
  3788. }
  3789. void HBViewerAutomation::onPositionChange(const LLVector3& pos_local,
  3790. const LLVector3d& pos_global)
  3791. {
  3792. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  3793. if (!mHasOnPositionChange || !mLuaState)
  3794. {
  3795. return;
  3796. }
  3797. LL_DEBUGS("Lua") << "Invoking OnPositionChange Lua callback." << LL_ENDL;
  3798. lua_getglobal(mLuaState, "OnPositionChange");
  3799. lua_newtable(mLuaState);
  3800. lua_pushliteral(mLuaState, "global_x");
  3801. lua_pushnumber(mLuaState, pos_global.mdV[VX]);
  3802. lua_rawset(mLuaState, -3);
  3803. lua_pushliteral(mLuaState, "global_y");
  3804. lua_pushnumber(mLuaState, pos_global.mdV[VY]);
  3805. lua_rawset(mLuaState, -3);
  3806. lua_pushliteral(mLuaState, "local_x");
  3807. lua_pushnumber(mLuaState, pos_local.mV[VX]);
  3808. lua_rawset(mLuaState, -3);
  3809. lua_pushliteral(mLuaState, "local_y");
  3810. lua_pushnumber(mLuaState, pos_local.mV[VY]);
  3811. lua_rawset(mLuaState, -3);
  3812. lua_pushliteral(mLuaState, "altitude");
  3813. lua_pushnumber(mLuaState, pos_local.mV[VZ]);
  3814. lua_rawset(mLuaState, -3);
  3815. resetTimer();
  3816. if (lua_pcall(mLuaState, 1, 0, 0) != LUA_OK)
  3817. {
  3818. reportError();
  3819. }
  3820. }
  3821. void HBViewerAutomation::onAveragedFPS(F32 fps, bool limited, F32 frame_time)
  3822. {
  3823. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  3824. if (!mHasOnAveragedFPS || !mLuaState)
  3825. {
  3826. return;
  3827. }
  3828. // Average the frame rates before actually invoking the Lua callback. Note:
  3829. // onAveragedFPS() is called every 200ms or so by the status bar refresh()
  3830. // method, sometimes at a shorter interval whenever the status bar needs an
  3831. // immediate refresh.
  3832. static F32 next_report = 0.f;
  3833. static U32 cumulated_count = 0;
  3834. static F32 cumulative_fps = 0.f;
  3835. static bool has_been_limited = false;
  3836. cumulative_fps += fps;
  3837. ++cumulated_count;
  3838. has_been_limited |= limited;
  3839. if (gFrameTimeSeconds < next_report || cumulated_count < 5)
  3840. {
  3841. return;
  3842. }
  3843. fps = cumulative_fps / F32(cumulated_count);
  3844. limited = has_been_limited;
  3845. cumulative_fps = 0.f;
  3846. cumulated_count = 0;
  3847. has_been_limited = false;
  3848. static LLCachedControl<F32> cb_interval(gSavedSettings,
  3849. "LuaOnAveragedFPSInterval");
  3850. next_report = gFrameTimeSeconds + llmax(1.f, F32(cb_interval));
  3851. LL_DEBUGS("Lua") << "Invoking OnAveragedFPS Lua callback. fps="
  3852. << fps << " - limited=" << (limited ? "true" : "false")
  3853. << " - frame_render_time= " << frame_time << LL_ENDL;
  3854. lua_getglobal(mLuaState, "OnAveragedFPS");
  3855. lua_pushnumber(mLuaState, fps);
  3856. lua_pushboolean(mLuaState, limited);
  3857. lua_pushnumber(mLuaState, frame_time);
  3858. resetTimer();
  3859. if (lua_pcall(mLuaState, 3, 0, 0) != LUA_OK)
  3860. {
  3861. reportError();
  3862. }
  3863. }
  3864. void HBViewerAutomation::onAgentOccupationChange(S32 type)
  3865. {
  3866. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  3867. if (!mHasOnAgentOccupationChange || !mLuaState ||
  3868. sIgnoredCallbacks[E_ONAGENTOCCUPATIONCHANGE])
  3869. {
  3870. return;
  3871. }
  3872. LL_DEBUGS("Lua") << "Invoking OnAgentOccupationChange Lua callback. type="
  3873. << type << LL_ENDL;
  3874. lua_getglobal(mLuaState, "OnAgentOccupationChange");
  3875. lua_pushinteger(mLuaState, type);
  3876. resetTimer();
  3877. if (lua_pcall(mLuaState, 1, 0, 0) != LUA_OK)
  3878. {
  3879. reportError();
  3880. }
  3881. }
  3882. void HBViewerAutomation::onAgentPush(const LLUUID& id, S32 type, F32 mag)
  3883. {
  3884. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  3885. if (!mHasOnAgentPush || !mLuaState) return;
  3886. LL_DEBUGS("Lua") << "Invoking OnAgentPush Lua callback. id=" << id
  3887. << " - type=" << type << " - mag=" << mag << LL_ENDL;
  3888. lua_getglobal(mLuaState, "OnAgentPush");
  3889. lua_pushstring(mLuaState, id.asString().c_str());
  3890. lua_pushinteger(mLuaState, type);
  3891. lua_pushnumber(mLuaState, mag);
  3892. resetTimer();
  3893. if (lua_pcall(mLuaState, 3, 0, 0) != LUA_OK)
  3894. {
  3895. reportError();
  3896. }
  3897. }
  3898. bool HBViewerAutomation::onSendChat(std::string& text)
  3899. {
  3900. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  3901. if (!mHasOnSendChat || !mLuaState || sIgnoredCallbacks[E_ONSENDCHAT])
  3902. {
  3903. return false;
  3904. }
  3905. LL_DEBUGS("Lua") << "Invoking onSendChat Lua callback." << LL_ENDL;
  3906. HBIgnoreCallback lock_on_chat(E_ONSENDCHAT);
  3907. lua_getglobal(mLuaState, "OnSendChat");
  3908. lua_pushstring(mLuaState, text.c_str());
  3909. resetTimer();
  3910. if (lua_pcall(mLuaState, 1, 1, 0) != LUA_OK)
  3911. {
  3912. reportError();
  3913. return false;
  3914. }
  3915. if (lua_gettop(mLuaState) == 0 || lua_type(mLuaState, -1) != LUA_TSTRING)
  3916. {
  3917. lua_settop(mLuaState, 0); // Sanitize stack by emptying it
  3918. lua_pushliteral(mLuaState,
  3919. "OnSendChat() Lua callback did not return a string");
  3920. reportError();
  3921. return false;
  3922. }
  3923. std::string new_text(lua_tolstring(mLuaState, -1, NULL));
  3924. lua_pop(mLuaState, 1);
  3925. if (new_text != text)
  3926. {
  3927. text = new_text;
  3928. return true;
  3929. }
  3930. return false;
  3931. }
  3932. void HBViewerAutomation::onReceivedChat(U8 chat_type, const LLUUID& from_id,
  3933. const std::string& name,
  3934. const std::string& text)
  3935. {
  3936. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  3937. if (!mHasOnReceivedChat || !mLuaState) return;
  3938. LL_DEBUGS("Lua") << "Invoking OnReceivedChat Lua callback. chat_type="
  3939. << chat_type << " - from_id=" << from_id << " - name="
  3940. << name << LL_ENDL;
  3941. lua_getglobal(mLuaState, "OnReceivedChat");
  3942. lua_pushinteger(mLuaState, chat_type);
  3943. lua_pushstring(mLuaState, from_id.asString().c_str());
  3944. lua_pushboolean(mLuaState, gObjectList.findAvatar(from_id) != NULL);
  3945. lua_pushstring(mLuaState, name.c_str());
  3946. lua_pushstring(mLuaState, text.c_str());
  3947. resetTimer();
  3948. if (lua_pcall(mLuaState, 5, 0, 0) != LUA_OK)
  3949. {
  3950. reportError();
  3951. }
  3952. }
  3953. bool HBViewerAutomation::onChatTextColoring(const LLUUID& from_id,
  3954. const std::string& name,
  3955. const std::string& text,
  3956. LLColor4& color)
  3957. {
  3958. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  3959. if (!mHasOnChatTextColoring || !mLuaState) return false;
  3960. LL_DEBUGS("Lua") << "Invoking OnChatTextColoring Lua callback. name="
  3961. << name << LL_ENDL;
  3962. lua_getglobal(mLuaState, "OnChatTextColoring");
  3963. lua_pushstring(mLuaState, from_id.asString().c_str());
  3964. lua_pushstring(mLuaState, name.c_str());
  3965. lua_pushstring(mLuaState, text.c_str());
  3966. resetTimer();
  3967. if (lua_pcall(mLuaState, 3, 1, 0) != LUA_OK)
  3968. {
  3969. reportError();
  3970. }
  3971. if (lua_gettop(mLuaState) == 0 || lua_type(mLuaState, -1) != LUA_TSTRING)
  3972. {
  3973. lua_pushliteral(mLuaState,
  3974. "OnChatTextColoring() Lua callback did not return a string");
  3975. reportError();
  3976. return false;
  3977. }
  3978. std::string color_str(lua_tolstring(mLuaState, -1, NULL));
  3979. lua_pop(mLuaState, 1);
  3980. if (color_str.empty())
  3981. {
  3982. return false;
  3983. }
  3984. if (!LLColor4::parseColor(color_str, &color))
  3985. {
  3986. lua_pushliteral(mLuaState,
  3987. "OnChatTextColoring() Lua returned an invalid color");
  3988. reportError();
  3989. return false;
  3990. }
  3991. return true;
  3992. }
  3993. void HBViewerAutomation::onInstantMsg(const LLUUID& session_id,
  3994. const LLUUID& origin_id,
  3995. const std::string& name,
  3996. const std::string& text)
  3997. {
  3998. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  3999. if (!mHasOnInstantMsg || !mLuaState || sIgnoredCallbacks[E_ONINSTANTMSG])
  4000. {
  4001. return;
  4002. }
  4003. // See LLIMMgr::computeSessionID() for the session Id computation rules
  4004. S32 type;
  4005. LLUUID other_participant_id = session_id;
  4006. if (session_id == gAgentID || (session_id ^ origin_id) == gAgentID)
  4007. {
  4008. LL_DEBUGS("Lua") << "Peer to peer session detected." << LL_ENDL;
  4009. other_participant_id = origin_id;
  4010. type = 0;
  4011. }
  4012. else if (gAgent.isInGroup(session_id, true))
  4013. {
  4014. LL_DEBUGS("Lua") << "Group session detected." << LL_ENDL;
  4015. type = 1;
  4016. }
  4017. else
  4018. {
  4019. LL_DEBUGS("Lua") << "Conference session assumed." << LL_ENDL;
  4020. type = 2;
  4021. }
  4022. LL_DEBUGS("Lua") << "Invoking OnInstantMsg Lua callback. session_id="
  4023. << session_id << " - other_participant_id="
  4024. << other_participant_id << " - type=" << type
  4025. << " - name=" << name << LL_ENDL;
  4026. HBIgnoreCallback lock_on_im(E_ONINSTANTMSG);
  4027. lua_getglobal(mLuaState, "OnInstantMsg");
  4028. lua_pushstring(mLuaState, session_id.asString().c_str());
  4029. lua_pushstring(mLuaState, other_participant_id.asString().c_str());
  4030. lua_pushinteger(mLuaState, type);
  4031. lua_pushstring(mLuaState, name.c_str());
  4032. lua_pushstring(mLuaState, text.c_str());
  4033. resetTimer();
  4034. if (lua_pcall(mLuaState, 5, 0, 0) != LUA_OK)
  4035. {
  4036. reportError();
  4037. }
  4038. }
  4039. // A mere wrapper for onAlertDialog()
  4040. void lua_alert_callback(const std::string& dialog_name, const LLUUID& alert_id,
  4041. const std::string& message,
  4042. const std::vector<std::string>& buttons)
  4043. {
  4044. if (gAutomationp)
  4045. {
  4046. gAutomationp->onAlertDialog(dialog_name, alert_id, message, buttons);
  4047. }
  4048. }
  4049. void HBViewerAutomation::onAlertDialog(const std::string& dialog_name,
  4050. const LLUUID& alert_id,
  4051. const std::string& message,
  4052. const std::vector<std::string>& buttons)
  4053. {
  4054. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  4055. if (!mHasOnAlertDialog || !mLuaState || dialog_name == "LuaAlert")
  4056. {
  4057. return;
  4058. }
  4059. LL_DEBUGS("Lua") << "Invoking OnAlertDialog Lua callback. dialog_name="
  4060. << dialog_name << " - alert_id=" << alert_id << LL_ENDL;
  4061. lua_getglobal(mLuaState, "OnAlertDialog");
  4062. lua_pushstring(mLuaState, dialog_name.c_str());
  4063. lua_pushstring(mLuaState, alert_id.asString().c_str());
  4064. lua_pushstring(mLuaState, message.c_str());
  4065. lua_newtable(mLuaState);
  4066. for (S32 i = 0, count = buttons.size(); i < count; ++i)
  4067. {
  4068. lua_pushnumber(mLuaState, i + 1);
  4069. lua_pushstring(mLuaState, buttons[i].c_str());
  4070. lua_rawset(mLuaState, -3);
  4071. }
  4072. resetTimer();
  4073. if (lua_pcall(mLuaState, 4, 0, 0) != LUA_OK)
  4074. {
  4075. reportError();
  4076. }
  4077. }
  4078. void HBViewerAutomation::onScriptDialog(const LLUUID& notif_id,
  4079. const std::string& message,
  4080. const std::vector<std::string>& buttons)
  4081. {
  4082. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  4083. if (!mHasOnScriptDialog || !mLuaState) return;
  4084. LL_DEBUGS("Lua") << "Invoking OnScriptDialog Lua callback. notif_id="
  4085. << notif_id << LL_ENDL;
  4086. lua_getglobal(mLuaState, "OnScriptDialog");
  4087. lua_pushstring(mLuaState, notif_id.asString().c_str());
  4088. lua_pushstring(mLuaState, message.c_str());
  4089. lua_newtable(mLuaState);
  4090. for (S32 i = 0, count = buttons.size(); i < count; ++i)
  4091. {
  4092. lua_pushnumber(mLuaState, i + 1);
  4093. lua_pushstring(mLuaState, buttons[i].c_str());
  4094. lua_rawset(mLuaState, -3);
  4095. }
  4096. resetTimer();
  4097. if (lua_pcall(mLuaState, 3, 0, 0) != LUA_OK)
  4098. {
  4099. reportError();
  4100. }
  4101. }
  4102. void HBViewerAutomation::onNotification(const std::string& dialog_name,
  4103. const LLUUID& notif_id,
  4104. const std::string& message)
  4105. {
  4106. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  4107. if (!mHasOnNotification || !mLuaState ||
  4108. dialog_name == "LuaNotifyTip" || dialog_name == "LuaNotification")
  4109. {
  4110. return;
  4111. }
  4112. LL_DEBUGS("Lua") << "Invoking OnNotification Lua callback. dialog_name="
  4113. << dialog_name << " - notif_id=" << notif_id << LL_ENDL;
  4114. lua_getglobal(mLuaState, "OnNotification");
  4115. lua_pushstring(mLuaState, dialog_name.c_str());
  4116. lua_pushstring(mLuaState, notif_id.asString().c_str());
  4117. lua_pushstring(mLuaState, message.c_str());
  4118. resetTimer();
  4119. if (lua_pcall(mLuaState, 3, 0, 0) != LUA_OK)
  4120. {
  4121. reportError();
  4122. }
  4123. }
  4124. bool HBViewerAutomation::onSLURLDispatch(const std::string& slurl,
  4125. const std::string& nav_type,
  4126. bool trusted)
  4127. {
  4128. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  4129. if (!mHasOnSLURLDispatch || !mLuaState ||
  4130. sIgnoredCallbacks[E_ONDISPATCHSLURL])
  4131. {
  4132. return true; // 'true' means "allow dispatching".
  4133. }
  4134. LL_DEBUGS("Lua") << "Invoking OnSLURLDispatch Lua callback. slurl="
  4135. << slurl << " - nav_type=" << nav_type << " - trusted="
  4136. << (trusted ? " true" : "false") << LL_ENDL;
  4137. lua_getglobal(mLuaState, "OnSLURLDispatch");
  4138. lua_pushstring(mLuaState, slurl.c_str());
  4139. lua_pushstring(mLuaState, nav_type.c_str());
  4140. lua_pushboolean(mLuaState, trusted);
  4141. resetTimer();
  4142. if (lua_pcall(mLuaState, 3, 1, 0) != LUA_OK)
  4143. {
  4144. reportError();
  4145. }
  4146. if (lua_gettop(mLuaState) == 0 || lua_type(mLuaState, -1) != LUA_TBOOLEAN)
  4147. {
  4148. lua_settop(mLuaState, 0); // Sanitize stack by emptying it
  4149. lua_pushliteral(mLuaState,
  4150. "OnSLURLDispatch() Lua callback did not return a boolean");
  4151. reportError();
  4152. return true; // 'true' means "allow dispatching".
  4153. }
  4154. bool result = lua_toboolean(mLuaState, -1);
  4155. lua_pop(mLuaState, 1);
  4156. return result;
  4157. }
  4158. U32 HBViewerAutomation::onURLDispatch(const std::string& url,
  4159. const std::string& target,
  4160. bool external_browser)
  4161. {
  4162. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  4163. if (!mHasOnURLDispatch || !mLuaState || sIgnoredCallbacks[E_ONDISPATCHURL])
  4164. {
  4165. // If no callback, do not modify the configured dispatching.
  4166. return external_browser ? 2 : 1;
  4167. }
  4168. LL_DEBUGS("Lua") << "Invoking OnURLDispatch Lua callback. url="
  4169. << url << " - target=" << target << LL_ENDL;
  4170. lua_getglobal(mLuaState, "OnURLDispatch");
  4171. lua_pushstring(mLuaState, url.c_str());
  4172. lua_pushstring(mLuaState, target.c_str());
  4173. lua_pushboolean(mLuaState, external_browser);
  4174. resetTimer();
  4175. if (lua_pcall(mLuaState, 3, 1, 0) != LUA_OK)
  4176. {
  4177. reportError();
  4178. }
  4179. if (lua_gettop(mLuaState) == 0 || lua_type(mLuaState, -1) != LUA_TNUMBER)
  4180. {
  4181. lua_settop(mLuaState, 0); // Sanitize stack by emptying it
  4182. lua_pushliteral(mLuaState,
  4183. "OnURLDispatch() Lua callback did not return a number");
  4184. reportError();
  4185. return external_browser ? 2 : 1;
  4186. }
  4187. S32 result = llclamp(lua_tonumber(mLuaState, -1), -1, 2);
  4188. lua_pop(mLuaState, 1);
  4189. if (result < 0)
  4190. {
  4191. result = external_browser ? 2 : 1;
  4192. }
  4193. return (U32)result;
  4194. }
  4195. void HBViewerAutomation::onFriendStatusChange(const LLUUID& id, U32 mask,
  4196. bool is_online)
  4197. {
  4198. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  4199. if (!mHasOnFriendStatusChange || !mLuaState) return;
  4200. LL_DEBUGS("Lua") << "Invoking OnFriendStatusChange Lua callback. id="
  4201. << id << " - mask=" << mask << " - is_online="
  4202. << (is_online ? " true" : "false") << LL_ENDL;
  4203. lua_getglobal(mLuaState, "OnFriendStatusChange");
  4204. lua_pushstring(mLuaState, id.asString().c_str());
  4205. lua_pushinteger(mLuaState, mask);
  4206. lua_pushboolean(mLuaState, is_online);
  4207. resetTimer();
  4208. if (lua_pcall(mLuaState, 3, 0, 0) != LUA_OK)
  4209. {
  4210. reportError();
  4211. }
  4212. }
  4213. void HBViewerAutomation::onAvatarRezzing(const LLUUID& id)
  4214. {
  4215. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  4216. if (!mHasOnAvatarRezzing || !mLuaState) return;
  4217. LL_DEBUGS("Lua") << "Invoking OnAvatarRezzing Lua callback. id="
  4218. << id << LL_ENDL;
  4219. lua_getglobal(mLuaState, "OnAvatarRezzing");
  4220. lua_pushstring(mLuaState, id.asString().c_str());
  4221. resetTimer();
  4222. if (lua_pcall(mLuaState, 1, 0, 0) != LUA_OK)
  4223. {
  4224. reportError();
  4225. }
  4226. }
  4227. void HBViewerAutomation::onAgentBaked()
  4228. {
  4229. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  4230. if (!mHasOnAgentBaked || !mLuaState || !isAgentAvatarValid()) return;
  4231. if (!gAgent.isGodlikeWithoutAdminMenuFakery() &&
  4232. !enable_avatar_textures(NULL))
  4233. {
  4234. return;
  4235. }
  4236. LL_DEBUGS("Lua") << "Queuing OnAgentBaked Lua callback." << LL_ENDL;
  4237. // We use a callback with a 2 seconds delay, because we may otherwise
  4238. // encounter race conditions between baking, messaging (in OpenSIM, with
  4239. // legacy UDP messages), and the actual availability of the baked textures.
  4240. doAfterInterval(boost::bind(&doCallOnAgentBaked, mLuaState), 2.f);
  4241. }
  4242. //static
  4243. void HBViewerAutomation::doCallOnAgentBaked(lua_State* state)
  4244. {
  4245. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  4246. HBViewerAutomation* self = findInstance(state);
  4247. if (!self || !self->mHasOnAgentBaked || !isAgentAvatarValid()) return;
  4248. // Double check...
  4249. if (!gAgent.isGodlikeWithoutAdminMenuFakery() &&
  4250. !enable_avatar_textures(NULL))
  4251. {
  4252. return;
  4253. }
  4254. LL_DEBUGS("Lua") << "Invoking OnAgentBaked Lua callback." << LL_ENDL;
  4255. lua_getglobal(state, "OnAgentBaked");
  4256. lua_newtable(state);
  4257. std::string te_name;
  4258. uuid_vec_t ids;
  4259. for (S32 i = 0, count = gAgentAvatarp->getNumTEs(); i < count; ++i)
  4260. {
  4261. LLFloaterAvatarTextures::getTextureIds(gAgentAvatarp, ETextureIndex(i),
  4262. te_name, ids);
  4263. const LLUUID& id = ids[0];
  4264. if (id != IMG_DEFAULT_AVATAR &&
  4265. te_name.rfind("-baked") != std::string::npos)
  4266. {
  4267. lua_pushstring(state, te_name.c_str());
  4268. lua_pushstring(state, id.asString().c_str());
  4269. lua_rawset(state, -3);
  4270. }
  4271. }
  4272. self->resetTimer();
  4273. if (lua_pcall(state, 1, 0, 0) != LUA_OK)
  4274. {
  4275. self->reportError();
  4276. }
  4277. }
  4278. void HBViewerAutomation::onRadar(const LLUUID& id, const std::string& name,
  4279. S32 range, bool marked)
  4280. {
  4281. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  4282. if (!mHasOnRadar || !mLuaState) return;
  4283. LL_DEBUGS("Lua") << "Invoking OnRadar Lua callback. id=" << id
  4284. << " - name=" << name << " - range=" << range
  4285. << " - marked=" << marked << LL_ENDL;
  4286. lua_getglobal(mLuaState, "OnRadar");
  4287. lua_pushstring(mLuaState, id.asString().c_str());
  4288. lua_pushstring(mLuaState, name.c_str());
  4289. lua_pushinteger(mLuaState, range);
  4290. lua_pushboolean(mLuaState, marked);
  4291. resetTimer();
  4292. if (lua_pcall(mLuaState, 4, 0, 0) != LUA_OK)
  4293. {
  4294. reportError();
  4295. }
  4296. }
  4297. void HBViewerAutomation::onRadarSelection(const uuid_vec_t& ids)
  4298. {
  4299. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  4300. if (!mHasOnRadarSelection || !mLuaState || ids.empty()) return;
  4301. S32 count = ids.size();
  4302. LL_DEBUGS("Lua") << "Invoking OnRadarSelection Lua callback with " << count
  4303. << " selected radar entries." << LL_ENDL;
  4304. lua_getglobal(mLuaState, "OnRadarSelection");
  4305. lua_newtable(mLuaState);
  4306. for (S32 i = 0; i < count; ++i)
  4307. {
  4308. lua_pushstring(mLuaState, ids[i].asString().c_str());
  4309. lua_rawseti(mLuaState, -2, i + 1);
  4310. }
  4311. resetTimer();
  4312. if (lua_pcall(mLuaState, 1, 0, 0) != LUA_OK)
  4313. {
  4314. reportError();
  4315. }
  4316. }
  4317. void HBViewerAutomation::onRadarMark(const LLUUID& id, const std::string& name,
  4318. bool marked)
  4319. {
  4320. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  4321. if (!mHasOnRadarMark || !mLuaState) return;
  4322. LL_DEBUGS("Lua") << "Invoking OnRadarMark Lua callback. avid=" << id
  4323. << " - name=" << name << " - marked="
  4324. << (marked ? "true" : "false") << LL_ENDL;
  4325. lua_getglobal(mLuaState, "OnRadarMark");
  4326. lua_pushstring(mLuaState, id.asString().c_str());
  4327. lua_pushstring(mLuaState, name.c_str());
  4328. lua_pushboolean(mLuaState, marked);
  4329. resetTimer();
  4330. if (lua_pcall(mLuaState, 3, 0, 0) != LUA_OK)
  4331. {
  4332. reportError();
  4333. }
  4334. }
  4335. void HBViewerAutomation::onRadarTrack(const LLUUID& id,
  4336. const std::string& name, bool tracked)
  4337. {
  4338. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  4339. if (!mHasOnRadarTrack || !mLuaState || sIgnoredCallbacks[E_ONRADARTRACK])
  4340. {
  4341. return;
  4342. }
  4343. LL_DEBUGS("Lua") << "Invoking OnRadarTrack Lua callback. avid=" << id
  4344. << " - name=" << name << " - tracking="
  4345. << (tracked ? "true" : "false") << LL_ENDL;
  4346. lua_getglobal(mLuaState, "OnRadarTrack");
  4347. lua_pushstring(mLuaState, id.asString().c_str());
  4348. lua_pushstring(mLuaState, name.c_str());
  4349. lua_pushboolean(mLuaState, tracked);
  4350. resetTimer();
  4351. if (lua_pcall(mLuaState, 3, 0, 0) != LUA_OK)
  4352. {
  4353. reportError();
  4354. }
  4355. }
  4356. void HBViewerAutomation::onLuaDialogClose(const std::string& title, S32 button,
  4357. const std::string& text)
  4358. {
  4359. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  4360. if (!mHasOnLuaDialogClose || !mLuaState) return;
  4361. LL_DEBUGS("Lua") << "Invoking OnLuaDialogClose Lua callback. button="
  4362. << button << " - text=" << text << LL_ENDL;
  4363. lua_getglobal(mLuaState, "OnLuaDialogClose");
  4364. lua_pushstring(mLuaState, title.c_str());
  4365. lua_pushinteger(mLuaState, button);
  4366. lua_pushstring(mLuaState, text.c_str());
  4367. resetTimer();
  4368. if (lua_pcall(mLuaState, 3, 0, 0) != LUA_OK)
  4369. {
  4370. reportError();
  4371. }
  4372. }
  4373. void HBViewerAutomation::onLuaFloaterAction(const std::string& floater_name,
  4374. const std::string& ctrl_name,
  4375. const std::string& value)
  4376. {
  4377. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  4378. if (!mHasOnLuaFloaterAction || !mLuaState) return;
  4379. LL_DEBUGS("Lua") << "Invoking OnLuaFloaterAction Lua callback. Floater: "
  4380. << floater_name << " - Control: " << ctrl_name
  4381. << " - Value: " << value << LL_ENDL;
  4382. lua_getglobal(mLuaState, "OnLuaFloaterAction");
  4383. lua_pushstring(mLuaState, floater_name.c_str());
  4384. lua_pushstring(mLuaState, ctrl_name.c_str());
  4385. lua_pushstring(mLuaState, value.c_str());
  4386. resetTimer();
  4387. if (lua_pcall(mLuaState, 3, 0, 0) != LUA_OK)
  4388. {
  4389. reportError();
  4390. }
  4391. }
  4392. void HBViewerAutomation::onLuaFloaterOpen(const std::string& floater_name,
  4393. const std::string& parameter)
  4394. {
  4395. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  4396. if (!mHasOnLuaFloaterOpen || !mLuaState) return;
  4397. LL_DEBUGS("Lua") << "Invoking OnLuaFloaterOpen Lua callback. Floater: "
  4398. << floater_name << LL_ENDL;
  4399. lua_getglobal(mLuaState, "OnLuaFloaterOpen");
  4400. lua_pushstring(mLuaState, floater_name.c_str());
  4401. lua_pushstring(mLuaState, parameter.c_str());
  4402. resetTimer();
  4403. if (lua_pcall(mLuaState, 2, 0, 0) != LUA_OK)
  4404. {
  4405. reportError();
  4406. }
  4407. }
  4408. void HBViewerAutomation::onLuaFloaterClose(const std::string& floater_name,
  4409. const std::string& parameter)
  4410. {
  4411. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  4412. if (!mHasOnLuaFloaterClose || !mLuaState) return;
  4413. LL_DEBUGS("Lua") << "Invoking OnLuaFloaterClose Lua callback. Floater: "
  4414. << floater_name << LL_ENDL;
  4415. lua_getglobal(mLuaState, "OnLuaFloaterClose");
  4416. lua_pushstring(mLuaState, floater_name.c_str());
  4417. lua_pushstring(mLuaState, parameter.c_str());
  4418. resetTimer();
  4419. if (lua_pcall(mLuaState, 2, 0, 0) != LUA_OK)
  4420. {
  4421. reportError();
  4422. }
  4423. }
  4424. void HBViewerAutomation::onSideBarVisibilityChange(bool visible)
  4425. {
  4426. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  4427. if (!mHasOnSideBarVisibilityChange || !mLuaState) return;
  4428. LL_DEBUGS("Lua") << "Invoking OnSideBarVisibilityChange Lua callback. visible="
  4429. << (visible ? "true" : "false") << LL_ENDL;
  4430. lua_getglobal(mLuaState, "OnSideBarVisibilityChange");
  4431. lua_pushboolean(mLuaState, visible);
  4432. resetTimer();
  4433. if (lua_pcall(mLuaState, 1, 0, 0) != LUA_OK)
  4434. {
  4435. reportError();
  4436. }
  4437. }
  4438. void HBViewerAutomation::onTPStateChange(S32 state, const std::string& reason)
  4439. {
  4440. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  4441. if (!mHasOnTPStateChange || !mLuaState)
  4442. {
  4443. return;
  4444. }
  4445. LL_DEBUGS("Lua") << "Invoking OnTPStateChange Lua callback. state="
  4446. << state << " - Reason: " << reason << LL_ENDL;
  4447. lua_getglobal(mLuaState, "OnTPStateChange");
  4448. lua_pushinteger(mLuaState, state);
  4449. lua_pushstring(mLuaState, reason.c_str());
  4450. resetTimer();
  4451. if (lua_pcall(mLuaState, 2, 0, 0) != LUA_OK)
  4452. {
  4453. reportError();
  4454. }
  4455. }
  4456. void HBViewerAutomation::onFailedTPSimChange(S32 agents_count)
  4457. {
  4458. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  4459. if (!mHasOnFailedTPSimChange || !mLuaState ||
  4460. // Is a teleport in progress ?
  4461. gAgent.teleportInProgress() ||
  4462. // Are there valid global TP coordinates available ?
  4463. gAgent.getTeleportedPosGlobal().isExactlyZero())
  4464. {
  4465. return;
  4466. }
  4467. LL_DEBUGS("Lua") << "Invoking OnFailedTPSimChange Lua callback. agents_count="
  4468. << agents_count << LL_ENDL;
  4469. lua_getglobal(mLuaState, "OnFailedTPSimChange");
  4470. lua_pushinteger(mLuaState, agents_count);
  4471. lua_pushinteger(mLuaState, gAgent.getTeleportedPosGlobal().mdV[VX]);
  4472. lua_pushinteger(mLuaState, gAgent.getTeleportedPosGlobal().mdV[VY]);
  4473. lua_pushinteger(mLuaState, gAgent.getTeleportedPosGlobal().mdV[VZ]);
  4474. resetTimer();
  4475. if (lua_pcall(mLuaState, 4, 0, 0) != LUA_OK)
  4476. {
  4477. reportError();
  4478. }
  4479. }
  4480. void HBViewerAutomation::onWindlightChange(const std::string& sky_settings,
  4481. const std::string& water_settings,
  4482. const std::string& day_settings)
  4483. {
  4484. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  4485. if (!mHasOnWindlightChange || !mLuaState ||
  4486. sIgnoredCallbacks[E_ONWINDLIGHTCHANGE])
  4487. {
  4488. return;
  4489. }
  4490. LL_DEBUGS("Lua") << "Invoking OnWindlightChange Lua callback. sky_settings_name="
  4491. << sky_settings << " - water_settings_name="
  4492. << water_settings << " - day_settings_name="
  4493. << day_settings << LL_ENDL;
  4494. lua_getglobal(mLuaState, "OnWindlightChange");
  4495. lua_pushstring(mLuaState, sky_settings.c_str());
  4496. lua_pushstring(mLuaState, water_settings.c_str());
  4497. lua_pushstring(mLuaState, day_settings.c_str());
  4498. resetTimer();
  4499. if (lua_pcall(mLuaState, 3, 0, 0) != LUA_OK)
  4500. {
  4501. reportError();
  4502. }
  4503. }
  4504. void HBViewerAutomation::onCameraModeChange(S32 mode)
  4505. {
  4506. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  4507. if (!mHasOnCameraModeChange || !mLuaState ||
  4508. sIgnoredCallbacks[E_ONCAMERAMODECHANGE])
  4509. {
  4510. return;
  4511. }
  4512. LL_DEBUGS("Lua") << "Invoking OnCameraModeChange Lua callback. mode="
  4513. << mode << LL_ENDL;
  4514. lua_getglobal(mLuaState, "OnCameraModeChange");
  4515. lua_pushinteger(mLuaState, mode);
  4516. resetTimer();
  4517. if (lua_pcall(mLuaState, 1, 0, 0) != LUA_OK)
  4518. {
  4519. reportError();
  4520. }
  4521. }
  4522. void HBViewerAutomation::onJoystickButtons(S32 old_state, S32 new_state)
  4523. {
  4524. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  4525. if (!mHasOnJoystickButtons || !mLuaState)
  4526. {
  4527. return;
  4528. }
  4529. LL_DEBUGS("Lua") << "Invoking OnJoystickButtons Lua callback. old_state="
  4530. << old_state << " - new_state=" << new_state << LL_ENDL;
  4531. lua_getglobal(mLuaState, "OnJoystickButtons");
  4532. lua_pushinteger(mLuaState, old_state);
  4533. lua_pushinteger(mLuaState, new_state);
  4534. resetTimer();
  4535. if (lua_pcall(mLuaState, 2, 0, 0) != LUA_OK)
  4536. {
  4537. reportError();
  4538. }
  4539. }
  4540. void HBViewerAutomation::onLuaPieMenu(U32 slice, S32 type, const LLPickInfo& pick)
  4541. {
  4542. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  4543. if (!mHasOnLuaPieMenu || !mLuaState)
  4544. {
  4545. return;
  4546. }
  4547. LL_DEBUGS("Lua") << "Invoking OnLuaPieMenu Lua callback." << LL_ENDL;
  4548. lua_getglobal(mLuaState, "OnLuaPieMenu");
  4549. lua_newtable(mLuaState);
  4550. lua_pushliteral(mLuaState, "type");
  4551. lua_pushinteger(mLuaState, type);
  4552. lua_rawset(mLuaState, -3);
  4553. lua_pushliteral(mLuaState, "slice");
  4554. lua_pushinteger(mLuaState, slice);
  4555. lua_rawset(mLuaState, -3);
  4556. const LLVector3d& pos_global = pick.mPosGlobal;
  4557. lua_pushliteral(mLuaState, "global_x");
  4558. lua_pushnumber(mLuaState, pos_global.mdV[VX]);
  4559. lua_rawset(mLuaState, -3);
  4560. lua_pushliteral(mLuaState, "global_y");
  4561. lua_pushnumber(mLuaState, pos_global.mdV[VY]);
  4562. lua_rawset(mLuaState, -3);
  4563. lua_pushliteral(mLuaState, "altitude");
  4564. lua_pushnumber(mLuaState, pos_global.mdV[VZ]);
  4565. lua_rawset(mLuaState, -3);
  4566. const LLUUID& object_id = pick.mObjectID;
  4567. lua_pushliteral(mLuaState, "object_id");
  4568. lua_pushstring(mLuaState, object_id.asString().c_str());
  4569. lua_rawset(mLuaState, -3);
  4570. if (object_id.notNull())
  4571. {
  4572. lua_pushliteral(mLuaState, "object_face");
  4573. lua_pushinteger(mLuaState, pick.mObjectFace);
  4574. lua_rawset(mLuaState, -3);
  4575. }
  4576. if (type == PICKED_PARTICLE)
  4577. {
  4578. lua_pushliteral(mLuaState, "particle_owner_id");
  4579. lua_pushstring(mLuaState, pick.mParticleOwnerID.asString().c_str());
  4580. lua_rawset(mLuaState, -3);
  4581. lua_pushliteral(mLuaState, "particle_source_id");
  4582. lua_pushstring(mLuaState, pick.mParticleSourceID.asString().c_str());
  4583. lua_rawset(mLuaState, -3);
  4584. }
  4585. resetTimer();
  4586. if (lua_pcall(mLuaState, 1, 0, 0) != LUA_OK)
  4587. {
  4588. reportError();
  4589. }
  4590. }
  4591. //static
  4592. void HBViewerAutomation::contextMenuCallback(HBContextMenuData* datap)
  4593. {
  4594. if (gAutomationp && datap)
  4595. {
  4596. bool ret = gAutomationp->onContextMenu(datap->mHandlerID,
  4597. datap->mOperation,
  4598. datap->mMenuType);
  4599. if (ret)
  4600. {
  4601. // When the OnContextMenu Lua callback returns true, perform the
  4602. // default operation, where appropriate.
  4603. switch (datap->mOperation)
  4604. {
  4605. case HBContextMenuData::SET:
  4606. ret = LLEditMenuHandler::setCustomMenu(datap->mHandlerID,
  4607. "Cut to Lua",
  4608. "Copy to Lua",
  4609. "Paste from Lua");
  4610. LL_DEBUGS("Lua") << "Default Lua context entries creation "
  4611. << (ret ? "succeeded" : "failed")
  4612. << " for handler_id=" << datap->mHandlerID
  4613. << LL_ENDL;
  4614. break;
  4615. case HBContextMenuData::PASTE:
  4616. ret = LLEditMenuHandler::pasteTo(datap->mHandlerID);
  4617. LL_DEBUGS("Lua") << "Pasting "
  4618. << (ret ? "succeeded" : "failed")
  4619. << " to handler_id=" << datap->mHandlerID
  4620. << LL_ENDL;
  4621. break;
  4622. default:
  4623. LL_DEBUGS("Lua") << "handler_id=" << " - operation="
  4624. << datap->mOperation << LL_ENDL;
  4625. }
  4626. }
  4627. else
  4628. {
  4629. LL_DEBUGS("Lua") << "No default action taken for handler_id="
  4630. << datap->mHandlerID << " - operation="
  4631. << datap->mOperation << LL_ENDL;
  4632. }
  4633. }
  4634. delete datap;
  4635. }
  4636. bool HBViewerAutomation::onContextMenu(U32 handler_id, S32 operation,
  4637. const std::string& type)
  4638. {
  4639. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  4640. if (!mHasOnContextMenu || !mLuaState)
  4641. {
  4642. return false;
  4643. }
  4644. LL_DEBUGS("Lua") << "Invoking OnContextMenu Lua callback. handler_id="
  4645. << handler_id << " - operation=" << operation
  4646. << " - type=" << type << LL_ENDL;
  4647. lua_getglobal(mLuaState, "OnContextMenu");
  4648. lua_pushstring(mLuaState, type.c_str());
  4649. lua_pushinteger(mLuaState, handler_id);
  4650. lua_pushinteger(mLuaState, operation);
  4651. lua_pushstring(mLuaState,
  4652. wstring_to_utf8str(gClipboard.getClipBoardString()).c_str());
  4653. resetTimer();
  4654. if (lua_pcall(mLuaState, 4, 1, 0) != LUA_OK)
  4655. {
  4656. reportError();
  4657. return false;
  4658. }
  4659. if (lua_gettop(mLuaState) == 0 || lua_type(mLuaState, -1) != LUA_TBOOLEAN)
  4660. {
  4661. lua_settop(mLuaState, 0); // Sanitize stack by emptying it
  4662. lua_pushliteral(mLuaState,
  4663. "OnContextMenu() Lua callback did not return a boolean");
  4664. reportError();
  4665. return false;
  4666. }
  4667. bool result = lua_toboolean(mLuaState, -1);
  4668. lua_pop(mLuaState, 1);
  4669. return result;
  4670. }
  4671. void HBViewerAutomation::onRLVHandleCommand(const LLUUID& object_id,
  4672. const std::string& behav,
  4673. const std::string& option,
  4674. const std::string& param)
  4675. {
  4676. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  4677. if (!mHasOnRLVHandleCommand || !mLuaState) return;
  4678. LL_DEBUGS("Lua") << "Invoking OnRLVHandleCommand Lua callback. Object Id: "
  4679. << object_id << " - behav=" << behav << " - option="
  4680. << option << " - param=" << param << LL_ENDL;
  4681. lua_getglobal(mLuaState, "OnRLVHandleCommand");
  4682. lua_pushstring(mLuaState, object_id.asString().c_str());
  4683. lua_pushstring(mLuaState, behav.c_str());
  4684. lua_pushstring(mLuaState, option.c_str());
  4685. lua_pushstring(mLuaState, param.c_str());
  4686. resetTimer();
  4687. if (lua_pcall(mLuaState, 4, 0, 0) != LUA_OK)
  4688. {
  4689. reportError();
  4690. }
  4691. }
  4692. void HBViewerAutomation::onRLVAnswerOnChat(const LLUUID& obj_id, S32 channel,
  4693. const std::string& text)
  4694. {
  4695. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  4696. if (!mHasOnRLVAnswerOnChat || !mLuaState) return;
  4697. LL_DEBUGS("Lua") << "Invoking OnRLVAnswerOnChat Lua callback for object Id: "
  4698. << obj_id << " - channel: " << channel << LL_ENDL;
  4699. lua_getglobal(mLuaState, "OnRLVAnswerOnChat");
  4700. lua_pushstring(mLuaState, obj_id.asString().c_str());
  4701. lua_pushinteger(mLuaState, channel);
  4702. lua_pushstring(mLuaState, text.c_str());
  4703. resetTimer();
  4704. if (lua_pcall(mLuaState, 3, 0, 0) != LUA_OK)
  4705. {
  4706. reportError();
  4707. }
  4708. }
  4709. void HBViewerAutomation::onObjectInfoReply(const LLUUID& object_id,
  4710. const std::string& name,
  4711. const std::string& desc,
  4712. const LLUUID& owner_id,
  4713. const LLUUID& group_id)
  4714. {
  4715. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  4716. if (!mHasOnObjectInfoReply || !mLuaState) return;
  4717. LL_DEBUGS("Lua") << "Invoking OnObjectInfoReply Lua callback. Object: "
  4718. << name << " (" << object_id << ")" << LL_ENDL;
  4719. lua_getglobal(mLuaState, "OnObjectInfoReply");
  4720. lua_pushstring(mLuaState, object_id.asString().c_str());
  4721. lua_pushstring(mLuaState, name.c_str());
  4722. lua_pushstring(mLuaState, desc.c_str());
  4723. lua_pushstring(mLuaState, owner_id.asString().c_str());
  4724. lua_pushstring(mLuaState, group_id.asString().c_str());
  4725. resetTimer();
  4726. if (lua_pcall(mLuaState, 5, 0, 0) != LUA_OK)
  4727. {
  4728. reportError();
  4729. }
  4730. }
  4731. void HBViewerAutomation::resetTimer()
  4732. {
  4733. mWatchdogTimer.start();
  4734. mWatchdogTimer.setTimerExpirySec(mWatchdogTimeout);
  4735. }
  4736. //static
  4737. void HBViewerAutomation::watchdog(lua_State* state, lua_Debug*)
  4738. {
  4739. HBViewerAutomation* self = findInstance(state);
  4740. if (self)
  4741. {
  4742. if (self->mWatchdogTimer.hasExpired())
  4743. {
  4744. lua_pushliteral(state, "Lua watchdog timeout reached !");
  4745. lua_error(state);
  4746. }
  4747. }
  4748. else
  4749. {
  4750. llwarns << "Lua instance gone !" << llendl;
  4751. }
  4752. }
  4753. //static
  4754. bool HBViewerAutomation::requestObjectPropertiesFamily(const LLUUID& object_id,
  4755. U32 reason)
  4756. {
  4757. LLMessageSystem* msg = gMessageSystemp;
  4758. if (!msg || object_id.isNull())
  4759. {
  4760. return false;
  4761. }
  4762. // We need for the object to be around...
  4763. LLViewerObject* objectp = gObjectList.findObject(object_id);
  4764. if (!objectp)
  4765. {
  4766. return false;
  4767. }
  4768. // We need for the object to have a region (which should always be the
  4769. // case)...
  4770. LLViewerRegion* regionp = objectp->getRegion();
  4771. if (!regionp)
  4772. {
  4773. return false;
  4774. }
  4775. bool in_mute = sMuteObjectRequests.count(object_id) != 0;
  4776. bool in_unmute = sUnmuteObjectRequests.count(object_id) != 0;
  4777. bool in_object_info = false;
  4778. if (gAutomationp)
  4779. {
  4780. in_object_info =
  4781. gAutomationp->mObjectInfoRequests.count(object_id) != 0;
  4782. }
  4783. switch (reason)
  4784. {
  4785. case 0: // For mute
  4786. if (in_mute)
  4787. {
  4788. return true; // No need to re-request
  4789. }
  4790. sMuteObjectRequests.emplace(object_id);
  4791. if (in_unmute || in_object_info)
  4792. {
  4793. return true; // No need to re-request
  4794. }
  4795. break;
  4796. case 1: // For un-mute
  4797. if (in_unmute)
  4798. {
  4799. return true; // No need to re-request
  4800. }
  4801. sUnmuteObjectRequests.emplace(object_id);
  4802. if (in_mute || in_object_info)
  4803. {
  4804. return true; // No need to re-request
  4805. }
  4806. break;
  4807. default: // For object info request
  4808. if (!gAutomationp)
  4809. {
  4810. return false; // Not requesting if no automation script
  4811. }
  4812. if (in_object_info)
  4813. {
  4814. return true; // No need to re-request
  4815. }
  4816. gAutomationp->mObjectInfoRequests.emplace(object_id);
  4817. if (in_mute || in_unmute)
  4818. {
  4819. return true; // No need to re-request
  4820. }
  4821. }
  4822. msg->newMessageFast(_PREHASH_RequestObjectPropertiesFamily);
  4823. msg->nextBlockFast(_PREHASH_AgentData);
  4824. msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
  4825. msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
  4826. msg->nextBlockFast(_PREHASH_ObjectData);
  4827. msg->addU32Fast(_PREHASH_RequestFlags, 0);
  4828. msg->addUUIDFast(_PREHASH_ObjectID, object_id);
  4829. msg->sendReliable(regionp->getHost());
  4830. LL_DEBUGS("Lua") << "Sent data request for object " << object_id
  4831. << LL_ENDL;
  4832. return true;
  4833. }
  4834. //static
  4835. void HBViewerAutomation::processObjectPropertiesFamily(LLMessageSystem* msg)
  4836. {
  4837. LL_TRACY_TIMER(TRC_LUA_PROCESS_OBJ_PROP);
  4838. if (!msg) return;
  4839. LLUUID object_id;
  4840. msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_ObjectID, object_id);
  4841. uuid_list_t::iterator it = sMuteObjectRequests.find(object_id);
  4842. bool for_mute = it != sMuteObjectRequests.end();
  4843. if (for_mute)
  4844. {
  4845. sMuteObjectRequests.erase(it);
  4846. }
  4847. it = sUnmuteObjectRequests.find(object_id);
  4848. bool for_unmute = it != sUnmuteObjectRequests.end();
  4849. if (for_unmute)
  4850. {
  4851. sUnmuteObjectRequests.erase(it);
  4852. }
  4853. bool for_object_info = false;
  4854. if (gAutomationp)
  4855. {
  4856. it = gAutomationp->mObjectInfoRequests.find(object_id);
  4857. if (it != gAutomationp->mObjectInfoRequests.end())
  4858. {
  4859. for_object_info = true;
  4860. gAutomationp->mObjectInfoRequests.erase(it);
  4861. }
  4862. }
  4863. if (!for_mute && !for_unmute && !for_object_info)
  4864. {
  4865. // Object data not requested by us.
  4866. return;
  4867. }
  4868. LLUUID owner_id, group_id;
  4869. msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_OwnerID, owner_id);
  4870. msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_GroupID, group_id);
  4871. std::string name, desc;
  4872. msg->getStringFast(_PREHASH_ObjectData, _PREHASH_Name, name);
  4873. msg->getStringFast(_PREHASH_ObjectData, _PREHASH_Description, desc);
  4874. // Process (un)mute first, in case we requested both one and object info
  4875. if (for_mute || for_unmute)
  4876. {
  4877. LLMute mute(object_id, name, LLMute::OBJECT);
  4878. if (for_mute)
  4879. {
  4880. LLMuteList::add(mute);
  4881. }
  4882. else
  4883. {
  4884. LLMuteList::remove(mute);
  4885. }
  4886. }
  4887. if (for_object_info)
  4888. {
  4889. gAutomationp->onObjectInfoReply(object_id, name, desc, owner_id,
  4890. group_id);
  4891. }
  4892. }
  4893. //static
  4894. int HBViewerAutomation::print(lua_State* state)
  4895. {
  4896. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  4897. HBViewerAutomation* self = findInstance(state);
  4898. if (!self) return 0;
  4899. S32 n = lua_gettop(state);
  4900. if (!n) return 0;
  4901. std::string value;
  4902. for (S32 i = 1; i <= n; ++i)
  4903. {
  4904. int type = lua_type(state, i);
  4905. switch (type)
  4906. {
  4907. case LUA_TNIL:
  4908. value = "nil";
  4909. break;
  4910. case LUA_TBOOLEAN:
  4911. value = lua_toboolean(state, i) ? "true" : "false";
  4912. break;
  4913. case LUA_TNUMBER:
  4914. value = llformat(LUA_NUMBER_FMT, lua_tonumber(state, i));
  4915. break;
  4916. case LUA_TSTRING:
  4917. value = lua_tostring(state, i);
  4918. break;
  4919. case LUA_TTABLE:
  4920. if (serializeTable(state, i, &value))
  4921. {
  4922. break;
  4923. }
  4924. // Else, fall through.
  4925. default:
  4926. value = lua_typename(state, type);
  4927. }
  4928. // NOTE: we need to delay chat printing until after login, since we
  4929. // otherwise could crash due to LLFloaterChat not yet being
  4930. // constructed.
  4931. if (self->mUsePrintBuffer || !LLStartUp::isLoggedIn())
  4932. {
  4933. if (!self->mPrintBuffer.empty())
  4934. {
  4935. #if LL_WINDOWS
  4936. self->mPrintBuffer += "\r\n";
  4937. #else
  4938. self->mPrintBuffer += '\n';
  4939. #endif
  4940. }
  4941. self->mPrintBuffer += value;
  4942. }
  4943. else if (!self->mUseConsoleOutput || !HBLuaConsole::print(value))
  4944. {
  4945. LLChat chat;
  4946. chat.mFromName = "Lua";
  4947. chat.mSourceType = CHAT_SOURCE_SYSTEM;
  4948. chat.mText = "Lua: " + value;
  4949. LLFloaterChat::addChat(chat, false, false);
  4950. }
  4951. }
  4952. lua_pop(state, n);
  4953. return 0;
  4954. }
  4955. //static
  4956. int HBViewerAutomation::isUUID(lua_State* state)
  4957. {
  4958. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  4959. if (!state) return 0; // Paranoia
  4960. S32 n = lua_gettop(state);
  4961. if (n != 1)
  4962. {
  4963. luaL_error(state, "%d arguments passed; expected 1.", n);
  4964. }
  4965. bool valid = false;
  4966. if (lua_type(state, 1) == LUA_TSTRING)
  4967. {
  4968. std::string param(luaL_checkstring(state, 1));
  4969. valid = LLUUID::validate(param);
  4970. }
  4971. lua_pop(state, 1);
  4972. lua_pushboolean(state, valid);
  4973. return 1;
  4974. }
  4975. //static
  4976. int HBViewerAutomation::isAvatar(lua_State* state)
  4977. {
  4978. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  4979. HBViewerAutomation* self = findInstance(state);
  4980. if (!self) return 0;
  4981. if (self->isThreaded())
  4982. {
  4983. HBAutomationThread* threadp = (HBAutomationThread*)self;
  4984. return threadp->callMainFunction("IsAvatar");
  4985. }
  4986. S32 n = lua_gettop(state);
  4987. if (n != 1)
  4988. {
  4989. luaL_error(state, "%d arguments passed; expected 1.", n);
  4990. }
  4991. LLUUID id(luaL_checkstring(state, 1), false);
  4992. lua_pop(state, 1);
  4993. bool is_avatar = false;
  4994. if (id.notNull())
  4995. {
  4996. is_avatar = gObjectList.findAvatar(id) != NULL;
  4997. }
  4998. lua_pushboolean(state, is_avatar);
  4999. return 1;
  5000. }
  5001. //static
  5002. int HBViewerAutomation::isObject(lua_State* state)
  5003. {
  5004. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  5005. HBViewerAutomation* self = findInstance(state);
  5006. if (!self) return 0;
  5007. if (self->isThreaded())
  5008. {
  5009. HBAutomationThread* threadp = (HBAutomationThread*)self;
  5010. return threadp->callMainFunction("IsObject");
  5011. }
  5012. S32 n = lua_gettop(state);
  5013. if (n != 1)
  5014. {
  5015. luaL_error(state, "%d arguments passed; expected 1.", n);
  5016. }
  5017. LLUUID id(luaL_checkstring(state, 1), false);
  5018. lua_pop(state, 1);
  5019. bool is_object = false;
  5020. if (id.notNull())
  5021. {
  5022. LLViewerObject* objectp = gObjectList.findObject(id);
  5023. is_object = objectp && !objectp->isAvatar();
  5024. }
  5025. lua_pushboolean(state, is_object);
  5026. return 1;
  5027. }
  5028. //static
  5029. int HBViewerAutomation::isAgentFriend(lua_State* state)
  5030. {
  5031. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  5032. HBViewerAutomation* self = findInstance(state);
  5033. if (!self) return 0;
  5034. if (self->isThreaded())
  5035. {
  5036. HBAutomationThread* threadp = (HBAutomationThread*)self;
  5037. return threadp->callMainFunction("IsAgentFriend");
  5038. }
  5039. S32 n = lua_gettop(state);
  5040. if (n != 1)
  5041. {
  5042. luaL_error(state, "%d arguments passed; expected 1.", n);
  5043. }
  5044. std::string param(luaL_checkstring(state, 1));
  5045. lua_pop(state, 1);
  5046. LLUUID id;
  5047. if (LLUUID::validate(param))
  5048. {
  5049. id.set(param);
  5050. }
  5051. bool is_friend = false;
  5052. bool is_online = false;
  5053. if (id.notNull())
  5054. {
  5055. is_friend = LLAvatarTracker::isAgentFriend(id);
  5056. is_online = is_friend && gAvatarTracker.isBuddyOnline(id);
  5057. }
  5058. else if (!param.empty())
  5059. {
  5060. // 'param' should contain the legacy name of the putative friend, with
  5061. // the "Display Name [Legacy Name]" format accepted as well.
  5062. size_t i = param.rfind(']');
  5063. if (i == param.size() - 1)
  5064. {
  5065. size_t j = param.rfind('[');
  5066. if (j != std::string::npos)
  5067. {
  5068. // This is indeed the "Display Name [Legacy Name]" format
  5069. param = param.substr(j + 1, i - j - 1);
  5070. }
  5071. }
  5072. // Eliminate the " Resident" last name if any.
  5073. i = param.find(" Resident");
  5074. if (i != std::string::npos)
  5075. {
  5076. param = param.substr(0, i);
  5077. }
  5078. // Collect all our friends in a map
  5079. LLCollectAllBuddies friends;
  5080. gAvatarTracker.applyFunctor(friends);
  5081. // Try and find a matching friend name (case-sensitive)
  5082. std::string name;
  5083. typedef LLCollectAllBuddies::buddy_map_t::const_iterator buddies_it;
  5084. for (buddies_it it = friends.mOnline.begin(),
  5085. end = friends.mOnline.end();
  5086. it != end; ++it)
  5087. {
  5088. name = it->first;
  5089. i = name.find(" Resident");
  5090. if (i != std::string::npos)
  5091. {
  5092. name = name.substr(0, i);
  5093. }
  5094. if (name == param)
  5095. {
  5096. is_friend = is_online = true;
  5097. break;
  5098. }
  5099. }
  5100. if (!is_friend)
  5101. {
  5102. for (buddies_it it = friends.mOffline.begin(),
  5103. end = friends.mOffline.end();
  5104. it != end; ++it)
  5105. {
  5106. name = it->first;
  5107. i = name.find(" Resident");
  5108. if (i != std::string::npos)
  5109. {
  5110. name = name.substr(0, i);
  5111. }
  5112. if (name == param)
  5113. {
  5114. is_friend = true;
  5115. break;
  5116. }
  5117. }
  5118. }
  5119. }
  5120. lua_pushboolean(state, is_friend);
  5121. lua_pushboolean(state, is_online);
  5122. return 2;
  5123. }
  5124. //static
  5125. int HBViewerAutomation::isAgentGroup(lua_State* state)
  5126. {
  5127. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  5128. HBViewerAutomation* self = findInstance(state);
  5129. if (!self) return 0;
  5130. if (self->isThreaded())
  5131. {
  5132. HBAutomationThread* threadp = (HBAutomationThread*)self;
  5133. return threadp->callMainFunction("IsAgentGroup");
  5134. }
  5135. S32 n = lua_gettop(state);
  5136. if (n != 1)
  5137. {
  5138. luaL_error(state, "%d arguments passed; expected 1.", n);
  5139. }
  5140. LLUUID id(luaL_checkstring(state, 1), false);
  5141. lua_pop(state, 1);
  5142. bool is_in_group = false;
  5143. if (id.notNull())
  5144. {
  5145. is_in_group = gAgent.isInGroup(id, true);
  5146. }
  5147. lua_pushboolean(state, is_in_group);
  5148. lua_pushboolean(state, is_in_group && gAgent.getGroupID() == id);
  5149. return 2;
  5150. }
  5151. //static
  5152. int HBViewerAutomation::getAvatarName(lua_State* state)
  5153. {
  5154. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  5155. HBViewerAutomation* self = findInstance(state);
  5156. if (!self) return 0;
  5157. if (self->isThreaded())
  5158. {
  5159. HBAutomationThread* threadp = (HBAutomationThread*)self;
  5160. return threadp->callMainFunction("GetAvatarName");
  5161. }
  5162. S32 n = lua_gettop(state);
  5163. if (n != 1 && n != 2)
  5164. {
  5165. luaL_error(state, "%d arguments passed; expected 1 or 2.", n);
  5166. }
  5167. LLUUID id(luaL_checkstring(state, 1), false);
  5168. S32 type = 0;
  5169. if (n > 1)
  5170. {
  5171. type = luaL_checknumber(state, 2);
  5172. }
  5173. lua_pop(state, n);
  5174. std::string name;
  5175. if (id.notNull() && gCacheNamep && !gCacheNamep->getFullName(id, name))
  5176. {
  5177. name.clear(); // Prevents "loading..."
  5178. }
  5179. if (type != 0 && !name.empty())
  5180. {
  5181. LLAvatarName avatar_name;
  5182. if (LLAvatarNameCache::get(id, &avatar_name))
  5183. {
  5184. if (type == 1)
  5185. {
  5186. name = avatar_name.mDisplayName;
  5187. }
  5188. else
  5189. {
  5190. name = avatar_name.getNames();
  5191. }
  5192. }
  5193. }
  5194. lua_pushstring(state, name.c_str());
  5195. return 1;
  5196. }
  5197. //static
  5198. int HBViewerAutomation::getGroupName(lua_State* state)
  5199. {
  5200. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  5201. HBViewerAutomation* self = findInstance(state);
  5202. if (!self) return 0;
  5203. if (self->isThreaded())
  5204. {
  5205. HBAutomationThread* threadp = (HBAutomationThread*)self;
  5206. return threadp->callMainFunction("GetGroupName");
  5207. }
  5208. S32 n = lua_gettop(state);
  5209. if (n != 1)
  5210. {
  5211. luaL_error(state, "%d arguments passed; expected 1.", n);
  5212. }
  5213. LLUUID id(luaL_checkstring(state, 1), false);
  5214. lua_pop(state, 1);
  5215. std::string name;
  5216. if (id.notNull() && gCacheNamep && !gCacheNamep->getGroupName(id, name))
  5217. {
  5218. name.clear(); // Prevents "loading..."
  5219. }
  5220. lua_pushstring(state, name.c_str());
  5221. return 1;
  5222. }
  5223. //static
  5224. int HBViewerAutomation::getAgentFriends(lua_State* state)
  5225. {
  5226. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  5227. HBViewerAutomation* self = findInstance(state);
  5228. if (!self) return 0;
  5229. if (self->isThreaded())
  5230. {
  5231. HBAutomationThread* threadp = (HBAutomationThread*)self;
  5232. return threadp->callMainFunction("GetAgentFriends");
  5233. }
  5234. S32 n = lua_gettop(state);
  5235. if (n > 1)
  5236. {
  5237. luaL_error(state, "%d arguments passed; expected 0 or 1.", n);
  5238. }
  5239. S32 type = 0; // Legacy names by default
  5240. if (n)
  5241. {
  5242. type = llclamp(luaL_checknumber(state, 1), -1, 2);
  5243. lua_pop(state, 1);
  5244. }
  5245. if (type > 0 && !LLAvatarNameCache::useDisplayNames())
  5246. {
  5247. llwarns_once << "Display names not available or disabled; falling back to legacy names."
  5248. << llendl;
  5249. type = 0;
  5250. }
  5251. if (type == -1) // Names as listed in the Friends floater
  5252. {
  5253. if (LLAvatarName::sLegacyNamesForFriends)
  5254. {
  5255. type = 0;
  5256. }
  5257. else
  5258. {
  5259. type = LLAvatarNameCache::useDisplayNames();
  5260. }
  5261. }
  5262. lua_newtable(state);
  5263. // Get all buddies we know about
  5264. std::string fullname;
  5265. LLAvatarName avatar_name;
  5266. LLAvatarTracker::buddy_map_t all_buddies;
  5267. gAvatarTracker.copyBuddyList(all_buddies);
  5268. for (LLAvatarTracker::buddy_map_t::const_iterator it = all_buddies.begin(),
  5269. end = all_buddies.end();
  5270. it != end; ++it)
  5271. {
  5272. const LLUUID& id = it->first;
  5273. fullname.clear();
  5274. lua_pushstring(state, id.asString().c_str());
  5275. bool has_name = gCacheNamep &&
  5276. gCacheNamep->getFullName(id, fullname);
  5277. if (has_name && type)
  5278. {
  5279. if (LLAvatarNameCache::get(id, &avatar_name))
  5280. {
  5281. if (type == 2)
  5282. {
  5283. fullname = avatar_name.mDisplayName;
  5284. }
  5285. else
  5286. {
  5287. fullname = avatar_name.getNames();
  5288. }
  5289. }
  5290. }
  5291. lua_pushstring(state, fullname.c_str());
  5292. lua_rawset(state, -3);
  5293. }
  5294. return 1;
  5295. }
  5296. //static
  5297. int HBViewerAutomation::getAgentGroups(lua_State* state)
  5298. {
  5299. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  5300. HBViewerAutomation* self = findInstance(state);
  5301. if (!self) return 0;
  5302. if (self->isThreaded())
  5303. {
  5304. HBAutomationThread* threadp = (HBAutomationThread*)self;
  5305. return threadp->callMainFunction("GetAgentGroups");
  5306. }
  5307. S32 n = lua_gettop(state);
  5308. if (n)
  5309. {
  5310. luaL_error(state, "%d arguments passed; expected 0.", n);
  5311. }
  5312. lua_newtable(state);
  5313. for (U32 i = 0, count = gAgent.mGroups.size(); i < count; ++i)
  5314. {
  5315. const LLGroupData& group_data = gAgent.mGroups[i];
  5316. lua_pushstring(state, group_data.mID.asString().c_str());
  5317. lua_pushstring(state, group_data.mName.c_str());
  5318. lua_rawset(state, -3);
  5319. }
  5320. return 1;
  5321. }
  5322. //static
  5323. int HBViewerAutomation::isAdmin(lua_State* state)
  5324. {
  5325. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  5326. HBViewerAutomation* self = findInstance(state);
  5327. if (!self) return 0;
  5328. if (self->isThreaded())
  5329. {
  5330. HBAutomationThread* threadp = (HBAutomationThread*)self;
  5331. return threadp->callMainFunction("IsAdmin");
  5332. }
  5333. S32 n = lua_gettop(state);
  5334. if (n != 1)
  5335. {
  5336. luaL_error(state, "%d arguments passed; expected 1.", n);
  5337. }
  5338. std::string param(luaL_checkstring(state, 1));
  5339. lua_pop(state, 1);
  5340. std::string name;
  5341. if (LLUUID::validate(param))
  5342. {
  5343. LLUUID av_id(param);
  5344. if (av_id.notNull() && gCacheNamep &&
  5345. gCacheNamep->getName(av_id, name, param))
  5346. {
  5347. name += " " + param;
  5348. }
  5349. else
  5350. {
  5351. name.clear();
  5352. }
  5353. }
  5354. else
  5355. {
  5356. name = param;
  5357. }
  5358. if (name.empty())
  5359. {
  5360. lua_pushnil(state);
  5361. }
  5362. else
  5363. {
  5364. lua_pushboolean(state, LLMuteList::isLinden(name));
  5365. }
  5366. return 1;
  5367. }
  5368. //static
  5369. int HBViewerAutomation::getRadarList(lua_State* state)
  5370. {
  5371. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  5372. HBViewerAutomation* self = findInstance(state);
  5373. if (!self) return 0;
  5374. if (self->isThreaded())
  5375. {
  5376. HBAutomationThread* threadp = (HBAutomationThread*)self;
  5377. return threadp->callMainFunction("GetRadarList");
  5378. }
  5379. S32 n = lua_gettop(state);
  5380. if (n > 1)
  5381. {
  5382. luaL_error(state, "%d arguments passed; expected 0 or 1.", n);
  5383. }
  5384. S32 type = 0; // Legacy names by default
  5385. if (n)
  5386. {
  5387. type = llclamp(luaL_checknumber(state, 1), -1, 2);
  5388. lua_pop(state, 1);
  5389. }
  5390. if (type > 0 && !LLAvatarNameCache::useDisplayNames())
  5391. {
  5392. llwarns_once << "Display names not available or disabled; falling back to legacy names."
  5393. << llendl;
  5394. type = 0;
  5395. }
  5396. HBFloaterRadar* avlistp = HBFloaterRadar::findInstance();
  5397. if (!avlistp)
  5398. {
  5399. lua_pushnil(state);
  5400. return 1;
  5401. }
  5402. lua_newtable(state);
  5403. std::string fullname;
  5404. LLAvatarName avatar_name;
  5405. const HBFloaterRadar::avatar_list_t& list = avlistp->getAvatarList();
  5406. for (HBFloaterRadar::avatar_list_t::const_iterator it = list.begin(),
  5407. end = list.end();
  5408. it != end; ++it)
  5409. {
  5410. const HBRadarListEntry& entry = it->second;
  5411. if (!entry.isDead())
  5412. {
  5413. const LLUUID& id = it->first;
  5414. lua_pushstring(state, id.asString().c_str());
  5415. if (type == -1)
  5416. {
  5417. fullname = entry.getListedName();
  5418. }
  5419. else if (type && LLAvatarNameCache::get(id, &avatar_name))
  5420. {
  5421. if (type == 2)
  5422. {
  5423. fullname = avatar_name.mDisplayName;
  5424. }
  5425. else
  5426. {
  5427. fullname = avatar_name.getNames();
  5428. }
  5429. }
  5430. else // type == 0 and fallback path
  5431. {
  5432. fullname = entry.getLegacyName();
  5433. }
  5434. lua_pushstring(state, fullname.c_str());
  5435. lua_rawset(state, -3);
  5436. }
  5437. }
  5438. return 1;
  5439. }
  5440. //static
  5441. int HBViewerAutomation::getRadarData(lua_State* state)
  5442. {
  5443. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  5444. HBViewerAutomation* self = findInstance(state);
  5445. if (!self) return 0;
  5446. if (self->isThreaded())
  5447. {
  5448. HBAutomationThread* threadp = (HBAutomationThread*)self;
  5449. return threadp->callMainFunction("GetRadarData");
  5450. }
  5451. S32 n = lua_gettop(state);
  5452. if (n != 1)
  5453. {
  5454. luaL_error(state, "%d arguments passed; expected 1.", n);
  5455. }
  5456. LLUUID id(luaL_checkstring(state, 1), false);
  5457. lua_pop(state, 1);
  5458. HBRadarListEntry* entryp = NULL;
  5459. if (id.notNull())
  5460. {
  5461. HBFloaterRadar* avlistp = HBFloaterRadar::findInstance();
  5462. if (avlistp)
  5463. {
  5464. entryp = avlistp->getAvatarEntry(id);
  5465. }
  5466. }
  5467. if (!entryp || entryp->isDead())
  5468. {
  5469. lua_pushnil(state);
  5470. return 1;
  5471. }
  5472. lua_newtable(state);
  5473. lua_pushliteral(state, "id");
  5474. lua_pushstring(state, id.asString().c_str());
  5475. lua_rawset(state, -3);
  5476. lua_pushliteral(state, "name");
  5477. lua_pushstring(state, entryp->getLegacyName().c_str());
  5478. lua_rawset(state, -3);
  5479. lua_pushliteral(state, "display_name");
  5480. lua_pushstring(state, entryp->getListedName().c_str());
  5481. lua_rawset(state, -3);
  5482. lua_pushliteral(state, "name_color");
  5483. const LLColor4& name_color = entryp->getColor();
  5484. lua_pushstring(state, llformat("%f, %f, %f",
  5485. name_color.mV[0],
  5486. name_color.mV[1],
  5487. name_color.mV[2]).c_str());
  5488. lua_rawset(state, -3);
  5489. lua_pushliteral(state, "tooltip");
  5490. lua_pushstring(state, entryp->getToolTip().c_str());
  5491. lua_rawset(state, -3);
  5492. const LLVector3d& global_pos = entryp->getPosition();
  5493. lua_pushliteral(state, "global_x");
  5494. lua_pushnumber(state, global_pos.mdV[VX]);
  5495. lua_rawset(state, -3);
  5496. lua_pushliteral(state, "global_y");
  5497. lua_pushnumber(state, global_pos.mdV[VY]);
  5498. lua_rawset(state, -3);
  5499. lua_pushliteral(state, "altitude");
  5500. lua_pushnumber(state, global_pos.mdV[VZ]);
  5501. lua_rawset(state, -3);
  5502. lua_pushliteral(state, "friend");
  5503. lua_pushboolean(state, entryp->isFriend());
  5504. lua_rawset(state, -3);
  5505. lua_pushliteral(state, "muted");
  5506. lua_pushboolean(state, entryp->isMuted());
  5507. lua_rawset(state, -3);
  5508. lua_pushliteral(state, "derendered");
  5509. lua_pushboolean(state, entryp->isDerendered());
  5510. lua_rawset(state, -3);
  5511. lua_pushliteral(state, "marked");
  5512. lua_pushboolean(state, entryp->isMarked());
  5513. lua_rawset(state, -3);
  5514. lua_pushliteral(state, "mark_char");
  5515. lua_pushstring(state, entryp->getMarkChar().c_str());
  5516. lua_rawset(state, -3);
  5517. lua_pushliteral(state, "mark_color");
  5518. const LLColor4& mark_color = entryp->getMarkColor();
  5519. lua_pushstring(state, llformat("%f, %f, %f",
  5520. mark_color.mV[0],
  5521. mark_color.mV[1],
  5522. mark_color.mV[2]).c_str());
  5523. lua_rawset(state, -3);
  5524. lua_pushliteral(state, "focused");
  5525. lua_pushboolean(state, entryp->isFocused());
  5526. lua_rawset(state, -3);
  5527. lua_pushliteral(state, "drawn");
  5528. lua_pushboolean(state, entryp->isDrawn());
  5529. lua_rawset(state, -3);
  5530. lua_pushliteral(state, "in_sim");
  5531. lua_pushboolean(state, entryp->isInSim());
  5532. lua_rawset(state, -3);
  5533. lua_pushliteral(state, "entry_age");
  5534. lua_pushnumber(state, entryp->getEntryAgeSeconds());
  5535. lua_rawset(state, -3);
  5536. return 1;
  5537. }
  5538. //static
  5539. int HBViewerAutomation::setRadarTracking(lua_State* state)
  5540. {
  5541. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  5542. HBViewerAutomation* self = findInstance(state);
  5543. if (!self) return 0;
  5544. if (self->isThreaded())
  5545. {
  5546. HBAutomationThread* threadp = (HBAutomationThread*)self;
  5547. return threadp->callMainFunction("SetRadarTracking");
  5548. }
  5549. S32 n = lua_gettop(state);
  5550. if (n != 1 && n != 2)
  5551. {
  5552. luaL_error(state, "%d arguments passed; expected 1 or 2.", n);
  5553. }
  5554. LLUUID id(luaL_checkstring(state, 1), false);
  5555. bool force = n >= 2 && lua_toboolean(state, 2);
  5556. lua_pop(state, n);
  5557. HBIgnoreCallback lock_on_radar_track(E_ONRADARTRACK);
  5558. bool success = false;
  5559. HBFloaterRadar* avlistp = HBFloaterRadar::findInstance();
  5560. if (id.isNull())
  5561. {
  5562. if (avlistp)
  5563. {
  5564. avlistp->stopTracker();
  5565. }
  5566. success = true;
  5567. }
  5568. else if (avlistp)
  5569. {
  5570. success = avlistp->startTracker(id);
  5571. }
  5572. else if (force)
  5573. {
  5574. if (!gSavedSettings.getBool("RadarKeepOpen"))
  5575. {
  5576. llinfos << "Enabling Radar background tracking" << llendl;
  5577. gSavedSettings.setBool("RadarKeepOpen", true);
  5578. }
  5579. avlistp = HBFloaterRadar::getInstance();
  5580. if (avlistp)
  5581. {
  5582. success = avlistp->startTracker(id);
  5583. HBFloaterRadar::hideInstance();
  5584. }
  5585. }
  5586. lua_pushboolean(state, success);
  5587. return 1;
  5588. }
  5589. //static
  5590. int HBViewerAutomation::setRadarToolTip(lua_State* state)
  5591. {
  5592. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  5593. HBViewerAutomation* self = findInstance(state);
  5594. if (!self) return 0;
  5595. if (self->isThreaded())
  5596. {
  5597. HBAutomationThread* threadp = (HBAutomationThread*)self;
  5598. return threadp->callMainFunction("SetRadarToolTip");
  5599. }
  5600. S32 n = lua_gettop(state);
  5601. if (n != 1 && n != 2)
  5602. {
  5603. luaL_error(state, "%d arguments passed; expected 1 or 2.", n);
  5604. }
  5605. LLUUID id(luaL_checkstring(state, 1), false);
  5606. std::string tooltip;
  5607. if (n > 1)
  5608. {
  5609. tooltip = luaL_checkstring(state, 2);
  5610. }
  5611. lua_pop(state, n);
  5612. HBRadarListEntry* entryp = NULL;
  5613. if (id.notNull())
  5614. {
  5615. HBFloaterRadar* avlistp = HBFloaterRadar::findInstance();
  5616. if (avlistp)
  5617. {
  5618. entryp = avlistp->getAvatarEntry(id);
  5619. }
  5620. }
  5621. bool success = entryp && !entryp->isDead();
  5622. if (success)
  5623. {
  5624. entryp->setToolTip(tooltip);
  5625. }
  5626. lua_pushboolean(state, success);
  5627. return 1;
  5628. }
  5629. //static
  5630. int HBViewerAutomation::setRadarMarkChar(lua_State* state)
  5631. {
  5632. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  5633. HBViewerAutomation* self = findInstance(state);
  5634. if (!self) return 0;
  5635. if (self->isThreaded())
  5636. {
  5637. HBAutomationThread* threadp = (HBAutomationThread*)self;
  5638. return threadp->callMainFunction("SetRadarMarkChar");
  5639. }
  5640. S32 n = lua_gettop(state);
  5641. if (n != 1 && n != 2)
  5642. {
  5643. luaL_error(state, "%d arguments passed; expected 1 or 2.", n);
  5644. }
  5645. LLUUID id(luaL_checkstring(state, 1), false);
  5646. std::string chr;
  5647. if (n > 1)
  5648. {
  5649. chr = luaL_checkstring(state, 2);
  5650. }
  5651. lua_pop(state, n);
  5652. HBRadarListEntry* entryp = NULL;
  5653. if (id.notNull())
  5654. {
  5655. HBFloaterRadar* avlistp = HBFloaterRadar::findInstance();
  5656. if (avlistp)
  5657. {
  5658. entryp = avlistp->getAvatarEntry(id);
  5659. }
  5660. }
  5661. bool success = entryp && !entryp->isDead();
  5662. if (success)
  5663. {
  5664. entryp->setMarkChar(chr);
  5665. }
  5666. lua_pushboolean(state, success);
  5667. return 1;
  5668. }
  5669. //static
  5670. int HBViewerAutomation::setRadarMarkColor(lua_State* state)
  5671. {
  5672. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  5673. HBViewerAutomation* self = findInstance(state);
  5674. if (!self) return 0;
  5675. if (self->isThreaded())
  5676. {
  5677. HBAutomationThread* threadp = (HBAutomationThread*)self;
  5678. return threadp->callMainFunction("SetRadarMarkColor");
  5679. }
  5680. S32 n = lua_gettop(state);
  5681. if (n != 1 && n != 2)
  5682. {
  5683. luaL_error(state, "%d arguments passed; expected 1 or 2.", n);
  5684. }
  5685. LLUUID id(luaL_checkstring(state, 1), false);
  5686. std::string color_str;
  5687. if (n > 1)
  5688. {
  5689. color_str = luaL_checkstring(state, 2);
  5690. }
  5691. lua_pop(state, n);
  5692. LLColor4 color;
  5693. if (color_str.empty())
  5694. {
  5695. color = gColors.getColor("RadarMarkColor");
  5696. }
  5697. else if (!LLColor4::parseColor(color_str, &color))
  5698. {
  5699. luaL_error(state, "invalid color: %s", color_str.c_str());
  5700. }
  5701. else
  5702. {
  5703. color.mV[3] = 1.f; // Make sure we use an opaque color...
  5704. }
  5705. HBRadarListEntry* entryp = NULL;
  5706. if (id.notNull())
  5707. {
  5708. HBFloaterRadar* avlistp = HBFloaterRadar::findInstance();
  5709. if (avlistp)
  5710. {
  5711. entryp = avlistp->getAvatarEntry(id);
  5712. }
  5713. }
  5714. bool success = entryp && !entryp->isDead();
  5715. if (success)
  5716. {
  5717. entryp->setMarkColor(color);
  5718. }
  5719. lua_pushboolean(state, success);
  5720. return 1;
  5721. }
  5722. //static
  5723. int HBViewerAutomation::setRadarNameColor(lua_State* state)
  5724. {
  5725. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  5726. HBViewerAutomation* self = findInstance(state);
  5727. if (!self) return 0;
  5728. if (self->isThreaded())
  5729. {
  5730. HBAutomationThread* threadp = (HBAutomationThread*)self;
  5731. return threadp->callMainFunction("SetRadarNameColor");
  5732. }
  5733. S32 n = lua_gettop(state);
  5734. if (n != 1 && n != 2)
  5735. {
  5736. luaL_error(state, "%d arguments passed; expected 1 or 2.", n);
  5737. }
  5738. LLUUID id(luaL_checkstring(state, 1), false);
  5739. std::string color_str;
  5740. if (n > 1)
  5741. {
  5742. color_str = luaL_checkstring(state, 2);
  5743. }
  5744. lua_pop(state, n);
  5745. bool success = false;
  5746. LLColor4 color;
  5747. if (color_str.empty())
  5748. {
  5749. color = LLColor4::black;
  5750. }
  5751. else if (!LLColor4::parseColor(color_str, &color))
  5752. {
  5753. luaL_error(state, "invalid color: %s", color_str.c_str());
  5754. }
  5755. else
  5756. {
  5757. color.mV[3] = 1.f; // Make sure we use an opaque color...
  5758. }
  5759. if (id != gAgentID && id.notNull())
  5760. {
  5761. LLVOAvatar* avatarp = gObjectList.findAvatar(id);
  5762. success = avatarp != NULL;
  5763. if (success)
  5764. {
  5765. avatarp->setRadarColor(color);
  5766. success = HBFloaterRadar::setAvatarNameColor(id, color);
  5767. }
  5768. }
  5769. lua_pushboolean(state, success);
  5770. return 1;
  5771. }
  5772. //static
  5773. int HBViewerAutomation::setAvatarMinimapColor(lua_State* state)
  5774. {
  5775. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  5776. HBViewerAutomation* self = findInstance(state);
  5777. if (!self) return 0;
  5778. if (self->isThreaded())
  5779. {
  5780. HBAutomationThread* threadp = (HBAutomationThread*)self;
  5781. return threadp->callMainFunction("SetAvatarMinimapColor");
  5782. }
  5783. S32 n = lua_gettop(state);
  5784. if (n != 1 && n != 2)
  5785. {
  5786. luaL_error(state, "%d arguments passed; expected 1 or 2.", n);
  5787. }
  5788. LLUUID id(luaL_checkstring(state, 1), false);
  5789. std::string color_str;
  5790. if (n > 1)
  5791. {
  5792. color_str = luaL_checkstring(state, 2);
  5793. }
  5794. lua_pop(state, n);
  5795. bool success = true;
  5796. LLColor4 color;
  5797. if (color_str.empty())
  5798. {
  5799. static LLCachedControl<LLColor4U> map_avatar(gColors, "MapAvatar");
  5800. static LLCachedControl<LLColor4U> map_friend(gColors, "MapFriend");
  5801. bool is_friend = LLAvatarTracker::isAgentFriend(id);
  5802. color = LLColor4(is_friend ? map_friend : map_avatar);
  5803. }
  5804. else if (!LLColor4::parseColor(color_str, &color))
  5805. {
  5806. luaL_error(state, "invalid color: %s", color_str.c_str());
  5807. }
  5808. if (id == gAgentID)
  5809. {
  5810. success = false;
  5811. }
  5812. else
  5813. {
  5814. LLVOAvatar* avatarp = gObjectList.findAvatar(id);
  5815. success = avatarp != NULL;
  5816. if (success)
  5817. {
  5818. avatarp->setMinimapColor(color);
  5819. }
  5820. }
  5821. lua_pushboolean(state, success);
  5822. return 1;
  5823. }
  5824. //static
  5825. int HBViewerAutomation::setAvatarNameTagColor(lua_State* state)
  5826. {
  5827. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  5828. HBViewerAutomation* self = findInstance(state);
  5829. if (!self) return 0;
  5830. if (self->isThreaded())
  5831. {
  5832. HBAutomationThread* threadp = (HBAutomationThread*)self;
  5833. return threadp->callMainFunction("SetAvatarNameTagColor");
  5834. }
  5835. S32 n = lua_gettop(state);
  5836. if (n != 1 && n != 2)
  5837. {
  5838. luaL_error(state, "%d arguments passed; expected 1 or 2.", n);
  5839. }
  5840. LLUUID id(luaL_checkstring(state, 1), false);
  5841. std::string color_str;
  5842. if (n > 1)
  5843. {
  5844. color_str = luaL_checkstring(state, 2);
  5845. }
  5846. lua_pop(state, n);
  5847. bool success = true;
  5848. LLColor4 color;
  5849. if (color_str.empty())
  5850. {
  5851. static LLCachedControl<LLColor4U> tag_color(gColors,
  5852. "AvatarNameColor");
  5853. color = LLColor4(tag_color);
  5854. }
  5855. else if (!LLColor4::parseColor(color_str, &color))
  5856. {
  5857. luaL_error(state, "invalid color: %s", color_str.c_str());
  5858. }
  5859. if (id == gAgentID)
  5860. {
  5861. success = isAgentAvatarValid();
  5862. if (success)
  5863. {
  5864. gAgentAvatarp->setNameTagColor(color);
  5865. }
  5866. }
  5867. else
  5868. {
  5869. LLVOAvatar* avatarp = gObjectList.findAvatar(id);
  5870. success = avatarp != NULL;
  5871. if (success)
  5872. {
  5873. avatarp->setNameTagColor(color);
  5874. }
  5875. }
  5876. lua_pushboolean(state, success);
  5877. return 1;
  5878. }
  5879. //static
  5880. void HBViewerAutomation::addToAgentPosHistory(const LLVector3d& global_pos)
  5881. {
  5882. static LLCachedControl<U32> max_history(gSavedSettings,
  5883. "LuaMaxAgentPosHistorySize");
  5884. while (sPositionsHistory.size() >= (size_t)max_history)
  5885. {
  5886. sPositionsHistory.pop_front();
  5887. }
  5888. if (max_history > 0)
  5889. {
  5890. sPositionsHistory.emplace_back(global_pos);
  5891. }
  5892. }
  5893. //static
  5894. int HBViewerAutomation::getAgentPosHistory(lua_State* state)
  5895. {
  5896. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  5897. HBViewerAutomation* self = findInstance(state);
  5898. if (!self) return 0;
  5899. if (self->isThreaded())
  5900. {
  5901. HBAutomationThread* threadp = (HBAutomationThread*)self;
  5902. return threadp->callMainFunction("GetAgentPosHistory");
  5903. }
  5904. S32 n = lua_gettop(state);
  5905. if (n)
  5906. {
  5907. luaL_error(state, "%d arguments passed; expected 0.", n);
  5908. }
  5909. if (sPositionsHistory.empty())
  5910. {
  5911. lua_pushnil(state);
  5912. return 1;
  5913. }
  5914. lua_newtable(state);
  5915. S32 i = 1;
  5916. std::string vecstr;
  5917. // Place the positions in reverse order in the Lua table (i.e. last known
  5918. // position will be first in the table).
  5919. for (pos_history_t::reverse_iterator it = sPositionsHistory.rbegin(),
  5920. end = sPositionsHistory.rend();
  5921. it != end; ++it)
  5922. {
  5923. vecstr = llformat("%lf %lf %lf", it->mdV[0], it->mdV[1], it->mdV[2]);
  5924. lua_pushnumber(state, i++);
  5925. lua_pushstring(state, vecstr.c_str());
  5926. lua_rawset(state, -3);
  5927. }
  5928. return 1;
  5929. }
  5930. //static
  5931. int HBViewerAutomation::getAgentInfo(lua_State* state)
  5932. {
  5933. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  5934. HBViewerAutomation* self = findInstance(state);
  5935. if (!self) return 0;
  5936. if (self->isThreaded())
  5937. {
  5938. HBAutomationThread* threadp = (HBAutomationThread*)self;
  5939. return threadp->callMainFunction("GetAgentInfo");
  5940. }
  5941. S32 n = lua_gettop(state);
  5942. if (n)
  5943. {
  5944. luaL_error(state, "%d arguments passed; expected 0.", n);
  5945. }
  5946. lua_newtable(state);
  5947. std::string temp;
  5948. gAgent.getName(temp);
  5949. lua_pushliteral(state, "name");
  5950. lua_pushstring(state, temp.c_str());
  5951. lua_rawset(state, -3);
  5952. if (LLStartUp::isLoggedIn() && isAgentAvatarValid())
  5953. {
  5954. lua_pushliteral(state, "id");
  5955. lua_pushstring(state, gAgentID.asString().c_str());
  5956. lua_rawset(state, -3);
  5957. LLAvatarName avatar_name;
  5958. if (LLAvatarNameCache::get(gAgentID, &avatar_name))
  5959. {
  5960. lua_pushliteral(state, "display_name");
  5961. lua_pushstring(state, avatar_name.mDisplayName.c_str());
  5962. lua_rawset(state, -3);
  5963. }
  5964. temp = "unknown";
  5965. if (gAgent.isTeen())
  5966. {
  5967. temp = "teen";
  5968. }
  5969. else if (gAgent.isAdult())
  5970. {
  5971. temp = "adult";
  5972. }
  5973. else if (gAgent.isMature())
  5974. {
  5975. temp = "mature";
  5976. }
  5977. lua_pushliteral(state, "maturity");
  5978. lua_pushstring(state, temp.c_str());
  5979. lua_rawset(state, -3);
  5980. lua_pushliteral(state, "active_group_id");
  5981. lua_pushstring(state, gAgent.getGroupID().asString().c_str());
  5982. lua_rawset(state, -3);
  5983. lua_pushliteral(state, "camera_mode");
  5984. lua_pushinteger(state, gAgent.getCameraMode());
  5985. lua_rawset(state, -3);
  5986. lua_pushliteral(state, "control_flags");
  5987. lua_pushinteger(state, gAgent.getControlFlags());
  5988. lua_rawset(state, -3);
  5989. lua_pushliteral(state, "occupation");
  5990. S32 occupation = 0;
  5991. if (gAgent.getAFK())
  5992. {
  5993. occupation = 1;
  5994. }
  5995. else if (gAgent.getBusy())
  5996. {
  5997. occupation = 2;
  5998. }
  5999. else if (gAgent.getAutoReply())
  6000. {
  6001. occupation = 3;
  6002. }
  6003. lua_pushinteger(state, occupation);
  6004. lua_rawset(state, -3);
  6005. lua_pushliteral(state, "flying");
  6006. lua_pushboolean(state, gAgent.getFlying());
  6007. lua_rawset(state, -3);
  6008. lua_pushliteral(state, "sitting");
  6009. lua_pushboolean(state, gAgentAvatarp->mIsSitting);
  6010. lua_rawset(state, -3);
  6011. lua_pushliteral(state, "sitting_on_ground");
  6012. lua_pushboolean(state, gAgent.sittingOnGround());
  6013. lua_rawset(state, -3);
  6014. lua_pushliteral(state, "baked");
  6015. lua_pushboolean(state, gAppearanceMgr.isAvatarFullyBaked());
  6016. lua_rawset(state, -3);
  6017. lua_pushliteral(state, "can_rebake_region");
  6018. lua_pushboolean(state,
  6019. gOverlayBarp && gOverlayBarp->canRebakeRegion());
  6020. lua_rawset(state, -3);
  6021. //MK
  6022. lua_pushliteral(state, "rlv");
  6023. lua_pushboolean(state, gRLenabled);
  6024. lua_rawset(state, -3);
  6025. if (gRLenabled)
  6026. {
  6027. std::string restrictions = ",";
  6028. rl_map_it_t it = gRLInterface.mSpecialObjectBehaviours.begin();
  6029. while (it != gRLInterface.mSpecialObjectBehaviours.end())
  6030. {
  6031. temp = it++->second + ",";
  6032. if (restrictions.find("," + temp) == std::string::npos)
  6033. {
  6034. restrictions += temp;
  6035. }
  6036. }
  6037. if (restrictions != ",")
  6038. {
  6039. restrictions = restrictions.substr(1, restrictions.size() - 2);
  6040. }
  6041. else
  6042. {
  6043. restrictions.clear();
  6044. }
  6045. lua_pushliteral(state, "restrictions");
  6046. lua_pushstring(state, restrictions.c_str());
  6047. lua_rawset(state, -3);
  6048. }
  6049. //mk
  6050. LLEconomy* economyp = LLEconomy::getInstance();
  6051. lua_pushliteral(state, "max_upload_cost");
  6052. lua_pushinteger(state, economyp->getPriceUpload());
  6053. lua_rawset(state, -3);
  6054. lua_pushliteral(state, "animation_upload_cost");
  6055. lua_pushinteger(state, economyp->getAnimationUploadCost());
  6056. lua_rawset(state, -3);
  6057. lua_pushliteral(state, "sound_upload_cost");
  6058. lua_pushinteger(state, economyp->getSoundUploadCost());
  6059. lua_rawset(state, -3);
  6060. lua_pushliteral(state, "texture_upload_cost");
  6061. lua_pushinteger(state, economyp->getTextureUploadCost());
  6062. lua_rawset(state, -3);
  6063. lua_pushliteral(state, "create_group_cost");
  6064. lua_pushinteger(state, economyp->getCreateGroupCost());
  6065. lua_rawset(state, -3);
  6066. lua_pushliteral(state, "picks_limit");
  6067. lua_pushinteger(state, economyp->getPicksLimit());
  6068. lua_rawset(state, -3);
  6069. lua_pushliteral(state, "group_membership_limit");
  6070. lua_pushinteger(state, gMaxAgentGroups);
  6071. lua_rawset(state, -3);
  6072. lua_pushliteral(state, "attachment_limit");
  6073. lua_pushinteger(state, gMaxSelfAttachments);
  6074. lua_rawset(state, -3);
  6075. lua_pushliteral(state, "animated_object_limit");
  6076. lua_pushinteger(state,
  6077. gAgentAvatarp->getMaxAnimatedObjectAttachments());
  6078. lua_rawset(state, -3);
  6079. }
  6080. return 1;
  6081. }
  6082. //static
  6083. int HBViewerAutomation::setAgentOccupation(lua_State* state)
  6084. {
  6085. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  6086. HBViewerAutomation* self = findInstance(state);
  6087. if (!self) return 0;
  6088. if (self->isThreaded())
  6089. {
  6090. HBAutomationThread* threadp = (HBAutomationThread*)self;
  6091. return threadp->callMainFunction("SetAgentOccupation");
  6092. }
  6093. S32 n = lua_gettop(state);
  6094. if (n != 1)
  6095. {
  6096. luaL_error(state, "%d arguments passed; expected 1.", n);
  6097. }
  6098. S32 type = luaL_checknumber(state, 1);
  6099. lua_pop(state, 1);
  6100. HBIgnoreCallback lock_on_occupation(E_ONAGENTOCCUPATIONCHANGE);
  6101. bool success = true;
  6102. switch (type)
  6103. {
  6104. case 0:
  6105. gAgent.clearAutoReply();
  6106. gAgent.clearBusy();
  6107. gAgent.clearAFK();
  6108. break;
  6109. case 1:
  6110. gAgent.setAFK();
  6111. break;
  6112. case 2:
  6113. gAgent.setBusy();
  6114. break;
  6115. case 3:
  6116. gAgent.setAutoReply();
  6117. break;
  6118. default:
  6119. success = false;
  6120. }
  6121. lua_pushboolean(state, success);
  6122. return 1;
  6123. }
  6124. //static
  6125. int HBViewerAutomation::getAgentGroupData(lua_State* state)
  6126. {
  6127. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  6128. HBViewerAutomation* self = findInstance(state);
  6129. if (!self) return 0;
  6130. if (self->isThreaded())
  6131. {
  6132. HBAutomationThread* threadp = (HBAutomationThread*)self;
  6133. return threadp->callMainFunction("GetAgentGroupData");
  6134. }
  6135. S32 n = lua_gettop(state);
  6136. if (n > 1)
  6137. {
  6138. luaL_error(state, "%d arguments passed; expected 0 or 1.", n);
  6139. }
  6140. const LLUUID& current_group_id = gAgent.getGroupID();
  6141. std::string group_name;
  6142. if (n > 0)
  6143. {
  6144. group_name.assign(luaL_checkstring(state, 1));
  6145. lua_pop(state, 1);
  6146. }
  6147. else
  6148. {
  6149. LLGroupData grp_data;
  6150. if (gAgent.getGroupData(current_group_id, grp_data))
  6151. {
  6152. group_name = grp_data.mName;
  6153. }
  6154. }
  6155. if (group_name.empty())
  6156. {
  6157. group_name = "none";
  6158. }
  6159. LL_DEBUGS("Lua") << "Searching group data for group: " << group_name
  6160. << LL_ENDL;
  6161. lua_newtable(state);
  6162. // The first time this method is called, we scan the whole agent groups
  6163. // list, even after we found the right group, so to ensure that data for
  6164. // all groups will have been loaded via gGroupMgr.fetchGroupMissingData().
  6165. static bool scanned_once = false;
  6166. U64 powers = 0;
  6167. bool active_group = current_group_id.isNull() && group_name == "none";
  6168. bool success = false;
  6169. for (S32 i = 0, count = gAgent.mGroups.size(); i < count; ++i)
  6170. {
  6171. if (success && scanned_once)
  6172. {
  6173. // Stop scanning if we found the right group and already did a full
  6174. // scan beforehand.
  6175. break;
  6176. }
  6177. LLGroupData* gdatap = &gAgent.mGroups[i];
  6178. if (!gdatap) continue; // Paranoia
  6179. const LLUUID& group_id = gdatap->mID;
  6180. LLGroupMgrGroupData* mgrdatap = gGroupMgr.getGroupData(group_id);
  6181. if (!mgrdatap)
  6182. {
  6183. gGroupMgr.fetchGroupMissingData(group_id);
  6184. LL_DEBUGS("Lua") << "Group data not yet received for group Id: "
  6185. << group_id << LL_ENDL;
  6186. continue;
  6187. }
  6188. if (!success && group_id.asString() == group_name)
  6189. {
  6190. group_name = gdatap->mName;
  6191. // Make sure we get all the data for this group
  6192. gGroupMgr.fetchGroupMissingData(group_id);
  6193. }
  6194. if (!success && gdatap->mName == group_name)
  6195. {
  6196. LL_DEBUGS("Lua") << "Found matching group name: " << group_name
  6197. << " - Group Id: " << group_id << LL_ENDL;
  6198. lua_pushliteral(state, "group_id");
  6199. lua_pushstring(state, group_id.asString().c_str());
  6200. lua_rawset(state, -3);
  6201. lua_pushliteral(state, "insignia_id");
  6202. lua_pushstring(state, gdatap->mInsigniaID.asString().c_str());
  6203. lua_rawset(state, -3);
  6204. lua_pushliteral(state, "contribution");
  6205. lua_pushinteger(state, gdatap->mContribution);
  6206. lua_rawset(state, -3);
  6207. lua_pushliteral(state, "in_profile");
  6208. lua_pushboolean(state, gdatap->mListInProfile);
  6209. lua_rawset(state, -3);
  6210. lua_pushliteral(state, "accept_notices");
  6211. lua_pushboolean(state, gdatap->mAcceptNotices);
  6212. lua_rawset(state, -3);
  6213. lua_pushliteral(state, "chat_muted");
  6214. lua_pushboolean(state,
  6215. LLMuteList::isMuted(group_id,
  6216. LLMute::flagTextChat));
  6217. lua_rawset(state, -3);
  6218. lua_pushliteral(state, "founder_id");
  6219. lua_pushstring(state, mgrdatap->mFounderID.asString().c_str());
  6220. lua_rawset(state, -3);
  6221. lua_pushliteral(state, "charter");
  6222. lua_pushstring(state, mgrdatap->mCharter.c_str());
  6223. lua_rawset(state, -3);
  6224. lua_pushliteral(state, "fee");
  6225. lua_pushinteger(state, mgrdatap->mMembershipFee);
  6226. lua_rawset(state, -3);
  6227. lua_pushliteral(state, "member_count");
  6228. lua_pushinteger(state, mgrdatap->mMemberCount);
  6229. lua_rawset(state, -3);
  6230. lua_pushliteral(state, "open_enrollment");
  6231. lua_pushboolean(state, mgrdatap->mOpenEnrollment);
  6232. lua_rawset(state, -3);
  6233. lua_pushliteral(state, "mature");
  6234. lua_pushboolean(state, mgrdatap->mMaturePublish);
  6235. lua_rawset(state, -3);
  6236. lua_pushliteral(state, "members_list_ok");
  6237. lua_pushboolean(state, mgrdatap->isMemberDataComplete());
  6238. lua_rawset(state, -3);
  6239. lua_pushliteral(state, "roles_list_ok");
  6240. lua_pushboolean(state, mgrdatap->isRoleDataComplete() &&
  6241. mgrdatap->isRoleMemberDataComplete());
  6242. lua_rawset(state, -3);
  6243. lua_pushliteral(state, "properties_ok");
  6244. lua_pushboolean(state, mgrdatap->isGroupPropertiesDataComplete());
  6245. lua_rawset(state, -3);
  6246. lua_pushliteral(state, "group_titles_ok");
  6247. lua_pushboolean(state, mgrdatap->hasGroupTitles());
  6248. lua_rawset(state, -3);
  6249. powers = gdatap->mPowers;
  6250. if (group_id == current_group_id)
  6251. {
  6252. LL_DEBUGS("Lua") << "Group is active" << LL_ENDL;
  6253. active_group = true;
  6254. }
  6255. for (U32 j = 0, count2 = mgrdatap->mTitles.size(); j < count2; ++j)
  6256. {
  6257. const LLGroupTitle& title = mgrdatap->mTitles[j];
  6258. const LLUUID& title_id = title.mRoleID;
  6259. const std::string& title_name = title.mTitle;
  6260. lua_pushstring(state, title_id.asString().c_str());
  6261. lua_pushstring(state, title_name.c_str());
  6262. lua_rawset(state, -3);
  6263. LL_DEBUGS("Lua") << "Found group title: " << title_name
  6264. << " - Group title id: " << title_id << LL_ENDL;
  6265. if (active_group && title.mSelected)
  6266. {
  6267. LL_DEBUGS("Lua") << "Group title is selected" << LL_ENDL;
  6268. lua_pushliteral(state, "current_title_id");
  6269. lua_pushstring(state, title_id.asString().c_str());
  6270. lua_rawset(state, -3);
  6271. lua_pushliteral(state, "current_title_name");
  6272. lua_pushstring(state, title_name.c_str());
  6273. lua_rawset(state, -3);
  6274. }
  6275. }
  6276. success = true;
  6277. }
  6278. }
  6279. scanned_once = true;
  6280. lua_pushliteral(state, "name");
  6281. lua_pushstring(state, group_name.c_str());
  6282. lua_rawset(state, -3);
  6283. if (!success)
  6284. {
  6285. LL_DEBUGS("Lua") << "Group not found" << LL_ENDL;
  6286. lua_pushliteral(state, "group_id");
  6287. lua_pushstring(state, LLUUID::null.asString().c_str());
  6288. lua_rawset(state, -3);
  6289. }
  6290. lua_pushliteral(state, "powers");
  6291. lua_pushinteger(state, powers);
  6292. lua_rawset(state, -3);
  6293. lua_pushliteral(state, "active");
  6294. lua_pushboolean(state, active_group);
  6295. lua_rawset(state, -3);
  6296. return 1;
  6297. }
  6298. //static
  6299. int HBViewerAutomation::setAgentGroup(lua_State* state)
  6300. {
  6301. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  6302. HBViewerAutomation* self = findInstance(state);
  6303. if (!self) return 0;
  6304. if (self->isThreaded())
  6305. {
  6306. HBAutomationThread* threadp = (HBAutomationThread*)self;
  6307. return threadp->callMainFunction("SetAgentGroup");
  6308. }
  6309. S32 n = lua_gettop(state);
  6310. if (n > 2)
  6311. {
  6312. luaL_error(state, "%d arguments passed; expected 0 to 2.", n);
  6313. }
  6314. bool success = true;
  6315. std::string param;
  6316. LLUUID group_id;
  6317. if (n > 0)
  6318. {
  6319. param = luaL_checkstring(state, 1);
  6320. if (param != "none" && param != LLUUID::null.asString())
  6321. {
  6322. LL_DEBUGS("Lua") << "Searching a match in agent's groups for: "
  6323. << param << LL_ENDL;
  6324. for (S32 i = 0, count = gAgent.mGroups.size(); i < count; ++i)
  6325. {
  6326. LLGroupData* gdatap = &gAgent.mGroups[i];
  6327. if (!gdatap) continue; // Paranoia
  6328. const LLUUID& id = gdatap->mID;
  6329. const std::string& name = gdatap->mName;
  6330. if (name == param || id.asString() == param)
  6331. {
  6332. group_id = id;
  6333. LL_DEBUGS("Lua") << "Found group Id: " << group_id
  6334. << LL_ENDL;
  6335. break;
  6336. }
  6337. }
  6338. success = group_id.notNull();
  6339. }
  6340. }
  6341. LLUUID role_id;
  6342. if (success && n > 1 && group_id.notNull())
  6343. {
  6344. param = luaL_checkstring(state, 2);
  6345. LLGroupMgrGroupData* mgrdatap = gGroupMgr.getGroupData(group_id);
  6346. if (mgrdatap)
  6347. {
  6348. LL_DEBUGS("Lua") << "Searching a match in roles for: " << param
  6349. << LL_ENDL;
  6350. for (U32 i = 0, count = mgrdatap->mTitles.size(); i < count; ++i)
  6351. {
  6352. const LLGroupTitle& title = mgrdatap->mTitles[i];
  6353. const LLUUID& title_id = title.mRoleID;
  6354. const std::string& title_name = title.mTitle;
  6355. if (title_name == param || title_id.asString() == param)
  6356. {
  6357. role_id = title_id;
  6358. success = true;
  6359. LL_DEBUGS("Lua") << "Found role Id: " << role_id
  6360. << LL_ENDL;
  6361. break;
  6362. }
  6363. }
  6364. }
  6365. success = role_id.notNull();
  6366. if (!success)
  6367. {
  6368. // Still try and set the group for now, at least...
  6369. success = gAgent.setGroup(group_id);
  6370. if (success)
  6371. {
  6372. LL_DEBUGS("Lua") << "Role/title not found; sending data requests for group Id "
  6373. << group_id
  6374. << ", with asynchronous title setting to: "
  6375. << param << LL_ENDL;
  6376. gGroupMgr.fetchGroupMissingData(group_id);
  6377. HBGroupTitlesObserver::addObserver(group_id, param);
  6378. lua_pop(state, n);
  6379. // Return a special value which is not 'true' since we could
  6380. // not set the title for now, but not 'false' either, since it
  6381. // may finally get set, asynchronously... The 'nil' value is
  6382. // also compatible with the older versions of SetAgentGroup()
  6383. // which used to give up and return 'false' in this case.
  6384. lua_pushnil(state);
  6385. return 1;
  6386. }
  6387. }
  6388. }
  6389. if (n)
  6390. {
  6391. lua_pop(state, n);
  6392. }
  6393. // Set the group if needed.
  6394. if (success)
  6395. {
  6396. success = gAgent.setGroup(group_id);
  6397. LL_DEBUGS("Lua") << "Setting agent group "
  6398. << (success ? "succeeded" : " failed") << LL_ENDL;
  6399. }
  6400. if (success && group_id.notNull() && role_id.notNull())
  6401. {
  6402. // Set the title for this group
  6403. LL_DEBUGS("Lua") << "Setting agent group title" << LL_ENDL;
  6404. gGroupMgr.sendGroupTitleUpdate(group_id, role_id);
  6405. }
  6406. lua_pushboolean(state, success);
  6407. return 1;
  6408. }
  6409. //static
  6410. int HBViewerAutomation::agentGroupInvite(lua_State* state)
  6411. {
  6412. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  6413. HBViewerAutomation* self = findInstance(state);
  6414. if (!self) return 0;
  6415. if (self->isThreaded())
  6416. {
  6417. HBAutomationThread* threadp = (HBAutomationThread*)self;
  6418. return threadp->callMainFunction("AgentGroupInvite");
  6419. }
  6420. S32 n = lua_gettop(state);
  6421. if (n != 2 && n != 3)
  6422. {
  6423. luaL_error(state, "%d arguments passed; expected 2 or 3.", n);
  6424. }
  6425. U32 invited = 0;
  6426. uuid_vec_t avids;
  6427. if (lua_type(state, 1) == LUA_TTABLE)
  6428. {
  6429. for (U32 i = 1, count = lua_rawlen(state, 1); i <= count; ++i)
  6430. {
  6431. if (lua_rawgeti(state, 1, i) == LUA_TSTRING)
  6432. {
  6433. LLUUID id(luaL_checkstring(state, -1), false);
  6434. if (id.notNull())
  6435. {
  6436. avids.emplace_back(id);
  6437. ++invited;
  6438. }
  6439. }
  6440. lua_pop(state, 1);
  6441. }
  6442. }
  6443. else
  6444. {
  6445. LLUUID id(luaL_checkstring(state, 1), false);
  6446. if (id.notNull())
  6447. {
  6448. avids.emplace_back(id);
  6449. invited = 1;
  6450. }
  6451. }
  6452. LLUUID group_id(luaL_checkstring(state, 2), false);
  6453. if (group_id.isNull())
  6454. {
  6455. llwarns << "Invalid (null) group Id passed." << llendl;
  6456. invited = 0;
  6457. }
  6458. LLUUID role_id;
  6459. if (n > 2)
  6460. {
  6461. role_id.set(luaL_checkstring(state, 2), false);
  6462. }
  6463. lua_pop(state, n);
  6464. if (invited)
  6465. {
  6466. if (!gGroupMgr.agentCanAddToRole(group_id, role_id))
  6467. {
  6468. LL_DEBUGS("Lua") << "Cannot invite to group Id " << group_id
  6469. << " with role Id " << role_id << LL_ENDL;
  6470. invited = 0;
  6471. }
  6472. else if (invited > MAX_GROUP_INVITES)
  6473. {
  6474. llwarns << "Too many simultaneous group invitations requested ("
  6475. << invited << ") to group Id: " << group_id
  6476. << ". Only the first " << MAX_GROUP_INVITES
  6477. << " invitations will be sent." << llendl;
  6478. invited = MAX_GROUP_INVITES;
  6479. }
  6480. }
  6481. if (invited)
  6482. {
  6483. LLGroupMgrGroupData* gdatap = gGroupMgr.getGroupData(group_id);
  6484. LLGroupMgrGroupData::member_list_t::iterator mit;
  6485. LLGroupMgrGroupData::member_list_t::iterator mend =
  6486. gdatap->mMembers.end();
  6487. LLGroupMgr::role_member_pairs_t invites;
  6488. for (U32 i = 0; i < invited; ++i)
  6489. {
  6490. const LLUUID& id = avids[i];
  6491. mit = gdatap->mMembers.find(id);
  6492. // Do not re-invite a member in the role they already got...
  6493. if (mit == mend || !mit->second->isInRole(role_id))
  6494. {
  6495. invites[id] = role_id;
  6496. }
  6497. }
  6498. gGroupMgr.sendGroupMemberInvites(group_id, invites);
  6499. }
  6500. lua_pushinteger(state, invited);
  6501. return 1;
  6502. }
  6503. //static
  6504. int HBViewerAutomation::agentSit(lua_State* state)
  6505. {
  6506. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  6507. HBViewerAutomation* self = findInstance(state);
  6508. if (!self) return 0;
  6509. if (self->isThreaded())
  6510. {
  6511. HBAutomationThread* threadp = (HBAutomationThread*)self;
  6512. return threadp->callMainFunction("AgentSit");
  6513. }
  6514. S32 n = lua_gettop(state);
  6515. if (n > 1)
  6516. {
  6517. luaL_error(state, "%d arguments passed; expected 0 or 1.", n);
  6518. }
  6519. if (n)
  6520. {
  6521. LLUUID object_id(luaL_checkstring(state, 1), false);
  6522. if (object_id.isNull())
  6523. {
  6524. luaL_error(state, "Invalid object UUID passed as argument");
  6525. }
  6526. lua_pop(state, 1);
  6527. LLViewerObject* objectp = gObjectList.findObject(object_id);
  6528. lua_pushboolean(state, objectp && sit_on_object(objectp));
  6529. }
  6530. else
  6531. {
  6532. lua_pushboolean(state, sit_on_ground());
  6533. }
  6534. return 1;
  6535. }
  6536. //static
  6537. int HBViewerAutomation::agentStand(lua_State* state)
  6538. {
  6539. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  6540. HBViewerAutomation* self = findInstance(state);
  6541. if (!self) return 0;
  6542. if (self->isThreaded())
  6543. {
  6544. HBAutomationThread* threadp = (HBAutomationThread*)self;
  6545. return threadp->callMainFunction("AgentStand");
  6546. }
  6547. S32 n = lua_gettop(state);
  6548. if (n)
  6549. {
  6550. luaL_error(state, "%d arguments passed; expected 0.", n);
  6551. }
  6552. lua_pushboolean(state, stand_up());
  6553. return 1;
  6554. }
  6555. //static
  6556. int HBViewerAutomation::setAgentTyping(lua_State* state)
  6557. {
  6558. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  6559. HBViewerAutomation* self = findInstance(state);
  6560. if (!self) return 0;
  6561. if (self->isThreaded())
  6562. {
  6563. HBAutomationThread* threadp = (HBAutomationThread*)self;
  6564. return threadp->callMainFunction("SetAgentTyping");
  6565. }
  6566. S32 n = lua_gettop(state);
  6567. if (n > 1)
  6568. {
  6569. luaL_error(state, "%d arguments passed; expected 0 or 1.", n);
  6570. }
  6571. bool start = true;
  6572. if (n == 1)
  6573. {
  6574. start = lua_toboolean(state, 1);
  6575. lua_pop(state, 1);
  6576. }
  6577. LL_DEBUGS("Lua") << "start=" << (start ? "true" : "false") << LL_ENDL;
  6578. if (start)
  6579. {
  6580. gAgent.startTyping();
  6581. }
  6582. else
  6583. {
  6584. gAgent.stopTyping();
  6585. }
  6586. return 0;
  6587. }
  6588. //static
  6589. int HBViewerAutomation::sendChat(lua_State* state)
  6590. {
  6591. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  6592. HBViewerAutomation* self = findInstance(state);
  6593. if (!self) return 0;
  6594. if (self->isThreaded())
  6595. {
  6596. HBAutomationThread* threadp = (HBAutomationThread*)self;
  6597. return threadp->callMainFunction("SendChat");
  6598. }
  6599. S32 n = lua_gettop(state);
  6600. if (n != 1 && n != 2)
  6601. {
  6602. luaL_error(state, "%d arguments passed; expected 1 or 2.", n);
  6603. }
  6604. std::string message(luaL_checkstring(state, 1));
  6605. std::string type;
  6606. if (n > 1)
  6607. {
  6608. type.assign(luaL_checkstring(state, 2));
  6609. }
  6610. lua_pop(state, n);
  6611. LL_DEBUGS("Lua") << "type=" << type << LL_ENDL;
  6612. EChatType chat_type = CHAT_TYPE_NORMAL;
  6613. if (type.find("whisper") != std::string::npos)
  6614. {
  6615. chat_type = CHAT_TYPE_WHISPER;
  6616. }
  6617. else if (type.find("shout") != std::string::npos)
  6618. {
  6619. chat_type = CHAT_TYPE_SHOUT;
  6620. }
  6621. bool animate = type.find("animate") != std::string::npos;
  6622. if (gChatBarp)
  6623. {
  6624. HBIgnoreCallback lock_on_chat(E_ONSENDCHAT);
  6625. gChatBarp->sendChatFromViewer(message, chat_type, animate, false);
  6626. }
  6627. return 0;
  6628. }
  6629. //static
  6630. int HBViewerAutomation::getIMSession(lua_State* state)
  6631. {
  6632. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  6633. HBViewerAutomation* self = findInstance(state);
  6634. if (!self || !gIMMgrp) return 0;
  6635. if (self->isThreaded())
  6636. {
  6637. HBAutomationThread* threadp = (HBAutomationThread*)self;
  6638. return threadp->callMainFunction("GetIMSession");
  6639. }
  6640. S32 n = lua_gettop(state);
  6641. if (n != 1)
  6642. {
  6643. luaL_error(state, "%d arguments passed; expected 1.", n);
  6644. }
  6645. LLUUID target_id(luaL_checkstring(state, 1), false);
  6646. lua_pop(state, 1);
  6647. EInstantMessage dialog =
  6648. gAgent.isInGroup(target_id, true) ? IM_SESSION_GROUP_START
  6649. : IM_NOTHING_SPECIAL;
  6650. std::string name;
  6651. if (gCacheNamep)
  6652. {
  6653. if (dialog == IM_SESSION_GROUP_START)
  6654. {
  6655. gCacheNamep->getGroupName(target_id, name);
  6656. }
  6657. else
  6658. {
  6659. gCacheNamep->getFullName(target_id, name);
  6660. }
  6661. }
  6662. if (name.empty())
  6663. {
  6664. name = target_id.asString();
  6665. }
  6666. LLUUID session_id = gIMMgrp->addSession(name, dialog, target_id);
  6667. LL_DEBUGS("Lua") << "target_id=" << target_id << " - target type: "
  6668. << (dialog == IM_SESSION_GROUP_START ? "group" : "agent")
  6669. << " - session_id=" << session_id << LL_ENDL;
  6670. lua_pushstring(state, session_id.asString().c_str());
  6671. return 1;
  6672. }
  6673. //static
  6674. int HBViewerAutomation::closeIMSession(lua_State* state)
  6675. {
  6676. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  6677. HBViewerAutomation* self = findInstance(state);
  6678. if (!self) return 0;
  6679. if (self->isThreaded())
  6680. {
  6681. HBAutomationThread* threadp = (HBAutomationThread*)self;
  6682. return threadp->callMainFunction("CloseIMSession");
  6683. }
  6684. S32 n = lua_gettop(state);
  6685. if (n != 1 && n != 2)
  6686. {
  6687. luaL_error(state, "%d arguments passed; expected 1 or 2.", n);
  6688. }
  6689. LLUUID session_id(luaL_checkstring(state, 1), false);
  6690. U32 duration = 0;
  6691. if (n > 1)
  6692. {
  6693. duration = llmax((S32)lua_tointeger(state, 2), 0);
  6694. }
  6695. lua_pop(state, n);
  6696. if (session_id.notNull())
  6697. {
  6698. LLFloaterIMSession* im_floater =
  6699. LLFloaterIMSession::findInstance(session_id);
  6700. if (im_floater)
  6701. {
  6702. if (duration)
  6703. {
  6704. bool success = im_floater->setSnoozeDuration(duration);
  6705. if (success)
  6706. {
  6707. LL_DEBUGS("Lua") << "Snoozing group IM session for: "
  6708. << duration << " minutes." << LL_ENDL;
  6709. }
  6710. else
  6711. {
  6712. llwarns << "Cannot snooze IM session: " << session_id
  6713. << ". Only group IM sessions may be snoozed. Leaving session instead."
  6714. << llendl;
  6715. }
  6716. }
  6717. else
  6718. {
  6719. LL_DEBUGS("Lua") << "Closing IM session: " << session_id
  6720. << LL_ENDL;
  6721. }
  6722. im_floater->close();
  6723. }
  6724. }
  6725. return 0;
  6726. }
  6727. //static
  6728. int HBViewerAutomation::sendIM(lua_State* state)
  6729. {
  6730. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  6731. HBViewerAutomation* self = findInstance(state);
  6732. if (!self) return 0;
  6733. if (self->isThreaded())
  6734. {
  6735. HBAutomationThread* threadp = (HBAutomationThread*)self;
  6736. return threadp->callMainFunction("SendIM");
  6737. }
  6738. S32 n = lua_gettop(state);
  6739. if (n != 2)
  6740. {
  6741. luaL_error(state, "%d arguments passed; expected 2.", n);
  6742. }
  6743. LLUUID session_id(luaL_checkstring(state, 1), false);
  6744. std::string message(luaL_checkstring(state, 2));
  6745. lua_pop(state, 2);
  6746. if (session_id.notNull())
  6747. {
  6748. LLFloaterIMSession* im_floater =
  6749. LLFloaterIMSession::findInstance(session_id);
  6750. if (im_floater)
  6751. {
  6752. LL_DEBUGS("Lua") << "other_participant_id=" << session_id
  6753. << LL_ENDL;
  6754. HBIgnoreCallback lock_on_im(E_ONINSTANTMSG);
  6755. im_floater->sendText(utf8str_to_wstring(message));
  6756. }
  6757. }
  6758. return 0;
  6759. }
  6760. //static
  6761. int HBViewerAutomation::alertDialogResponse(lua_State* state)
  6762. {
  6763. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  6764. HBViewerAutomation* self = findInstance(state);
  6765. if (!self) return 0;
  6766. if (self->isThreaded())
  6767. {
  6768. HBAutomationThread* threadp = (HBAutomationThread*)self;
  6769. return threadp->callMainFunction("AlertDialogResponse");
  6770. }
  6771. S32 n = lua_gettop(state);
  6772. if (n != 2)
  6773. {
  6774. luaL_error(state, "%d arguments passed; expected 2.", n);
  6775. }
  6776. LLUUID alert_id(luaL_checkstring(state, 1), false);
  6777. S32 button_idx = luaL_checknumber(state, 2) - 1; // Index, not number
  6778. lua_pop(state, 2);
  6779. bool result = false;
  6780. if (button_idx >= 0 && alert_id.notNull())
  6781. {
  6782. LLAlertDialog* alertp =
  6783. LLAlertDialog::getNamedInstance(alert_id).get();
  6784. if (alertp && !alertp->isDead())
  6785. {
  6786. result = alertp->simulateClickButton(button_idx);
  6787. }
  6788. }
  6789. lua_pushboolean(state, result);
  6790. return 1;
  6791. }
  6792. //static
  6793. int HBViewerAutomation::scriptDialogResponse(lua_State* state)
  6794. {
  6795. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  6796. HBViewerAutomation* self = findInstance(state);
  6797. if (!self) return 0;
  6798. if (self->isThreaded())
  6799. {
  6800. HBAutomationThread* threadp = (HBAutomationThread*)self;
  6801. return threadp->callMainFunction("ScriptDialogResponse");
  6802. }
  6803. S32 n = lua_gettop(state);
  6804. if (n != 2)
  6805. {
  6806. luaL_error(state, "%d arguments passed; expected 2.", n);
  6807. }
  6808. LLUUID notif_id(luaL_checkstring(state, 1), false);
  6809. std::string button(luaL_checkstring(state, 2));
  6810. lua_pop(state, 2);
  6811. if (notif_id.notNull() && !button.empty())
  6812. {
  6813. LLNotifyBox* boxp = LLNotifyBox::getNamedInstance(notif_id).get();
  6814. if (boxp && !boxp->isDead())
  6815. {
  6816. const LLNotifyBox::cb_data_vec_t& data = boxp->getCallbackData();
  6817. for (S32 i = 0, count = data.size(); i < count; ++i)
  6818. {
  6819. if (data[i]->mButtonName == button)
  6820. {
  6821. LLSD response =
  6822. boxp->getNotification()->getResponseTemplate();
  6823. if (!boxp->isDefaultBtnAdded())
  6824. {
  6825. response[button] = true;
  6826. }
  6827. boxp->getNotification()->respond(response);
  6828. lua_pushboolean(state, true);
  6829. return 1;
  6830. }
  6831. }
  6832. }
  6833. }
  6834. lua_pushboolean(state, false);
  6835. return 1;
  6836. }
  6837. //static
  6838. int HBViewerAutomation::cancelNotification(lua_State* state)
  6839. {
  6840. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  6841. HBViewerAutomation* self = findInstance(state);
  6842. if (!self) return 0;
  6843. if (self->isThreaded())
  6844. {
  6845. HBAutomationThread* threadp = (HBAutomationThread*)self;
  6846. return threadp->callMainFunction("CancelNotification");
  6847. }
  6848. S32 n = lua_gettop(state);
  6849. if (n != 1)
  6850. {
  6851. luaL_error(state, "%d arguments passed; expected 1.", n);
  6852. }
  6853. LLUUID notif_id(luaL_checkstring(state, 1), false);
  6854. lua_pop(state, 1);
  6855. if (notif_id.notNull())
  6856. {
  6857. LLNotificationPtr n = gNotifications.find(notif_id);
  6858. if (n)
  6859. {
  6860. gNotifications.cancel(n);
  6861. lua_pushboolean(state, true);
  6862. return 1;
  6863. }
  6864. }
  6865. lua_pushboolean(state, false);
  6866. return 1;
  6867. }
  6868. //static
  6869. int HBViewerAutomation::getObjectInfo(lua_State* state)
  6870. {
  6871. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  6872. HBViewerAutomation* self = findInstance(state);
  6873. if (!self) return 0;
  6874. if (self->isThreaded())
  6875. {
  6876. HBAutomationThread* threadp = (HBAutomationThread*)self;
  6877. return threadp->callMainFunction("GetObjectInfo");
  6878. }
  6879. S32 n = lua_gettop(state);
  6880. if (n != 1)
  6881. {
  6882. luaL_error(state, "%d arguments passed; expected 1.", n);
  6883. }
  6884. LLUUID object_id(luaL_checkstring(state, 1), false);
  6885. lua_pop(state, 1);
  6886. lua_pushboolean(state, requestObjectPropertiesFamily(object_id, 2));
  6887. return 1;
  6888. }
  6889. //static
  6890. int HBViewerAutomation::browseToURL(lua_State* state)
  6891. {
  6892. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  6893. HBViewerAutomation* self = findInstance(state);
  6894. if (!self) return 0;
  6895. if (self->isThreaded())
  6896. {
  6897. HBAutomationThread* threadp = (HBAutomationThread*)self;
  6898. return threadp->callMainFunction("BrowseToURL");
  6899. }
  6900. HBIgnoreCallback lock_on_dispatch_url(E_ONDISPATCHURL);
  6901. S32 n = lua_gettop(state);
  6902. if (n != 1 && n != 2)
  6903. {
  6904. luaL_error(state, "%d arguments passed; expected 1 or 2.", n);
  6905. }
  6906. std::string url(luaL_checkstring(state, 1));
  6907. S32 browser = 0;
  6908. if (n > 1)
  6909. {
  6910. browser = luaL_checknumber(state, 2);
  6911. }
  6912. lua_pop(state, n);
  6913. LL_DEBUGS("Lua") << "Browsing with "
  6914. << (browser ? (browser == 1 ? "built-in" : "external")
  6915. : "preferred")
  6916. << " browser to URL: " << url << LL_ENDL;
  6917. switch (browser)
  6918. {
  6919. case 1:
  6920. LLWeb::loadURLInternal(url);
  6921. break;
  6922. case 2:
  6923. LLWeb::loadURLExternal(url);
  6924. break;
  6925. default:
  6926. LLWeb::loadURL(url);
  6927. }
  6928. return 0;
  6929. }
  6930. //static
  6931. int HBViewerAutomation::dispatchSLURL(lua_State* state)
  6932. {
  6933. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  6934. HBViewerAutomation* self = findInstance(state);
  6935. if (!self) return 0;
  6936. if (self->isThreaded())
  6937. {
  6938. HBAutomationThread* threadp = (HBAutomationThread*)self;
  6939. return threadp->callMainFunction("DispatchSLURL");
  6940. }
  6941. HBIgnoreCallback lock_on_dispatch_slurl(E_ONDISPATCHSLURL);
  6942. S32 n = lua_gettop(state);
  6943. if (n != 1 && n != 2)
  6944. {
  6945. luaL_error(state, "%d arguments passed; expected 1 or 2.", n);
  6946. }
  6947. std::string slurl(luaL_checkstring(state, 1));
  6948. bool trusted = n >= 2 && lua_toboolean(state, 2);
  6949. lua_pop(state, n);
  6950. LL_DEBUGS("Lua") << "Dispatching ("
  6951. << (trusted ? "trusted" : "untrusted") << "): " << slurl
  6952. << LL_ENDL;
  6953. LLURLDispatcher::dispatch(slurl, "clicked", NULL, trusted);
  6954. return 0;
  6955. }
  6956. //static
  6957. int HBViewerAutomation::executeRLV(lua_State* state)
  6958. {
  6959. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  6960. HBViewerAutomation* self = findInstance(state);
  6961. if (!self) return 0;
  6962. if (self->isThreaded())
  6963. {
  6964. HBAutomationThread* threadp = (HBAutomationThread*)self;
  6965. return threadp->callMainFunction("ExecuteRLV");
  6966. }
  6967. S32 n = lua_gettop(state);
  6968. if (n != 1)
  6969. {
  6970. luaL_error(state, "%d arguments passed; expected 1.", n);
  6971. }
  6972. std::string rlvcmd(luaL_checkstring(state, 1));
  6973. lua_pop(state, 1);
  6974. if (gRLenabled && rlvcmd.length())
  6975. {
  6976. LLStringUtil::toLower(rlvcmd);
  6977. LL_DEBUGS("Lua") << "Executing RLV command: \"" << rlvcmd
  6978. << "\" on behalf of: " << self->mFromObjectName
  6979. << LL_ENDL;
  6980. gRLInterface.queueCommands(self->mFromObjectId, self->mFromObjectName,
  6981. rlvcmd);
  6982. }
  6983. return 0;
  6984. }
  6985. //static
  6986. int HBViewerAutomation::openNotification(lua_State* state)
  6987. {
  6988. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  6989. HBViewerAutomation* self = findInstance(state);
  6990. if (!self) return 0;
  6991. if (self->isThreaded())
  6992. {
  6993. HBAutomationThread* threadp = (HBAutomationThread*)self;
  6994. return threadp->callMainFunction("OpenNotification");
  6995. }
  6996. S32 n = lua_gettop(state);
  6997. if (n != 2)
  6998. {
  6999. luaL_error(state, "%d arguments passed; expected 2.", n);
  7000. }
  7001. S32 type = luaL_checknumber(state, 1);
  7002. std::string message(luaL_checkstring(state, 2));
  7003. lua_pop(state, 2);
  7004. std::string name;
  7005. switch (type)
  7006. {
  7007. case ALERT:
  7008. name = "LuaAlert";
  7009. break;
  7010. case NOTIFICATION:
  7011. name = "LuaNotification";
  7012. break;
  7013. case NOTIFYTIP:
  7014. name = "LuaNotifyTip";
  7015. break;
  7016. default:
  7017. luaL_error(state, "Unknown notification type !");
  7018. }
  7019. LL_DEBUGS("Lua") << "Notification type: " << name << LL_ENDL;
  7020. LLSD args;
  7021. args["MESSAGE"] = message;
  7022. gNotifications.add(name, args);
  7023. return 0;
  7024. }
  7025. //static
  7026. int HBViewerAutomation::openFloater(lua_State* state)
  7027. {
  7028. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  7029. HBViewerAutomation* self = findInstance(state);
  7030. if (!self) return 0;
  7031. if (self->isThreaded())
  7032. {
  7033. HBAutomationThread* threadp = (HBAutomationThread*)self;
  7034. return threadp->callMainFunction("OpenFloater");
  7035. }
  7036. S32 n = lua_gettop(state);
  7037. if (n != 1 && n != 2)
  7038. {
  7039. luaL_error(state, "%d arguments passed; expected 1 or 2.", n);
  7040. }
  7041. std::string name(luaL_checkstring(state, 1));
  7042. std::string param;
  7043. LLUUID target_id;
  7044. if (n == 2)
  7045. {
  7046. param.assign(luaL_checkstring(state, 2));
  7047. if (LLUUID::validate(param))
  7048. {
  7049. target_id.set(param);
  7050. }
  7051. }
  7052. lua_pop(state, n);
  7053. LL_DEBUGS("Lua") << "Floater: " << name << " - parameter: " << param
  7054. << LL_ENDL;
  7055. if (name == "active speakers")
  7056. {
  7057. LLFloaterActiveSpeakers::showInstance();
  7058. }
  7059. else if (name == "area search")
  7060. {
  7061. HBFloaterAreaSearch::showInstance();
  7062. }
  7063. else if (name == "beacons")
  7064. {
  7065. LLFloaterBeacons::showInstance();
  7066. }
  7067. else if (name == "avatar info")
  7068. {
  7069. if (self && gObjectList.findAvatar(target_id))
  7070. {
  7071. LLFloaterAvatarInfo::show(target_id);
  7072. }
  7073. }
  7074. else if (name == "camera controls")
  7075. {
  7076. LLFloaterCamera::showInstance();
  7077. }
  7078. else if (name == "chat")
  7079. {
  7080. LLFloaterChat::showInstance();
  7081. }
  7082. else if (name == "debug settings")
  7083. {
  7084. LLFloaterDebugSettings::showInstance();
  7085. }
  7086. else if (name == "debug tags")
  7087. {
  7088. HBFloaterDebugTags::showInstance();
  7089. }
  7090. else if (name == "experiences")
  7091. {
  7092. LLFloaterExperiences::showInstance();
  7093. }
  7094. else if (name == "friends")
  7095. {
  7096. LLFloaterFriends::showInstance();
  7097. }
  7098. else if (name == "gestures")
  7099. {
  7100. LLFloaterGesture::showInstance();
  7101. }
  7102. else if (name == "group info")
  7103. {
  7104. if (self && gAgent.isInGroup(target_id))
  7105. {
  7106. LLFloaterGroupInfo::showFromUUID(target_id);
  7107. }
  7108. }
  7109. else if (name == "groups")
  7110. {
  7111. LLFloaterGroups::showInstance();
  7112. }
  7113. else if (name == "inspect")
  7114. {
  7115. LLViewerObject* object = gObjectList.findObject(target_id);
  7116. if (object)
  7117. {
  7118. if (object->isAvatar())
  7119. {
  7120. HBFloaterInspectAvatar::show(target_id);
  7121. }
  7122. else
  7123. {
  7124. LLFloaterInspect::show(object);
  7125. }
  7126. }
  7127. }
  7128. else if (name == "instant messages")
  7129. {
  7130. LLFloaterChatterBox::showInstance();
  7131. }
  7132. else if (name == "inventory")
  7133. {
  7134. if (!gSavedSettings.getBool("ShowInventory"))
  7135. {
  7136. LLFloaterInventory::toggleVisibility();
  7137. }
  7138. }
  7139. else if (name == "land")
  7140. {
  7141. if (!gRLenabled || !gRLInterface.mContainsShowloc)
  7142. {
  7143. if (gViewerParcelMgr.selectionEmpty())
  7144. {
  7145. gViewerParcelMgr.selectParcelAt(gAgent.getPositionGlobal());
  7146. }
  7147. LLFloaterLand::showInstance();
  7148. }
  7149. }
  7150. else if (name == "land holdings")
  7151. {
  7152. LLFloaterLandHoldings::showInstance();
  7153. }
  7154. else if (name == "lua console")
  7155. {
  7156. HBLuaConsole::showInstance();
  7157. }
  7158. else if (name == "map")
  7159. {
  7160. if (!gSavedSettings.getBool("ShowWorldMap"))
  7161. {
  7162. LLFloaterWorldMap::toggle(NULL);
  7163. }
  7164. }
  7165. else if (name == "media filter")
  7166. {
  7167. SLFloaterMediaFilter::showInstance();
  7168. }
  7169. else if (name == "mini map")
  7170. {
  7171. LLFloaterMiniMap::showInstance();
  7172. }
  7173. else if (name == "movement controls")
  7174. {
  7175. LLFloaterMove::showInstance();
  7176. }
  7177. else if (name == "mute list")
  7178. {
  7179. if (target_id.notNull())
  7180. {
  7181. LLFloaterMute::selectMute(target_id);
  7182. }
  7183. else
  7184. {
  7185. LLFloaterMute::selectMute(param);
  7186. }
  7187. }
  7188. else if (name == "nearby media")
  7189. {
  7190. LLFloaterNearByMedia::showInstance();
  7191. }
  7192. else if (name == "notifications")
  7193. {
  7194. LLFloaterNotificationConsole::showInstance();
  7195. }
  7196. else if (name == "characters")
  7197. {
  7198. LLFloaterPathfindingCharacters::openCharactersWithSelectedObjects();
  7199. }
  7200. else if (name == "linksets")
  7201. {
  7202. LLFloaterPathfindingLinksets::openLinksetsWithSelectedObjects();
  7203. }
  7204. else if (name == "preferences")
  7205. {
  7206. S32 tab = param.empty() ? -1 : atoi(param.c_str());
  7207. if (tab >= 0 && tab < LLFloaterPreference::NUMBER_OF_TABS)
  7208. {
  7209. LLFloaterPreference::openInTab(tab);
  7210. }
  7211. else
  7212. {
  7213. LLFloaterPreference::showInstance();
  7214. }
  7215. }
  7216. else if (name == "pushes")
  7217. {
  7218. HBFloaterBump::showInstance();
  7219. }
  7220. else if (name == "radar")
  7221. {
  7222. HBFloaterRadar::showInstance();
  7223. }
  7224. else if (name == "region")
  7225. {
  7226. if (!gRLenabled || !gRLInterface.mContainsShowloc)
  7227. {
  7228. LLFloaterRegionInfo::showInstance();
  7229. }
  7230. }
  7231. else if (name == "search")
  7232. {
  7233. if (!gSavedSettings.getBool("ShowSearch"))
  7234. {
  7235. HBFloaterSearch::toggle();
  7236. }
  7237. }
  7238. else if (name == "snapshot")
  7239. {
  7240. LLFloaterSnapshot::show(NULL);
  7241. }
  7242. else if (name == "sounds list")
  7243. {
  7244. HBFloaterSoundsList::showInstance();
  7245. }
  7246. else if (name == "stats")
  7247. {
  7248. LLFloaterStats::showInstance();
  7249. }
  7250. else if (name == "teleport history")
  7251. {
  7252. if (gFloaterTeleportHistoryp &&
  7253. !gFloaterTeleportHistoryp->getVisible())
  7254. {
  7255. gFloaterTeleportHistoryp->toggle();
  7256. }
  7257. }
  7258. return 0;
  7259. }
  7260. //static
  7261. int HBViewerAutomation::closeFloater(lua_State* state)
  7262. {
  7263. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  7264. HBViewerAutomation* self = findInstance(state);
  7265. if (!self) return 0;
  7266. if (self->isThreaded())
  7267. {
  7268. HBAutomationThread* threadp = (HBAutomationThread*)self;
  7269. return threadp->callMainFunction("CloseFloater");
  7270. }
  7271. S32 n = lua_gettop(state);
  7272. if (n != 1)
  7273. {
  7274. luaL_error(state, "%d arguments passed; expected 1.", n);
  7275. }
  7276. std::string name(luaL_checkstring(state, 1));
  7277. lua_pop(state, 1);
  7278. LL_DEBUGS("Lua") << "Floater: " << name << LL_ENDL;
  7279. if (name == "active speakers")
  7280. {
  7281. LLFloaterActiveSpeakers::hideInstance();
  7282. }
  7283. else if (name == "area search")
  7284. {
  7285. HBFloaterAreaSearch::hideInstance();
  7286. }
  7287. else if (name == "beacons")
  7288. {
  7289. LLFloaterBeacons::hideInstance();
  7290. }
  7291. else if (name == "camera controls")
  7292. {
  7293. LLFloaterCamera::hideInstance();
  7294. }
  7295. else if (name == "chat")
  7296. {
  7297. LLFloaterChat::hideInstance();
  7298. }
  7299. else if (name == "debug settings")
  7300. {
  7301. LLFloaterDebugSettings::hideInstance();
  7302. }
  7303. else if (name == "debug tags")
  7304. {
  7305. HBFloaterDebugTags::hideInstance();
  7306. }
  7307. else if (name == "experiences")
  7308. {
  7309. LLFloaterExperiences::hideInstance();
  7310. }
  7311. else if (name == "friends")
  7312. {
  7313. LLFloaterFriends::hideInstance();
  7314. }
  7315. else if (name == "gestures")
  7316. {
  7317. LLFloaterGesture::hideInstance();
  7318. }
  7319. else if (name == "groups")
  7320. {
  7321. LLFloaterGroups::hideInstance();
  7322. }
  7323. else if (name == "inspect object")
  7324. {
  7325. LLFloaterInspect::hideInstance();
  7326. }
  7327. else if (name == "inspect avatar")
  7328. {
  7329. HBFloaterInspectAvatar::hideInstance();
  7330. }
  7331. else if (name == "instant messages")
  7332. {
  7333. LLFloaterChatterBox::hideInstance();
  7334. }
  7335. else if (name == "inventory")
  7336. {
  7337. if (gSavedSettings.getBool("ShowInventory"))
  7338. {
  7339. LLFloaterInventory::toggleVisibility();
  7340. }
  7341. }
  7342. else if (name == "land")
  7343. {
  7344. LLFloaterLand::hideInstance();
  7345. }
  7346. else if (name == "land holdings")
  7347. {
  7348. LLFloaterLandHoldings::hideInstance();
  7349. }
  7350. else if (name == "map")
  7351. {
  7352. if (gSavedSettings.getBool("ShowWorldMap"))
  7353. {
  7354. LLFloaterWorldMap::toggle(NULL);
  7355. }
  7356. }
  7357. else if (name == "media filter")
  7358. {
  7359. SLFloaterMediaFilter::hideInstance();
  7360. }
  7361. else if (name == "mini map")
  7362. {
  7363. LLFloaterMiniMap::hideInstance();
  7364. }
  7365. else if (name == "movement controls")
  7366. {
  7367. LLFloaterMove::hideInstance();
  7368. }
  7369. else if (name == "mute list")
  7370. {
  7371. LLFloaterMute::hideInstance();
  7372. }
  7373. else if (name == "nearby media")
  7374. {
  7375. LLFloaterNearByMedia::hideInstance();
  7376. }
  7377. else if (name == "notifications")
  7378. {
  7379. LLFloaterNotificationConsole::hideInstance();
  7380. }
  7381. else if (name == "characters")
  7382. {
  7383. LLFloaterPathfindingCharacters::hideInstance();
  7384. }
  7385. else if (name == "linksets")
  7386. {
  7387. LLFloaterPathfindingLinksets::hideInstance();
  7388. }
  7389. else if (name == "preferences")
  7390. {
  7391. LLFloaterPreference::hideInstance();
  7392. }
  7393. else if (name == "pushes")
  7394. {
  7395. HBFloaterBump::hideInstance();
  7396. }
  7397. else if (name == "radar")
  7398. {
  7399. HBFloaterRadar::hideInstance();
  7400. }
  7401. else if (name == "region")
  7402. {
  7403. LLFloaterRegionInfo::hideInstance();
  7404. }
  7405. else if (name == "search")
  7406. {
  7407. if (gSavedSettings.getBool("ShowSearch"))
  7408. {
  7409. HBFloaterSearch::toggle();
  7410. }
  7411. }
  7412. else if (name == "snapshot")
  7413. {
  7414. LLFloaterSnapshot::hide(NULL);
  7415. }
  7416. else if (name == "sounds list")
  7417. {
  7418. HBFloaterSoundsList::hideInstance();
  7419. }
  7420. else if (name == "stats")
  7421. {
  7422. LLFloaterStats::hideInstance();
  7423. }
  7424. else if (name == "teleport history")
  7425. {
  7426. if (gFloaterTeleportHistoryp &&
  7427. gFloaterTeleportHistoryp->getVisible())
  7428. {
  7429. gFloaterTeleportHistoryp->toggle();
  7430. }
  7431. }
  7432. return 0;
  7433. }
  7434. //static
  7435. int HBViewerAutomation::getFloaterInstances(lua_State* state)
  7436. {
  7437. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  7438. HBViewerAutomation* self = findInstance(state);
  7439. if (!self) return 0;
  7440. if (self->isThreaded())
  7441. {
  7442. HBAutomationThread* threadp = (HBAutomationThread*)self;
  7443. return threadp->callMainFunction("GetFloaterInstances");
  7444. }
  7445. S32 n = lua_gettop(state);
  7446. if (n > 1)
  7447. {
  7448. luaL_error(state, "%d arguments passed; expected 0 or 1.", n);
  7449. }
  7450. std::string match;
  7451. if (n)
  7452. {
  7453. match = luaL_checkstring(state, 1);
  7454. lua_pop(state, 1);
  7455. }
  7456. lua_newtable(state);
  7457. std::string name, title;
  7458. bool do_match = !match.empty();
  7459. using iter_t = LLView::child_list_const_iter_t;
  7460. for (iter_t it = gFloaterViewp->getChildList()->begin(),
  7461. end = gFloaterViewp->getChildList()->end();
  7462. it != end; ++it)
  7463. {
  7464. LLFloater* floaterp = (*it)->asFloater();
  7465. if (floaterp)
  7466. {
  7467. name = floaterp->getName();
  7468. if (do_match && name != match)
  7469. {
  7470. continue;
  7471. }
  7472. if (!floaterp->isTitlePristine())
  7473. {
  7474. title = floaterp->getTitle();
  7475. if (!title.empty() && stricmp(name.c_str(), title.c_str()))
  7476. {
  7477. name += "=" + title;
  7478. }
  7479. }
  7480. lua_pushstring(state, name.c_str());
  7481. lua_rawseti(state, -2, floaterp->getId());
  7482. }
  7483. }
  7484. return 1;
  7485. }
  7486. static LLFloater* get_floater_by_id(S32 id)
  7487. {
  7488. if (id > 0)
  7489. {
  7490. using iter_t = LLView::child_list_const_iter_t;
  7491. for (iter_t it = gFloaterViewp->getChildList()->begin(),
  7492. end = gFloaterViewp->getChildList()->end();
  7493. it != end; ++it)
  7494. {
  7495. LLFloater* floaterp = (*it)->asFloater();
  7496. if (floaterp && floaterp->getId() == (U32)id)
  7497. {
  7498. return floaterp;
  7499. }
  7500. }
  7501. }
  7502. return NULL;
  7503. }
  7504. //static
  7505. int HBViewerAutomation::showFloater(lua_State* state)
  7506. {
  7507. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  7508. HBViewerAutomation* self = findInstance(state);
  7509. if (!self) return 0;
  7510. if (self->isThreaded())
  7511. {
  7512. HBAutomationThread* threadp = (HBAutomationThread*)self;
  7513. return threadp->callMainFunction("ShowFloater");
  7514. }
  7515. S32 n = lua_gettop(state);
  7516. if (n != 1)
  7517. {
  7518. luaL_error(state, "%d arguments passed; expected 1.", n);
  7519. }
  7520. S32 id = luaL_checknumber(state, 1);
  7521. lua_pop(state, 1);
  7522. LLFloater* floaterp = get_floater_by_id(id);
  7523. if (floaterp)
  7524. {
  7525. floaterp->open();
  7526. }
  7527. lua_pushboolean(state, floaterp && floaterp->getVisible());
  7528. return 1;
  7529. }
  7530. static void get_all_children(LLView* parentp, std::vector<LLView*>& children)
  7531. {
  7532. size_t count = parentp->getChildCount();
  7533. if (!count)
  7534. {
  7535. return;
  7536. }
  7537. children.reserve(children.size() + count);
  7538. using iter_t = LLView::child_list_const_iter_t;
  7539. for (iter_t it = parentp->getChildList()->begin(),
  7540. end = parentp->getChildList()->end();
  7541. it != end; ++it)
  7542. {
  7543. LLView* viewp = *it;
  7544. if (viewp) // Paranoia
  7545. {
  7546. children.push_back(viewp);
  7547. get_all_children(viewp, children);
  7548. }
  7549. }
  7550. }
  7551. //static
  7552. int HBViewerAutomation::getFloaterControls(lua_State* state)
  7553. {
  7554. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  7555. HBViewerAutomation* self = findInstance(state);
  7556. if (!self) return 0;
  7557. if (self->isThreaded())
  7558. {
  7559. HBAutomationThread* threadp = (HBAutomationThread*)self;
  7560. return threadp->callMainFunction("GetFloaterControls");
  7561. }
  7562. S32 n = lua_gettop(state);
  7563. if (n < 1 || n > 5)
  7564. {
  7565. luaL_error(state, "%d arguments passed; expected 1 to 5.", n);
  7566. }
  7567. S32 id = luaL_checknumber(state, 1);
  7568. bool list_disabled = n >= 2 && lua_toboolean(state, 2);
  7569. bool list_hidden = n >= 3 && lua_toboolean(state, 3);
  7570. bool filter_tag = false;
  7571. std::string tag_match;
  7572. if (n >= 4)
  7573. {
  7574. tag_match = luaL_checkstring(state, 4);
  7575. filter_tag = !tag_match.empty();
  7576. }
  7577. bool filter_name = false;
  7578. std::string name_match;
  7579. if (n >= 5)
  7580. {
  7581. name_match = luaL_checkstring(state, 5);
  7582. filter_name = !name_match.empty();
  7583. }
  7584. lua_pop(state, n);
  7585. LLFloater* floaterp = get_floater_by_id(id);
  7586. if (!floaterp)
  7587. {
  7588. // No such floater: return nil.
  7589. lua_pushnil(state);
  7590. return 1;
  7591. }
  7592. lua_newtable(state);
  7593. if (!list_hidden && !floaterp->getVisible())
  7594. {
  7595. // Return an empty table since all elements are hidden.
  7596. return 1;
  7597. }
  7598. // Get all children first.
  7599. std::vector<LLView*> children;
  7600. get_all_children(floaterp, children);
  7601. std::string name;
  7602. for (U32 i = 0, count = children.size(); i < count; ++i)
  7603. {
  7604. LLView* viewp = children[i];
  7605. if (viewp && viewp->isCtrl() &&
  7606. (list_hidden || viewp->getVisible()) &&
  7607. (list_disabled || viewp->getEnabled()))
  7608. {
  7609. const std::string& tag = viewp->getTag();
  7610. if (filter_tag && tag != tag_match)
  7611. {
  7612. continue;
  7613. }
  7614. std::string name = viewp->getName();
  7615. if (filter_name && name.find(name_match) == std::string::npos)
  7616. {
  7617. continue;
  7618. }
  7619. lua_pushstring(state, name.c_str());
  7620. lua_pushstring(state, tag.c_str());
  7621. lua_rawset(state, -3);
  7622. }
  7623. }
  7624. return 1;
  7625. }
  7626. //static
  7627. int HBViewerAutomation::getFloaterCtrlState(lua_State* state)
  7628. {
  7629. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  7630. HBViewerAutomation* self = findInstance(state);
  7631. if (!self) return 0;
  7632. if (self->isThreaded())
  7633. {
  7634. HBAutomationThread* threadp = (HBAutomationThread*)self;
  7635. return threadp->callMainFunction("GetFloaterCtrlState");
  7636. }
  7637. S32 n = lua_gettop(state);
  7638. if (n != 2)
  7639. {
  7640. luaL_error(state, "%d arguments passed; expected 2.", n);
  7641. }
  7642. S32 id = luaL_checknumber(state, 1);
  7643. std::string name = luaL_checkstring(state, 2);
  7644. lua_pop(state, 2);
  7645. LLFloater* floaterp = get_floater_by_id(id);
  7646. if (!floaterp || name.empty())
  7647. {
  7648. // No such floater, or no UI control name: return nil.
  7649. lua_pushnil(state);
  7650. return 1;
  7651. }
  7652. LLView* viewp = floaterp->getChildView(name.c_str(), true, false);
  7653. if (!viewp || !viewp->isCtrl())
  7654. {
  7655. // No such *control*: return nil.
  7656. lua_pushnil(state);
  7657. return 1;
  7658. }
  7659. LLUICtrl* ctrlp = (LLUICtrl*)viewp;
  7660. lua_newtable(state);
  7661. lua_pushliteral(state, "type");
  7662. lua_pushstring(state, ctrlp->getTag().c_str());
  7663. lua_rawset(state, -3);
  7664. lua_pushliteral(state, "children");
  7665. lua_pushinteger(state, ctrlp->getChildCount());
  7666. lua_rawset(state, -3);
  7667. lua_pushliteral(state, "visible");
  7668. lua_pushboolean(state, ctrlp->getVisible());
  7669. lua_rawset(state, -3);
  7670. lua_pushliteral(state, "enabled");
  7671. lua_pushboolean(state, ctrlp->getEnabled());
  7672. lua_rawset(state, -3);
  7673. lua_pushliteral(state, "chrome");
  7674. lua_pushboolean(state, ctrlp->getIsChrome());
  7675. lua_rawset(state, -3);
  7676. lua_pushliteral(state, "control");
  7677. lua_pushstring(state, ctrlp->getControlName().c_str());
  7678. lua_rawset(state, -3);
  7679. lua_pushliteral(state, "value");
  7680. lua_pushstring(state, ctrlp->getValue().asString().c_str());
  7681. lua_rawset(state, -3);
  7682. lua_pushliteral(state, "dirty");
  7683. lua_pushboolean(state, ctrlp->isDirty());
  7684. lua_rawset(state, -3);
  7685. lua_pushliteral(state, "focusable");
  7686. lua_pushboolean(state, ctrlp->isFocusableCtrl());
  7687. lua_rawset(state, -3);
  7688. lua_pushliteral(state, "focused");
  7689. lua_pushboolean(state, ctrlp->hasFocus());
  7690. lua_rawset(state, -3);
  7691. lua_pushliteral(state, "mouse_capture");
  7692. lua_pushboolean(state, ctrlp->hasMouseCapture());
  7693. lua_rawset(state, -3);
  7694. lua_pushliteral(state, "text_input");
  7695. lua_pushboolean(state, ctrlp->acceptsTextInput());
  7696. lua_rawset(state, -3);
  7697. return 1;
  7698. }
  7699. //static
  7700. int HBViewerAutomation::getFloaterList(lua_State* state)
  7701. {
  7702. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  7703. HBViewerAutomation* self = findInstance(state);
  7704. if (!self) return 0;
  7705. if (self->isThreaded())
  7706. {
  7707. HBAutomationThread* threadp = (HBAutomationThread*)self;
  7708. return threadp->callMainFunction("GetFloaterList");
  7709. }
  7710. S32 n = lua_gettop(state);
  7711. if (n != 2)
  7712. {
  7713. luaL_error(state, "%d arguments passed; expected 2.", n);
  7714. }
  7715. S32 id = luaL_checknumber(state, 1);
  7716. std::string name = luaL_checkstring(state, 2);
  7717. lua_pop(state, 2);
  7718. LLFloater* floaterp = get_floater_by_id(id);
  7719. if (!floaterp || name.empty())
  7720. {
  7721. // No such floater, or no UI control name: return nil.
  7722. lua_pushnil(state);
  7723. return 1;
  7724. }
  7725. LLScrollListCtrl* listp =
  7726. floaterp->getChild<LLScrollListCtrl>(name.c_str(), true, false);
  7727. if (!listp)
  7728. {
  7729. // No such list: return nil.
  7730. lua_pushnil(state);
  7731. return 1;
  7732. }
  7733. lua_newtable(state);
  7734. // Number of columns in the list.
  7735. S32 columns = listp->getNumColumns();
  7736. lua_pushliteral(state, "columns");
  7737. lua_pushinteger(state, columns);
  7738. lua_rawset(state, -3);
  7739. // Give the header for each column as a string in the form:
  7740. // "col1_name=col1_label|...|colN_name=colN_label"
  7741. std::string temp;
  7742. for (S32 i = 0; i < columns; ++i)
  7743. {
  7744. LLScrollListColumn* colp = listp->getColumn(i);
  7745. if (i)
  7746. {
  7747. temp += "|";
  7748. }
  7749. temp += colp->mName + "=" + colp->mLabel;
  7750. }
  7751. lua_pushliteral(state, "headers");
  7752. lua_pushstring(state, temp.c_str());
  7753. lua_rawset(state, -3);
  7754. // Give one table entry per list line (numbred from 1 to n, with n the
  7755. // number of lines in the list); each column cell value in the line is
  7756. // converted into a string and separated from the next with a pipe
  7757. // character.
  7758. std::vector<LLScrollListItem*> items = listp->getAllData();
  7759. for (S32 i = 0, lines = items.size(); i < lines; ++i)
  7760. {
  7761. LLScrollListItem* itemp = items[i];
  7762. if (!itemp) continue; // Paranoia
  7763. temp.clear();
  7764. for (S32 j = 0; j < columns; ++j)
  7765. {
  7766. if (j)
  7767. {
  7768. temp += "|";
  7769. }
  7770. LLScrollListCell* cellp = itemp->getColumn(j);
  7771. if (cellp) // Paranoia ?
  7772. {
  7773. temp += cellp->getValue().asString();
  7774. }
  7775. }
  7776. lua_pushinteger(state, i + 1);
  7777. lua_pushstring(state, temp.c_str());
  7778. lua_rawset(state, -3);
  7779. }
  7780. return 1;
  7781. }
  7782. //static
  7783. int HBViewerAutomation::makeDialog(lua_State* state)
  7784. {
  7785. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  7786. HBViewerAutomation* self = findInstance(state);
  7787. if (!self) return 0;
  7788. if (self->isThreaded())
  7789. {
  7790. HBAutomationThread* threadp = (HBAutomationThread*)self;
  7791. return threadp->callMainFunction("MakeDialog");
  7792. }
  7793. S32 n = lua_gettop(state);
  7794. if (n != 9)
  7795. {
  7796. luaL_error(state, "%d arguments passed; expected 9.", n);
  7797. }
  7798. std::string params[9];
  7799. for (S32 i = 0; i < 9; ++i)
  7800. {
  7801. params[i] = luaL_checkstring(state, i + 1);
  7802. }
  7803. lua_pop(state, 9);
  7804. HBLuaDialog::create(params[0], params[1], params[2], params[3], params[4],
  7805. params[5], params[6], params[7], params[8]);
  7806. return 0;
  7807. }
  7808. //static
  7809. int HBViewerAutomation::openLuaFloater(lua_State* state)
  7810. {
  7811. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  7812. HBViewerAutomation* self = findInstance(state);
  7813. if (!self) return 0;
  7814. if (self->isThreaded())
  7815. {
  7816. HBAutomationThread* threadp = (HBAutomationThread*)self;
  7817. return threadp->callMainFunction("OpenLuaFloater");
  7818. }
  7819. S32 n = lua_gettop(state);
  7820. if (n < 1 || n > 4)
  7821. {
  7822. luaL_error(state, "%d arguments passed; expected 1 to 4.", n);
  7823. }
  7824. std::string name(luaL_checkstring(state, 1));
  7825. std::string param, pos;
  7826. if (n >= 2)
  7827. {
  7828. param.assign(luaL_checkstring(state, 2));
  7829. }
  7830. if (n >= 3)
  7831. {
  7832. pos.assign(luaL_checkstring(state, 3));
  7833. }
  7834. bool open = n < 4 || lua_toboolean(state, 4);
  7835. lua_pop(state, n);
  7836. lua_pushboolean(state,
  7837. HBLuaFloater::create(name, param, pos, open) != NULL);
  7838. return 1;
  7839. }
  7840. //static
  7841. int HBViewerAutomation::showLuaFloater(lua_State* state)
  7842. {
  7843. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  7844. HBViewerAutomation* self = findInstance(state);
  7845. if (!self) return 0;
  7846. if (self->isThreaded())
  7847. {
  7848. HBAutomationThread* threadp = (HBAutomationThread*)self;
  7849. return threadp->callMainFunction("ShowLuaFloater");
  7850. }
  7851. S32 n = lua_gettop(state);
  7852. if (n != 1 && n != 2)
  7853. {
  7854. luaL_error(state, "%d arguments passed; expected 1 or 2.", n);
  7855. }
  7856. std::string name(luaL_checkstring(state, 1));
  7857. bool show = n < 2 || lua_toboolean(state, 2);
  7858. lua_pop(state, n);
  7859. lua_pushboolean(state, HBLuaFloater::setVisible(name, show));
  7860. return 1;
  7861. }
  7862. //static
  7863. int HBViewerAutomation::closeLuaFloater(lua_State* state)
  7864. {
  7865. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  7866. HBViewerAutomation* self = findInstance(state);
  7867. if (!self) return 0;
  7868. if (self->isThreaded())
  7869. {
  7870. HBAutomationThread* threadp = (HBAutomationThread*)self;
  7871. return threadp->callMainFunction("CloseLuaFloater");
  7872. }
  7873. S32 n = lua_gettop(state);
  7874. if (n != 1)
  7875. {
  7876. luaL_error(state, "%d arguments passed; expected 1.", n);
  7877. }
  7878. std::string name(luaL_checkstring(state, 1));
  7879. lua_pop(state, 1);
  7880. // This will call the OnLuaFloaterClose() callback if
  7881. // CloseLuaFloater() was not invoked from the automation script.
  7882. HBLuaFloater::destroy(name, self != gAutomationp);
  7883. return 0;
  7884. }
  7885. //static
  7886. int HBViewerAutomation::setLuaFloaterCommand(lua_State* state)
  7887. {
  7888. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  7889. HBViewerAutomation* self = findInstance(state);
  7890. if (!self) return 0;
  7891. if (self->isThreaded())
  7892. {
  7893. HBAutomationThread* threadp = (HBAutomationThread*)self;
  7894. return threadp->callMainFunction("SetLuaFloaterCommand");
  7895. }
  7896. S32 n = lua_gettop(state);
  7897. if (n != 3)
  7898. {
  7899. luaL_error(state, "%d arguments passed; expected 3.", n);
  7900. }
  7901. std::string floater_name(luaL_checkstring(state, 1));
  7902. std::string ctrl_name(luaL_checkstring(state, 2));
  7903. std::string command(luaL_checkstring(state, 3));
  7904. lua_pop(state, 3);
  7905. lua_pushboolean(state,
  7906. HBLuaFloater::setControlCallback(floater_name,
  7907. ctrl_name, command));
  7908. return 1;
  7909. }
  7910. //static
  7911. int HBViewerAutomation::getLuaFloaterValue(lua_State* state)
  7912. {
  7913. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  7914. HBViewerAutomation* self = findInstance(state);
  7915. if (!self) return 0;
  7916. if (self->isThreaded())
  7917. {
  7918. HBAutomationThread* threadp = (HBAutomationThread*)self;
  7919. return threadp->callMainFunction("GetLuaFloaterValue");
  7920. }
  7921. S32 n = lua_gettop(state);
  7922. if (n != 2)
  7923. {
  7924. luaL_error(state, "%d arguments passed; expected 2.", n);
  7925. }
  7926. std::string floater_name(luaL_checkstring(state, 1));
  7927. std::string ctrl_name(luaL_checkstring(state, 2));
  7928. lua_pop(state, 2);
  7929. std::string value;
  7930. if (HBLuaFloater::getControlValue(floater_name, ctrl_name, value))
  7931. {
  7932. lua_pushstring(state, value.c_str());
  7933. }
  7934. else
  7935. {
  7936. lua_pushnil(state);
  7937. }
  7938. return 1;
  7939. }
  7940. //static
  7941. int HBViewerAutomation::getLuaFloaterValues(lua_State* state)
  7942. {
  7943. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  7944. HBViewerAutomation* self = findInstance(state);
  7945. if (!self) return 0;
  7946. if (self->isThreaded())
  7947. {
  7948. HBAutomationThread* threadp = (HBAutomationThread*)self;
  7949. return threadp->callMainFunction("GetLuaFloaterValues");
  7950. }
  7951. S32 n = lua_gettop(state);
  7952. if (n != 2)
  7953. {
  7954. luaL_error(state, "%d arguments passed; expected 2.", n);
  7955. }
  7956. std::string floater_name(luaL_checkstring(state, 1));
  7957. std::string ctrl_name(luaL_checkstring(state, 2));
  7958. lua_pop(state, 2);
  7959. std::vector<std::string> values;
  7960. if (HBLuaFloater::getControlValues(floater_name, ctrl_name, values))
  7961. {
  7962. lua_newtable(state);
  7963. for (S32 i = 0, count = values.size(); i < count; ++i)
  7964. {
  7965. lua_pushstring(state, values[i].c_str());
  7966. lua_rawseti(state, -2, i + 1);
  7967. }
  7968. }
  7969. else
  7970. {
  7971. lua_pushnil(state);
  7972. }
  7973. return 1;
  7974. }
  7975. //static
  7976. int HBViewerAutomation::setLuaFloaterValue(lua_State* state)
  7977. {
  7978. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  7979. HBViewerAutomation* self = findInstance(state);
  7980. if (!self) return 0;
  7981. if (self->isThreaded())
  7982. {
  7983. HBAutomationThread* threadp = (HBAutomationThread*)self;
  7984. return threadp->callMainFunction("SetLuaFloaterValue");
  7985. }
  7986. S32 n = lua_gettop(state);
  7987. if (n != 3)
  7988. {
  7989. luaL_error(state, "%d arguments passed; expected 3.", n);
  7990. }
  7991. std::string floater_name(luaL_checkstring(state, 1));
  7992. std::string ctrl_name(luaL_checkstring(state, 2));
  7993. std::string value(luaL_checkstring(state, 3));
  7994. lua_pop(state, n);
  7995. lua_pushboolean(state,
  7996. HBLuaFloater::setControlValue(floater_name, ctrl_name,
  7997. value));
  7998. return 1;
  7999. }
  8000. //static
  8001. int HBViewerAutomation::setLuaFloaterInvFilter(lua_State* state)
  8002. {
  8003. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  8004. HBViewerAutomation* self = findInstance(state);
  8005. if (!self) return 0;
  8006. if (self->isThreaded())
  8007. {
  8008. HBAutomationThread* threadp = (HBAutomationThread*)self;
  8009. return threadp->callMainFunction("SetLuaFloaterInvFilter");
  8010. }
  8011. S32 n = lua_gettop(state);
  8012. if (n != 2 && n != 3)
  8013. {
  8014. luaL_error(state, "%d arguments passed; expected 2 or 3.", n);
  8015. }
  8016. std::string floater_name(luaL_checkstring(state, 1));
  8017. std::string ctrl_name(luaL_checkstring(state, 2));
  8018. std::string value;
  8019. if (n > 2)
  8020. {
  8021. value.assign(luaL_checkstring(state, 3));
  8022. }
  8023. lua_pop(state, n);
  8024. lua_pushboolean(state,
  8025. HBLuaFloater::setInvFilter(floater_name, ctrl_name,
  8026. value));
  8027. return 1;
  8028. }
  8029. //static
  8030. int HBViewerAutomation::setLuaFloaterEnabled(lua_State* state)
  8031. {
  8032. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  8033. HBViewerAutomation* self = findInstance(state);
  8034. if (!self) return 0;
  8035. if (self->isThreaded())
  8036. {
  8037. HBAutomationThread* threadp = (HBAutomationThread*)self;
  8038. return threadp->callMainFunction("SetLuaFloaterEnabled");
  8039. }
  8040. S32 n = lua_gettop(state);
  8041. if (n != 2 && n != 3)
  8042. {
  8043. luaL_error(state, "%d arguments passed; expected 2 or 3.", n);
  8044. }
  8045. std::string floater_name(luaL_checkstring(state, 1));
  8046. std::string ctrl_name(luaL_checkstring(state, 2));
  8047. bool enable = n < 3 || lua_toboolean(state, 3);
  8048. lua_pop(state, n);
  8049. lua_pushboolean(state,
  8050. HBLuaFloater::setControlEnabled(floater_name, ctrl_name,
  8051. enable));
  8052. return 1;
  8053. }
  8054. //static
  8055. int HBViewerAutomation::setLuaFloaterVisible(lua_State* state)
  8056. {
  8057. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  8058. HBViewerAutomation* self = findInstance(state);
  8059. if (!self) return 0;
  8060. if (self->isThreaded())
  8061. {
  8062. HBAutomationThread* threadp = (HBAutomationThread*)self;
  8063. return threadp->callMainFunction("SetLuaFloaterVisible");
  8064. }
  8065. S32 n = lua_gettop(state);
  8066. if (n != 2 && n != 3)
  8067. {
  8068. luaL_error(state, "%d arguments passed; expected 2 or 3.", n);
  8069. }
  8070. std::string floater_name(luaL_checkstring(state, 1));
  8071. std::string ctrl_name(luaL_checkstring(state, 2));
  8072. bool visible = n < 3 || lua_toboolean(state, 3);
  8073. lua_pop(state, n);
  8074. lua_pushboolean(state,
  8075. HBLuaFloater::setControlVisible(floater_name, ctrl_name,
  8076. visible));
  8077. return 1;
  8078. }
  8079. //static
  8080. int HBViewerAutomation::overlayBarLuaButton(lua_State* state)
  8081. {
  8082. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  8083. HBViewerAutomation* self = findInstance(state);
  8084. if (!self) return 0;
  8085. if (self->isThreaded())
  8086. {
  8087. HBAutomationThread* threadp = (HBAutomationThread*)self;
  8088. return threadp->callMainFunction("OverlayBarLuaButton");
  8089. }
  8090. S32 n = lua_gettop(state);
  8091. if (n != 2 && n != 3)
  8092. {
  8093. luaL_error(state, "%d arguments passed; expected 2 or 3.", n);
  8094. }
  8095. std::string label(luaL_checkstring(state, 1));
  8096. std::string command(luaL_checkstring(state, 2));
  8097. std::string tooltip;
  8098. if (n == 3)
  8099. {
  8100. tooltip.assign(luaL_checkstring(state, 3));
  8101. }
  8102. lua_pop(state, n);
  8103. if (gOverlayBarp)
  8104. {
  8105. gOverlayBarp->setLuaFunctionButton(label, command, tooltip);
  8106. }
  8107. return 0;
  8108. }
  8109. //static
  8110. int HBViewerAutomation::statusBarLuaIcon(lua_State* state)
  8111. {
  8112. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  8113. HBViewerAutomation* self = findInstance(state);
  8114. if (!self) return 0;
  8115. if (self->isThreaded())
  8116. {
  8117. HBAutomationThread* threadp = (HBAutomationThread*)self;
  8118. return threadp->callMainFunction("StatusBarLuaIcon");
  8119. }
  8120. S32 n = lua_gettop(state);
  8121. if (n != 1 && n != 2)
  8122. {
  8123. luaL_error(state, "%d arguments passed; expected 1 or 2.", n);
  8124. }
  8125. std::string command(luaL_checkstring(state, 1));
  8126. std::string tooltip;
  8127. if (n == 2)
  8128. {
  8129. tooltip.assign(luaL_checkstring(state, 2));
  8130. }
  8131. lua_pop(state, n);
  8132. if (gStatusBarp)
  8133. {
  8134. gStatusBarp->setLuaFunctionButton(command, tooltip);
  8135. }
  8136. return 0;
  8137. }
  8138. //static
  8139. int HBViewerAutomation::sideBarButton(lua_State* state)
  8140. {
  8141. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  8142. HBViewerAutomation* self = findInstance(state);
  8143. if (!self) return 0;
  8144. if (self->isThreaded())
  8145. {
  8146. HBAutomationThread* threadp = (HBAutomationThread*)self;
  8147. return threadp->callMainFunction("SideBarButton");
  8148. }
  8149. S32 n = lua_gettop(state);
  8150. if (n == 0 || n > 4)
  8151. {
  8152. luaL_error(state, "%d arguments passed; expected 1 to 4.", n);
  8153. }
  8154. U32 number = luaL_checknumber(state, 1);
  8155. std::string icon, tooltip, command;
  8156. if (n > 1)
  8157. {
  8158. icon.assign(luaL_checkstring(state, 2));
  8159. if (!icon.empty() && n > 2)
  8160. {
  8161. command.assign(luaL_checkstring(state, 3));
  8162. if (n > 3)
  8163. {
  8164. tooltip.assign(luaL_checkstring(state, 4));
  8165. }
  8166. }
  8167. }
  8168. lua_pop(state, n);
  8169. U32 result = 0;
  8170. if (gLuaSideBarp)
  8171. {
  8172. result = gLuaSideBarp->setButton(number, icon, command, tooltip);
  8173. }
  8174. lua_pushinteger(state, result);
  8175. return 1;
  8176. }
  8177. //static
  8178. int HBViewerAutomation::sideBarButtonToggle(lua_State* state)
  8179. {
  8180. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  8181. HBViewerAutomation* self = findInstance(state);
  8182. if (!self) return 0;
  8183. if (self->isThreaded())
  8184. {
  8185. HBAutomationThread* threadp = (HBAutomationThread*)self;
  8186. return threadp->callMainFunction("SideBarButtonToggle");
  8187. }
  8188. S32 n = lua_gettop(state);
  8189. if (n == 0 || n > 2)
  8190. {
  8191. luaL_error(state, "%d arguments passed; expected 1 or 2.", n);
  8192. }
  8193. U32 number = luaL_checknumber(state, 1);
  8194. S32 toggle = -1;
  8195. if (n == 2)
  8196. {
  8197. int type = lua_type(state, 2);
  8198. if (type == LUA_TNIL || type == LUA_TSTRING)
  8199. {
  8200. LLControlVariable* control = NULL;
  8201. std::string control_name;
  8202. if (type == LUA_TSTRING)
  8203. {
  8204. control_name.assign(luaL_checkstring(state, 2));
  8205. }
  8206. if (!control_name.empty())
  8207. {
  8208. control = gSavedSettings.getControl(control_name.c_str());
  8209. if (!control)
  8210. {
  8211. control = gSavedPerAccountSettings.getControl(control_name.c_str());
  8212. }
  8213. if (!control)
  8214. {
  8215. luaL_error(state, "No setting named: %s",
  8216. control_name.c_str());
  8217. }
  8218. if (control->type() != TYPE_BOOLEAN)
  8219. {
  8220. luaL_error(state, "Setting '%s' is not of boolean type",
  8221. control_name.c_str());
  8222. }
  8223. }
  8224. if (gLuaSideBarp)
  8225. {
  8226. gLuaSideBarp->buttonSetControl(number, control);
  8227. }
  8228. }
  8229. else
  8230. {
  8231. toggle = lua_toboolean(state, 2) ? 1 : 0;
  8232. }
  8233. }
  8234. lua_pop(state, n);
  8235. if (gLuaSideBarp)
  8236. {
  8237. toggle = gLuaSideBarp->buttonToggle(number, toggle);
  8238. }
  8239. if (toggle == -1)
  8240. {
  8241. lua_pushnil(state);
  8242. }
  8243. else
  8244. {
  8245. lua_pushboolean(state, toggle);
  8246. }
  8247. return 1;
  8248. }
  8249. //static
  8250. int HBViewerAutomation::sideBarHide(lua_State* state)
  8251. {
  8252. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  8253. HBViewerAutomation* self = findInstance(state);
  8254. if (!self) return 0;
  8255. if (self->isThreaded())
  8256. {
  8257. HBAutomationThread* threadp = (HBAutomationThread*)self;
  8258. return threadp->callMainFunction("SideBarHide");
  8259. }
  8260. S32 n = lua_gettop(state);
  8261. if (n > 1)
  8262. {
  8263. luaL_error(state, "%d arguments passed; expected 0 or 1.", n);
  8264. }
  8265. bool hide = true;
  8266. if (n == 1)
  8267. {
  8268. hide = lua_toboolean(state, 1);
  8269. lua_pop(state, 1);
  8270. }
  8271. if (gLuaSideBarp)
  8272. {
  8273. gLuaSideBarp->setHidden(hide);
  8274. }
  8275. return 0;
  8276. }
  8277. //static
  8278. int HBViewerAutomation::sideBarHideOnRightClick(lua_State* state)
  8279. {
  8280. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  8281. HBViewerAutomation* self = findInstance(state);
  8282. if (!self) return 0;
  8283. if (self->isThreaded())
  8284. {
  8285. HBAutomationThread* threadp = (HBAutomationThread*)self;
  8286. return threadp->callMainFunction("SideBarHideOnRightClick");
  8287. }
  8288. S32 n = lua_gettop(state);
  8289. if (n > 1)
  8290. {
  8291. luaL_error(state, "%d arguments passed; expected 0 or 1.", n);
  8292. }
  8293. bool hide = true;
  8294. if (n == 1)
  8295. {
  8296. hide = lua_toboolean(state, 1);
  8297. lua_pop(state, 1);
  8298. }
  8299. if (gLuaSideBarp)
  8300. {
  8301. gLuaSideBarp->hideOnRightClick(hide);
  8302. }
  8303. return 0;
  8304. }
  8305. //static
  8306. int HBViewerAutomation::sideBarButtonHide(lua_State* state)
  8307. {
  8308. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  8309. HBViewerAutomation* self = findInstance(state);
  8310. if (!self) return 0;
  8311. if (self->isThreaded())
  8312. {
  8313. HBAutomationThread* threadp = (HBAutomationThread*)self;
  8314. return threadp->callMainFunction("SideBarButtonHide");
  8315. }
  8316. S32 n = lua_gettop(state);
  8317. if (n != 1 && n != 2)
  8318. {
  8319. luaL_error(state, "%d arguments passed; expected 1 or 2.", n);
  8320. }
  8321. U32 number = luaL_checknumber(state, 1);
  8322. bool hide = n < 2 || lua_toboolean(state, 2);
  8323. lua_pop(state, n);
  8324. if (gLuaSideBarp)
  8325. {
  8326. gLuaSideBarp->setButtonVisible(number, !hide);
  8327. }
  8328. return 0;
  8329. }
  8330. //static
  8331. int HBViewerAutomation::sideBarButtonDisable(lua_State* state)
  8332. {
  8333. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  8334. HBViewerAutomation* self = findInstance(state);
  8335. if (!self) return 0;
  8336. if (self->isThreaded())
  8337. {
  8338. HBAutomationThread* threadp = (HBAutomationThread*)self;
  8339. return threadp->callMainFunction("SideBarButtonDisable");
  8340. }
  8341. S32 n = lua_gettop(state);
  8342. if (n != 1 && n != 2)
  8343. {
  8344. luaL_error(state, "%d arguments passed; expected 1 or 2.", n);
  8345. }
  8346. U32 number = luaL_checknumber(state, 1);
  8347. bool disable = n < 2 || lua_toboolean(state, 2);
  8348. lua_pop(state, n);
  8349. if (gLuaSideBarp)
  8350. {
  8351. gLuaSideBarp->setButtonEnabled(number, !disable);
  8352. }
  8353. return 0;
  8354. }
  8355. //static
  8356. int HBViewerAutomation::luaPieMenuSlice(lua_State* state)
  8357. {
  8358. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  8359. HBViewerAutomation* self = findInstance(state);
  8360. if (!self) return 0;
  8361. if (self->isThreaded())
  8362. {
  8363. HBAutomationThread* threadp = (HBAutomationThread*)self;
  8364. return threadp->callMainFunction("LuaPieMenuSlice");
  8365. }
  8366. S32 n = lua_gettop(state);
  8367. if (n == 0 || n > 4)
  8368. {
  8369. luaL_error(state, "%d arguments passed; expected 1 to 4.", n);
  8370. }
  8371. S32 type = luaL_checknumber(state, 1);
  8372. U32 slice = 0;
  8373. std::string label, command;
  8374. if (n > 1)
  8375. {
  8376. slice = luaL_checknumber(state, 2);
  8377. if (slice && n > 2)
  8378. {
  8379. label.assign(luaL_checkstring(state, 3));
  8380. if (n > 3)
  8381. {
  8382. command.assign(luaL_checkstring(state, 4));
  8383. }
  8384. }
  8385. }
  8386. lua_pop(state, n);
  8387. if (gLuaPiep)
  8388. {
  8389. gLuaPiep->setSlice(type, slice, label, command);
  8390. }
  8391. return 0;
  8392. }
  8393. //static
  8394. int HBViewerAutomation::luaContextMenu(lua_State* state)
  8395. {
  8396. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  8397. HBViewerAutomation* self = findInstance(state);
  8398. if (!self) return 0;
  8399. if (self->isThreaded())
  8400. {
  8401. HBAutomationThread* threadp = (HBAutomationThread*)self;
  8402. return threadp->callMainFunction("LuaContextMenu");
  8403. }
  8404. S32 n = lua_gettop(state);
  8405. if (n == 0 || n > 4)
  8406. {
  8407. luaL_error(state, "%d arguments passed; expected 1 to 4.", n);
  8408. }
  8409. S32 id = luaL_checknumber(state, 1);
  8410. std::string cut_label, copy_label, paste_label;
  8411. if (n > 1)
  8412. {
  8413. cut_label = luaL_checkstring(state, 2);
  8414. if (n > 2)
  8415. {
  8416. copy_label.assign(luaL_checkstring(state, 3));
  8417. if (n > 3)
  8418. {
  8419. paste_label.assign(luaL_checkstring(state, 4));
  8420. }
  8421. }
  8422. }
  8423. lua_pop(state, n);
  8424. lua_pushboolean(state,
  8425. LLEditMenuHandler::setCustomMenu(id, cut_label, copy_label,
  8426. paste_label));
  8427. return 1;
  8428. }
  8429. //static
  8430. int HBViewerAutomation::pasteToContextHandler(lua_State* state)
  8431. {
  8432. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  8433. HBViewerAutomation* self = findInstance(state);
  8434. if (!self) return 0;
  8435. if (self->isThreaded())
  8436. {
  8437. HBAutomationThread* threadp = (HBAutomationThread*)self;
  8438. return threadp->callMainFunction("PasteToContextHandler");
  8439. }
  8440. S32 n = lua_gettop(state);
  8441. if (n != 1 && n != 2)
  8442. {
  8443. luaL_error(state, "%d arguments passed; expected 1 or 2.", n);
  8444. }
  8445. S32 id = luaL_checknumber(state, 1);
  8446. if (n > 1)
  8447. {
  8448. std::string text(luaL_checkstring(state, 2));
  8449. gClipboard.copyFromSubstring(utf8str_to_wstring(text), 0,
  8450. text.length());
  8451. }
  8452. lua_pop(state, n);
  8453. lua_pushboolean(state, LLEditMenuHandler::pasteTo(id));
  8454. return 1;
  8455. }
  8456. //static
  8457. int HBViewerAutomation::automationMessage(lua_State* state)
  8458. {
  8459. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  8460. HBViewerAutomation* self = findInstance(state);
  8461. if (!self) return 0;
  8462. S32 n = lua_gettop(state);
  8463. if (n != 1)
  8464. {
  8465. luaL_error(state, "%d arguments passed; expected 1.", n);
  8466. }
  8467. std::string text(luaL_checkstring(state, 1));
  8468. lua_pop(state, 1);
  8469. if (gAutomationp && gAutomationp->mHasOnAutomationMessage)
  8470. {
  8471. LL_DEBUGS("Lua") << "Invoking OnAutomationMessage Lua callback. text="
  8472. << text << LL_ENDL;
  8473. lua_getglobal(gAutomationp->mLuaState, "OnAutomationMessage");
  8474. lua_pushstring(gAutomationp->mLuaState, text.c_str());
  8475. gAutomationp->resetTimer();
  8476. if (lua_pcall(gAutomationp->mLuaState, 1, 0, 0) != LUA_OK)
  8477. {
  8478. gAutomationp->reportError();
  8479. }
  8480. }
  8481. return 0;
  8482. }
  8483. //static
  8484. int HBViewerAutomation::automationRequest(lua_State* state)
  8485. {
  8486. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  8487. HBViewerAutomation* self = findInstance(state);
  8488. if (!self) return 0;
  8489. S32 n = lua_gettop(state);
  8490. if (n != 1)
  8491. {
  8492. luaL_error(state, "%d arguments passed; expected 1.", n);
  8493. }
  8494. std::string request(luaL_checkstring(state, 1));
  8495. lua_pop(state, 1);
  8496. if (!gAutomationp || !gAutomationp->mHasOnAutomationRequest)
  8497. {
  8498. LL_DEBUGS("Lua") << "No OnAutomationRequest Lua callback. request="
  8499. << request << ". Returning an empty result string."
  8500. << LL_ENDL;
  8501. lua_pushliteral(state, "");
  8502. return 1;
  8503. }
  8504. LL_DEBUGS("Lua") << "Invoking OnAutomationRequest Lua callback. request="
  8505. << request << LL_ENDL;
  8506. lua_getglobal(gAutomationp->mLuaState, "OnAutomationRequest");
  8507. lua_pushstring(gAutomationp->mLuaState, request.c_str());
  8508. gAutomationp->resetTimer();
  8509. if (lua_pcall(gAutomationp->mLuaState, 1, 1, 0) != LUA_OK)
  8510. {
  8511. gAutomationp->reportError();
  8512. return 0;
  8513. }
  8514. if (lua_gettop(gAutomationp->mLuaState) == 0 ||
  8515. lua_type(gAutomationp->mLuaState, -1) != LUA_TSTRING)
  8516. {
  8517. lua_settop(gAutomationp->mLuaState, 0); // Sanitize stack by emptying it
  8518. lua_pushliteral(gAutomationp->mLuaState,
  8519. "OnAutomationRequest() Lua callback did not return a string");
  8520. gAutomationp->reportError();
  8521. return 0;
  8522. }
  8523. // Recover the result from the automation script stack...
  8524. std::string result(lua_tolstring(gAutomationp->mLuaState, -1, NULL));
  8525. lua_pop(gAutomationp->mLuaState, 1);
  8526. // ... and push it on our stack.
  8527. lua_pushstring(state, result.c_str());
  8528. return 1;
  8529. }
  8530. //static
  8531. int HBViewerAutomation::playUISound(lua_State* state)
  8532. {
  8533. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  8534. static const std::string valid_sounds = get_valid_sounds();
  8535. HBViewerAutomation* self = findInstance(state);
  8536. if (!self) return 0;
  8537. if (self->isThreaded())
  8538. {
  8539. HBAutomationThread* threadp = (HBAutomationThread*)self;
  8540. return threadp->callMainFunction("PlayUISound");
  8541. }
  8542. S32 n = lua_gettop(state);
  8543. if (n != 1 && n != 2)
  8544. {
  8545. luaL_error(state, "%d arguments passed; expected 1 or 2.", n);
  8546. }
  8547. std::string name(luaL_checkstring(state, 1));
  8548. name = "UISnd" + name;
  8549. if (valid_sounds.find(";" + name + ";") == std::string::npos)
  8550. {
  8551. llwarns << "No such UI sound name: " << name << llendl;
  8552. lua_pop(state, n);
  8553. return 0;
  8554. }
  8555. bool force = n >= 2 && lua_toboolean(state, 2);
  8556. lua_pop(state, n);
  8557. make_ui_sound(name.c_str(), force);
  8558. return 0;
  8559. }
  8560. //static
  8561. int HBViewerAutomation::renderDebugInfo(lua_State* state)
  8562. {
  8563. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  8564. HBViewerAutomation* self = findInstance(state);
  8565. if (!self) return 0;
  8566. if (self->isThreaded())
  8567. {
  8568. HBAutomationThread* threadp = (HBAutomationThread*)self;
  8569. return threadp->callMainFunction("RenderDebugInfo");
  8570. }
  8571. S32 n = lua_gettop(state);
  8572. if (n != 1)
  8573. {
  8574. luaL_error(state, "%d arguments passed; expected 1.", n);
  8575. }
  8576. S32 feature = luaL_checknumber(state, 1);
  8577. lua_pop(state, 1);
  8578. if (feature < 0 || feature > 32)
  8579. {
  8580. luaL_error(state,
  8581. "Invalid render debug feature index (valid range is 0 to 32");
  8582. }
  8583. if (feature)
  8584. {
  8585. gPipeline.setRenderDebugMask(1U << (feature - 1));
  8586. }
  8587. else
  8588. {
  8589. gPipeline.setRenderDebugMask(0);
  8590. }
  8591. return 0;
  8592. }
  8593. //static
  8594. int HBViewerAutomation::getDebugSetting(lua_State* state)
  8595. {
  8596. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  8597. HBViewerAutomation* self = findInstance(state);
  8598. if (!self) return 0;
  8599. if (self->isThreaded())
  8600. {
  8601. HBAutomationThread* threadp = (HBAutomationThread*)self;
  8602. return threadp->callMainFunction("GetDebugSetting");
  8603. }
  8604. S32 n = lua_gettop(state);
  8605. if (n != 1)
  8606. {
  8607. luaL_error(state, "%d arguments passed; expected 1.", n);
  8608. }
  8609. std::string name(luaL_checkstring(state, 1));
  8610. if (name.empty())
  8611. {
  8612. luaL_error(state, "Empty setting name");
  8613. }
  8614. lua_pop(state, 1);
  8615. // Note: as of Cool VL Viewer v1.28.2.72 & v1.30.0.0, commands sent via
  8616. // scripted objects (or via D-Bus, under Linux) are now forbidden access
  8617. // to debug settings, but the settings white lists have been removed (i.e.
  8618. // non-external scripts are granted full access to any valid debug
  8619. // setting).
  8620. if (self->mFromObjectId != gAgentID)
  8621. {
  8622. lua_pushnil(state);
  8623. return 1;
  8624. }
  8625. LLControlVariable* control = gSavedSettings.getControl(name.c_str());
  8626. if (!control)
  8627. {
  8628. control = gSavedPerAccountSettings.getControl(name.c_str());
  8629. }
  8630. if (!control)
  8631. {
  8632. control = gColors.getControl(name.c_str());
  8633. }
  8634. if (!control)
  8635. {
  8636. luaL_error(state, "No setting named: %s", name.c_str());
  8637. }
  8638. eControlType type = control->type();
  8639. switch (type)
  8640. {
  8641. case TYPE_U32:
  8642. case TYPE_S32:
  8643. lua_pushinteger(state, control->getValue().asInteger());
  8644. break;
  8645. case TYPE_F32:
  8646. lua_pushnumber(state, control->getValue().asReal());
  8647. break;
  8648. case TYPE_BOOLEAN:
  8649. lua_pushboolean(state, control->getValue().asBoolean());
  8650. break;
  8651. case TYPE_STRING:
  8652. lua_pushstring(state, control->getValue().asString().c_str());
  8653. break;
  8654. case TYPE_VEC3:
  8655. {
  8656. LLVector3 vec;
  8657. vec.setValue(control->getValue());
  8658. lua_pushnumber(state, vec.mV[0]);
  8659. lua_pushnumber(state, vec.mV[1]);
  8660. lua_pushnumber(state, vec.mV[2]);
  8661. n = 3;
  8662. break;
  8663. }
  8664. case TYPE_RECT:
  8665. {
  8666. LLRect r;
  8667. r.setValue(control->getValue());
  8668. lua_pushinteger(state, r.mLeft);
  8669. lua_pushinteger(state, r.mTop);
  8670. lua_pushinteger(state, r.mRight);
  8671. lua_pushinteger(state, r.mBottom);
  8672. n = 4;
  8673. break;
  8674. }
  8675. case TYPE_COL4:
  8676. {
  8677. LLColor4 color;
  8678. color.setValue(control->getValue());
  8679. lua_pushnumber(state, color.mV[0]);
  8680. lua_pushnumber(state, color.mV[1]);
  8681. lua_pushnumber(state, color.mV[2]);
  8682. lua_pushnumber(state, color.mV[3]);
  8683. n = 4;
  8684. break;
  8685. }
  8686. case TYPE_COL3:
  8687. {
  8688. LLColor3 color;
  8689. color.setValue(control->getValue());
  8690. lua_pushnumber(state, color.mV[0]);
  8691. lua_pushnumber(state, color.mV[1]);
  8692. lua_pushnumber(state, color.mV[2]);
  8693. n = 3;
  8694. break;
  8695. }
  8696. case TYPE_COL4U:
  8697. {
  8698. LLColor4U color;
  8699. color.setValue(control->getValue());
  8700. lua_pushinteger(state, color.mV[0]);
  8701. lua_pushinteger(state, color.mV[1]);
  8702. lua_pushinteger(state, color.mV[2]);
  8703. lua_pushinteger(state, color.mV[3]);
  8704. n = 4;
  8705. break;
  8706. }
  8707. default:
  8708. // Other setting types (TYPE_LLSD which is only used in a couple
  8709. // hidden settings, and TYPE_VEC3D which is not used at all) are
  8710. // unsupported for now.
  8711. lua_pushnil(state);
  8712. }
  8713. return n;
  8714. }
  8715. //static
  8716. int HBViewerAutomation::setDebugSetting(lua_State* state)
  8717. {
  8718. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  8719. HBViewerAutomation* self = findInstance(state);
  8720. if (!self) return 0;
  8721. if (self->isThreaded())
  8722. {
  8723. HBAutomationThread* threadp = (HBAutomationThread*)self;
  8724. return threadp->callMainFunction("SetDebugSetting");
  8725. }
  8726. S32 n = lua_gettop(state);
  8727. if (!n)
  8728. {
  8729. luaL_error(state, "Missing arguments.", n);
  8730. }
  8731. std::string name(luaL_checkstring(state, 1));
  8732. if (name.empty())
  8733. {
  8734. luaL_error(state, "Empty setting name");
  8735. }
  8736. // Note: as of Cool VL Viewer v1.28.2.72 & v1.30.0.0, commands sent via
  8737. // scripted objects (or via D-Bus, under Linux) are now forbidden access
  8738. // to debug settings, but the settings white lists have been removed (i.e.
  8739. // non-external scripts are granted full access to any valid debug
  8740. // setting).
  8741. if (self->mFromObjectId != gAgentID)
  8742. {
  8743. lua_pop(state, n);
  8744. lua_pushnil(state);
  8745. return 1;
  8746. }
  8747. LLControlVariable* control = gSavedSettings.getControl(name.c_str());
  8748. if (!control)
  8749. {
  8750. control = gSavedPerAccountSettings.getControl(name.c_str());
  8751. }
  8752. if (!control)
  8753. {
  8754. control = gColors.getControl(name.c_str());
  8755. }
  8756. if (!control)
  8757. {
  8758. luaL_error(state, "No setting named: %s", name.c_str());
  8759. }
  8760. if (control->isHiddenFromUser())
  8761. {
  8762. luaL_error(state,
  8763. "Cannot set '%s' which is reserved for internal viewer code use only",
  8764. name.c_str());
  8765. }
  8766. bool success;
  8767. eControlType type = control->type();
  8768. if (n == 1)
  8769. {
  8770. success = type != TYPE_LLSD && type != TYPE_VEC3D;
  8771. if (success)
  8772. {
  8773. control->resetToDefault();
  8774. }
  8775. }
  8776. else
  8777. {
  8778. LLSD value;
  8779. switch (type)
  8780. {
  8781. case TYPE_U32:
  8782. case TYPE_S32:
  8783. success = n == 2;
  8784. if (success)
  8785. {
  8786. value = LLSD::Integer(luaL_checknumber(state, 2));
  8787. }
  8788. break;
  8789. case TYPE_F32:
  8790. success = n == 2;
  8791. if (success)
  8792. {
  8793. value = LLSD::Real(luaL_checknumber(state, 2));
  8794. }
  8795. break;
  8796. case TYPE_BOOLEAN:
  8797. success = n == 2;
  8798. if (success)
  8799. {
  8800. value = LLSD::Boolean(lua_toboolean(state, 2));
  8801. }
  8802. break;
  8803. case TYPE_STRING:
  8804. success = n == 2;
  8805. if (success)
  8806. {
  8807. value = LLSD::String(luaL_checkstring(state, 2));
  8808. }
  8809. break;
  8810. case TYPE_VEC3:
  8811. success = n == 4;
  8812. if (success)
  8813. {
  8814. value = LLVector3(luaL_checknumber(state, 2),
  8815. luaL_checknumber(state, 3),
  8816. luaL_checknumber(state, 4)).getValue();
  8817. }
  8818. break;
  8819. case TYPE_RECT:
  8820. success = n == 5;
  8821. if (success)
  8822. {
  8823. value = LLRect(S32(luaL_checknumber(state, 2)),
  8824. S32(luaL_checknumber(state, 3)),
  8825. S32(luaL_checknumber(state, 4)),
  8826. S32(luaL_checknumber(state, 5))).getValue();
  8827. }
  8828. break;
  8829. case TYPE_COL4:
  8830. success = n == 4 || n == 5;
  8831. if (success)
  8832. {
  8833. F32 r = luaL_checknumber(state, 2);
  8834. F32 g = luaL_checknumber(state, 3);
  8835. F32 b = luaL_checknumber(state, 4);
  8836. F32 a = 1.f;
  8837. if (n == 5)
  8838. {
  8839. a = luaL_checknumber(state, 5);
  8840. }
  8841. if (r >= 0.f && g >= 0.f && b >= 0.f && a >= 0.f &&
  8842. r <= 1.f && g <= 1.f && b <= 1.f && a <= 1.f)
  8843. {
  8844. value = LLColor4(r, g, b, a).getValue();
  8845. }
  8846. else
  8847. {
  8848. success = false;
  8849. }
  8850. }
  8851. break;
  8852. case TYPE_COL3:
  8853. success = n == 4;
  8854. if (success)
  8855. {
  8856. F32 r = luaL_checknumber(state, 2);
  8857. F32 g = luaL_checknumber(state, 3);
  8858. F32 b = luaL_checknumber(state, 4);
  8859. if (r >= 0.f && g >= 0.f && b >= 0.f &&
  8860. r <= 1.f && g <= 1.f && b <= 1.f)
  8861. {
  8862. value = LLColor3(r, g, b).getValue();
  8863. }
  8864. else
  8865. {
  8866. success = false;
  8867. }
  8868. }
  8869. break;
  8870. case TYPE_COL4U:
  8871. success = n == 4 || n == 5;
  8872. if (success)
  8873. {
  8874. F32 r = luaL_checknumber(state, 2);
  8875. F32 g = luaL_checknumber(state, 3);
  8876. F32 b = luaL_checknumber(state, 4);
  8877. F32 a = 255.f;
  8878. if (n == 5)
  8879. {
  8880. a = luaL_checknumber(state, 5);
  8881. }
  8882. if (r >= 0.f && g >= 0.f && b >= 0.f && a >= 0.f &&
  8883. r <= 255.f && g <= 255.f && b <= 255.f && a <= 255.f)
  8884. {
  8885. value = LLColor4U((U8)r, (U8)g, (U8)b,
  8886. (U8)a).getValue();
  8887. }
  8888. }
  8889. break;
  8890. default:
  8891. // Other setting types (TYPE_LLSD which is only used in a
  8892. // couple hidden settings, and TYPE_VEC3D which is not used at
  8893. // all) are unsupported for now.
  8894. success = false;
  8895. }
  8896. if (success)
  8897. {
  8898. control->setValue(value);
  8899. }
  8900. }
  8901. lua_pop(state, n);
  8902. lua_pushboolean(state, success);
  8903. return 1;
  8904. }
  8905. //static
  8906. bool HBViewerAutomation::serializeTable(lua_State* state, S32 stack_level,
  8907. std::string* output)
  8908. {
  8909. if (!state || lua_type(state, stack_level) != LUA_TTABLE)
  8910. {
  8911. return false;
  8912. }
  8913. std::string data, value;
  8914. lua_pushnil(state);
  8915. while (lua_next(state, stack_level))
  8916. {
  8917. if (data.empty())
  8918. {
  8919. data = "{[";
  8920. }
  8921. else
  8922. {
  8923. data += ";[";
  8924. }
  8925. int key_type = lua_type(state, -2);
  8926. switch (key_type)
  8927. {
  8928. case LUA_TNUMBER:
  8929. value = llformat(LUA_NUMBER_FMT, lua_tonumber(state, -2));
  8930. break;
  8931. case LUA_TSTRING:
  8932. value = lua_tostring(state, -2);
  8933. LLStringUtil::replaceString(value, "\"", "\\\"");
  8934. value = "\"" + value + "\"";
  8935. break;
  8936. case LUA_TBOOLEAN:
  8937. case LUA_TNIL:
  8938. default:
  8939. lua_pop(state, 2);
  8940. return false;
  8941. }
  8942. data += value + "]=";
  8943. int value_type = lua_type(state, -1);
  8944. switch (value_type)
  8945. {
  8946. case LUA_TNIL:
  8947. value = "nil";
  8948. break;
  8949. case LUA_TBOOLEAN:
  8950. value = lua_toboolean(state, -1) ? "true" : "false";
  8951. break;
  8952. case LUA_TNUMBER:
  8953. value = llformat(LUA_NUMBER_FMT, lua_tonumber(state, -1));
  8954. break;
  8955. case LUA_TSTRING:
  8956. value = lua_tostring(state, -1);
  8957. LLStringUtil::replaceString(value, "\"", "\\\"");
  8958. value = "\"" + value + "\"";
  8959. break;
  8960. default:
  8961. lua_pop(state, 2);
  8962. return false;
  8963. }
  8964. data += value;
  8965. lua_pop(state, 1);
  8966. }
  8967. lua_pop(state, 1);
  8968. if (data.empty())
  8969. {
  8970. data = "{}";
  8971. }
  8972. else
  8973. {
  8974. data += "}";
  8975. }
  8976. LL_DEBUGS("Lua") << "Resulting Lua code (table): " << data << LL_ENDL;
  8977. if (output)
  8978. {
  8979. *output = data;
  8980. }
  8981. else
  8982. {
  8983. data = "base64:" + LLBase64::encode(data);
  8984. lua_pushstring(state, data.c_str());
  8985. }
  8986. return true;
  8987. }
  8988. //static
  8989. bool HBViewerAutomation::deserializeTable(lua_State* state, std::string data)
  8990. {
  8991. if (!state || data.compare(0, 7, "base64:") != 0)
  8992. {
  8993. return false;
  8994. }
  8995. data = LLBase64::decode(data.substr(7).c_str());
  8996. LL_DEBUGS("Lua") << "Decoded Base64 data: " << data << LL_ENDL;
  8997. data = "_V_SETTINGS=" + data;
  8998. if (luaL_dostring(state, data.c_str()))
  8999. {
  9000. return false;
  9001. }
  9002. lua_getglobal(state, "_V_SETTINGS");
  9003. lua_pushnil(state);
  9004. lua_setglobal(state, "_V_SETTINGS");
  9005. return true;
  9006. }
  9007. //static
  9008. int HBViewerAutomation::getGlobalData(lua_State* state)
  9009. {
  9010. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  9011. if (!state) return 0; // Paranoia
  9012. S32 n = lua_gettop(state);
  9013. if (n)
  9014. {
  9015. luaL_error(state, "%d arguments passed; expected 0.", n);
  9016. }
  9017. std::string data = gSavedSettings.getString("LuaSessionData");
  9018. if (!deserializeTable(state, data))
  9019. {
  9020. lua_pushstring(state, data.c_str());
  9021. }
  9022. return 1;
  9023. }
  9024. //static
  9025. int HBViewerAutomation::setGlobalData(lua_State* state)
  9026. {
  9027. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  9028. if (!state) return 0; // Paranoia
  9029. S32 n = lua_gettop(state);
  9030. if (n != 1)
  9031. {
  9032. luaL_error(state, "%d arguments passed; expected 1.", n);
  9033. }
  9034. if (lua_type(state, 1) == LUA_TTABLE && !serializeTable(state))
  9035. {
  9036. luaL_error(state, "Unsupported table format");
  9037. }
  9038. std::string data(luaL_checkstring(state, 1));
  9039. lua_pop(state, 1);
  9040. gSavedSettings.setString("LuaSessionData", data);
  9041. return 0;
  9042. }
  9043. //static
  9044. int HBViewerAutomation::getPerAccountData(lua_State* state)
  9045. {
  9046. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  9047. if (!state) return 0; // Paranoia
  9048. S32 n = lua_gettop(state);
  9049. if (n)
  9050. {
  9051. luaL_error(state, "%d arguments passed; expected 0.", n);
  9052. }
  9053. std::string data = gSavedPerAccountSettings.getString("LuaUserData");
  9054. if (!deserializeTable(state, data))
  9055. {
  9056. lua_pushstring(state, data.c_str());
  9057. }
  9058. return 1;
  9059. }
  9060. //static
  9061. int HBViewerAutomation::setPerAccountData(lua_State* state)
  9062. {
  9063. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  9064. if (!state) return 0; // Paranoia
  9065. S32 n = lua_gettop(state);
  9066. if (n != 1)
  9067. {
  9068. luaL_error(state, "%d arguments passed; expected 1.", n);
  9069. }
  9070. if (lua_type(state, 1) == LUA_TTABLE && !serializeTable(state))
  9071. {
  9072. luaL_error(state, "Unsupported table format");
  9073. }
  9074. std::string data(luaL_checkstring(state, 1));
  9075. lua_pop(state, 1);
  9076. gSavedPerAccountSettings.setString("LuaUserData", data);
  9077. return 0;
  9078. }
  9079. //static
  9080. int HBViewerAutomation::getSourceFileName(lua_State* state)
  9081. {
  9082. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  9083. HBViewerAutomation* self = findInstance(state);
  9084. if (!self) return 0;
  9085. S32 n = lua_gettop(state);
  9086. if (n)
  9087. {
  9088. luaL_error(state, "%d arguments passed; expected 0.", n);
  9089. }
  9090. if (self->mSourceFileName.empty())
  9091. {
  9092. lua_pushnil(state);
  9093. return 1;
  9094. }
  9095. lua_pushstring(state, self->mSourceFileName.c_str());
  9096. return 1;
  9097. }
  9098. //static
  9099. int HBViewerAutomation::getWatchdogState(lua_State* state)
  9100. {
  9101. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  9102. HBViewerAutomation* self = findInstance(state);
  9103. if (!self) return 0;
  9104. S32 n = lua_gettop(state);
  9105. if (n)
  9106. {
  9107. luaL_error(state, "%d arguments passed; expected 0.", n);
  9108. }
  9109. lua_pushnumber(state, self->mWatchdogTimer.getRemainingTimeF64());
  9110. lua_pushnumber(state, self->mWatchdogTimer.getElapsedTimeF64());
  9111. return 2;
  9112. }
  9113. //static
  9114. int HBViewerAutomation::getFrameTimeSeconds(lua_State* state)
  9115. {
  9116. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  9117. if (!state) return 0; // Paranoia
  9118. S32 n = lua_gettop(state);
  9119. if (n)
  9120. {
  9121. luaL_error(state, "%d arguments passed; expected 0.", n);
  9122. }
  9123. lua_pushnumber(state, gFrameTimeSeconds);
  9124. return 1;
  9125. }
  9126. //static
  9127. int HBViewerAutomation::getTimeStamp(lua_State* state)
  9128. {
  9129. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  9130. HBViewerAutomation* self = findInstance(state);
  9131. if (!self) return 0;
  9132. if (self->isThreaded())
  9133. {
  9134. HBAutomationThread* threadp = (HBAutomationThread*)self;
  9135. return threadp->callMainFunction("GetTimeStamp");
  9136. }
  9137. S32 n = lua_gettop(state);
  9138. if (n > 2)
  9139. {
  9140. luaL_error(state, "%d arguments passed; expected 0 to 2.", n);
  9141. }
  9142. S32 time_zone = 0; // Default to UTC
  9143. if (n)
  9144. {
  9145. time_zone = luaL_checknumber(state, 1);
  9146. }
  9147. std::string time_format;
  9148. if (n > 1)
  9149. {
  9150. time_format.assign(luaL_checkstring(state, 2));
  9151. }
  9152. else
  9153. {
  9154. time_format = gSavedSettings.getString("ShortDateFormat") + " ";
  9155. time_format += gSavedSettings.getString("ShortTimeFormat");
  9156. }
  9157. if (n)
  9158. {
  9159. lua_pop(state, n);
  9160. }
  9161. // Correct the UTC time, adding the time zone offset
  9162. time_t tz_time = time_corrected() + time_zone * 3600;
  9163. struct tm* internal_time = utc_time_to_tm(tz_time);
  9164. std::string timestamp;
  9165. timeStructToFormattedString(internal_time, time_format, timestamp);
  9166. timestamp += " UTC";
  9167. if (time_zone != 0)
  9168. {
  9169. timestamp += llformat("%+d", time_zone);
  9170. }
  9171. lua_pushstring(state, timestamp.c_str());
  9172. return 1;
  9173. }
  9174. //static
  9175. int HBViewerAutomation::getClipBoardString(lua_State* state)
  9176. {
  9177. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  9178. HBViewerAutomation* self = findInstance(state);
  9179. if (!self) return 0;
  9180. if (self->isThreaded())
  9181. {
  9182. HBAutomationThread* threadp = (HBAutomationThread*)self;
  9183. return threadp->callMainFunction("GetClipBoardString");
  9184. }
  9185. S32 n = lua_gettop(state);
  9186. if (n > 1)
  9187. {
  9188. luaL_error(state, "%d arguments passed; expected 0 or 1.", n);
  9189. }
  9190. S32 clipboard = 0; // Default to viewer clipboard
  9191. if (n)
  9192. {
  9193. clipboard = luaL_checknumber(state, 1);
  9194. lua_pop(state, 1);
  9195. }
  9196. LLWString wtext;
  9197. switch (clipboard)
  9198. {
  9199. case 0:
  9200. wtext = gClipboard.getClipBoardString();
  9201. break;
  9202. case 1:
  9203. if (gWindowp)
  9204. {
  9205. gWindowp->pasteTextFromClipboard(wtext);
  9206. }
  9207. break;
  9208. case 2:
  9209. if (gWindowp)
  9210. {
  9211. gWindowp->pasteTextFromPrimary(wtext);
  9212. }
  9213. break;
  9214. default:
  9215. luaL_error(state,
  9216. "Invalid clipboard type %d (valid types are 0 to 2).",
  9217. n);
  9218. }
  9219. lua_pushstring(state, wstring_to_utf8str(wtext).c_str());
  9220. return 1;
  9221. }
  9222. //static
  9223. int HBViewerAutomation::setClipBoardString(lua_State* state)
  9224. {
  9225. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  9226. HBViewerAutomation* self = findInstance(state);
  9227. if (!self) return 0;
  9228. if (self->isThreaded())
  9229. {
  9230. HBAutomationThread* threadp = (HBAutomationThread*)self;
  9231. return threadp->callMainFunction("SetClipBoardString");
  9232. }
  9233. S32 n = lua_gettop(state);
  9234. if (n > 1)
  9235. {
  9236. luaL_error(state, "%d arguments passed; expected 0 or 1.", n);
  9237. }
  9238. std::string text;
  9239. if (n)
  9240. {
  9241. text = luaL_checkstring(state, 1);
  9242. lua_pop(state, 1);
  9243. }
  9244. gClipboard.copyFromSubstring(utf8str_to_wstring(text), 0, text.length());
  9245. return 0;
  9246. }
  9247. //static
  9248. const LLUUID& HBViewerAutomation::getInventoryObjectId(const std::string& name,
  9249. bool& is_category)
  9250. {
  9251. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  9252. if (name.empty() || name == "|")
  9253. {
  9254. is_category = true;
  9255. return gInventory.getRootFolderID();
  9256. }
  9257. LLViewerInventoryItem* item;
  9258. LLViewerInventoryCategory* cat;
  9259. // First check if the passed string is a valid object inventory Id
  9260. if (LLUUID::validate(name))
  9261. {
  9262. LLUUID inv_obj_id(name);
  9263. cat = gInventory.getCategory(inv_obj_id);
  9264. if (cat)
  9265. {
  9266. LL_DEBUGS("Lua") << "Found an inventory category for Id: "
  9267. << inv_obj_id << " - Name: " << cat->getName()
  9268. << LL_ENDL;
  9269. is_category = true;
  9270. return cat->getUUID();
  9271. }
  9272. item = gInventory.getItem(inv_obj_id);
  9273. if (item)
  9274. {
  9275. LL_DEBUGS("Lua") << "Found an inventory item for Id: "
  9276. << inv_obj_id << " - Name: " << item->getName()
  9277. << LL_ENDL;
  9278. is_category = false;
  9279. return item->getUUID();
  9280. }
  9281. }
  9282. // Not an UUID, so split the string into path elements
  9283. std::string item_name = name;
  9284. std::deque<std::string> path;
  9285. size_t i;
  9286. std::string temp;
  9287. while ((i = item_name.find('|')) != std::string::npos)
  9288. {
  9289. temp = item_name.substr(0, i);
  9290. item_name = item_name.substr(i + 1);
  9291. // temp is empty when 2+ successive '|' exist in path, or when one is
  9292. // leading the full path. In both cases, skip the empty element.
  9293. if (!temp.empty())
  9294. {
  9295. LL_DEBUGS("Lua") << "Adding name to path: " << temp << LL_ENDL;
  9296. path.emplace_back(temp);
  9297. }
  9298. }
  9299. // item_name is empty when a '|' is trailing in path (in which case the
  9300. // empty string shall not be added to the path elements queue).
  9301. if (!item_name.empty())
  9302. {
  9303. LL_DEBUGS("Lua") << "Adding name to path: " << item_name << LL_ENDL;
  9304. path.emplace_back(item_name);
  9305. }
  9306. // Search for a matching inventory object
  9307. const LLUUID* cat_id = &gInventory.getRootFolderID();
  9308. LLInventoryModel::cat_array_t* cats;
  9309. LLInventoryModel::item_array_t* items;
  9310. bool last_name = false;
  9311. while (!last_name)
  9312. {
  9313. item_name = path.front();
  9314. path.pop_front();
  9315. last_name = path.empty();
  9316. gInventory.getDirectDescendentsOf(*cat_id, cats, items);
  9317. item = NULL;
  9318. cat = NULL;
  9319. if (last_name)
  9320. {
  9321. for (S32 i = 0, count = items->size(); i < count; ++i)
  9322. {
  9323. item = (*items)[i];
  9324. if (!item) continue; // Paranoia
  9325. if (item->getName() == item_name)
  9326. {
  9327. LL_DEBUGS("Lua") << "Found matching item name: "
  9328. << item_name << " - Returning item Id: "
  9329. << item->getUUID() << LL_ENDL;
  9330. is_category = false;
  9331. return item->getUUID();
  9332. }
  9333. }
  9334. }
  9335. for (S32 i = 0, count = cats->size(); i < count; ++i)
  9336. {
  9337. cat = (*cats)[i];
  9338. if (!cat) continue; // Paranoia
  9339. if (cat->getName() == item_name)
  9340. {
  9341. LL_DEBUGS("Lua") << "Found matching category name: "
  9342. << item_name << LL_ENDL;
  9343. if (last_name)
  9344. {
  9345. LL_DEBUGS("Lua") << "Returning category Id: "
  9346. << cat->getUUID() << LL_ENDL;
  9347. is_category = true;
  9348. return cat->getUUID();
  9349. }
  9350. break;
  9351. }
  9352. cat = NULL;
  9353. }
  9354. if (!cat)
  9355. {
  9356. break;
  9357. }
  9358. cat_id = &cat->getUUID();
  9359. }
  9360. is_category = false;
  9361. return LLUUID::null;
  9362. }
  9363. //static
  9364. int HBViewerAutomation::findInventoryObject(lua_State* state)
  9365. {
  9366. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  9367. HBViewerAutomation* self = findInstance(state);
  9368. if (!self) return 0;
  9369. if (self->isThreaded())
  9370. {
  9371. HBAutomationThread* threadp = (HBAutomationThread*)self;
  9372. return threadp->callMainFunction("FindInventoryObject");
  9373. }
  9374. S32 n = lua_gettop(state);
  9375. if (n != 1)
  9376. {
  9377. luaL_error(state, "%d arguments passed; expected 1.", n);
  9378. }
  9379. std::string obj_name(luaL_checkstring(state, 1));
  9380. if (obj_name.empty())
  9381. {
  9382. luaL_error(state, "Empty inventory object path name");
  9383. }
  9384. lua_pop(state, 1);
  9385. bool is_category = false;
  9386. const LLUUID& obj_id = getInventoryObjectId(obj_name, is_category);
  9387. bool export_support = gAgent.regionHasExportPermSupport();
  9388. bool copy_ok = false;
  9389. bool mod_ok = false;
  9390. bool xfer_ok = false;
  9391. bool export_ok = false;
  9392. S32 type = LLAssetType::AT_NONE;
  9393. if (is_category)
  9394. {
  9395. LLViewerInventoryCategory* cat = gInventory.getCategory(obj_id);
  9396. if (cat)
  9397. {
  9398. obj_name = cat->getName();
  9399. }
  9400. type = LLAssetType::AT_CATEGORY;
  9401. }
  9402. else if (obj_id.notNull())
  9403. {
  9404. LLViewerInventoryItem* itemp = gInventory.getItem(obj_id);
  9405. if (itemp)
  9406. {
  9407. type = itemp->getType();
  9408. obj_name = itemp->getName();
  9409. const LLPermissions& perms = itemp->getPermissions();
  9410. copy_ok = perms.allowCopyBy(gAgentID);
  9411. mod_ok = perms.allowModifyBy(gAgentID);
  9412. xfer_ok = perms.allowTransferBy(gAgentID);
  9413. export_ok = export_support &&
  9414. perms.allowExportBy(gAgentID, ep_export_bit);
  9415. }
  9416. }
  9417. lua_newtable(state);
  9418. lua_pushliteral(state, "id");
  9419. lua_pushstring(state, obj_id.asString().c_str());
  9420. lua_rawset(state, -3);
  9421. lua_pushliteral(state, "name");
  9422. lua_pushstring(state, obj_name.c_str());
  9423. lua_rawset(state, -3);
  9424. lua_pushliteral(state, "type");
  9425. lua_pushinteger(state, type);
  9426. lua_rawset(state, -3);
  9427. lua_pushliteral(state, "copy_ok");
  9428. lua_pushboolean(state, copy_ok);
  9429. lua_rawset(state, -3);
  9430. lua_pushliteral(state, "mod_ok");
  9431. lua_pushboolean(state, mod_ok);
  9432. lua_rawset(state, -3);
  9433. lua_pushliteral(state, "xfer_ok");
  9434. lua_pushboolean(state, xfer_ok);
  9435. lua_rawset(state, -3);
  9436. if (!is_category && export_support)
  9437. {
  9438. lua_pushliteral(state, "export_ok");
  9439. lua_pushboolean(state, export_ok);
  9440. lua_rawset(state, -3);
  9441. }
  9442. return 1;
  9443. }
  9444. //static
  9445. int HBViewerAutomation::giveInventory(lua_State* state)
  9446. {
  9447. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  9448. HBViewerAutomation* self = findInstance(state);
  9449. if (!self) return 0;
  9450. if (self->isThreaded())
  9451. {
  9452. HBAutomationThread* threadp = (HBAutomationThread*)self;
  9453. return threadp->callMainFunction("GiveInventory");
  9454. }
  9455. S32 n = lua_gettop(state);
  9456. if (n != 2)
  9457. {
  9458. luaL_error(state, "%d arguments passed; expected 2.", n);
  9459. }
  9460. LLUUID avatar_id(luaL_checkstring(state, 1), false);
  9461. std::string item_name(luaL_checkstring(state, 2));
  9462. lua_pop(state, 2);
  9463. bool success = false;
  9464. if (avatar_id.notNull())
  9465. {
  9466. bool is_category = false;
  9467. const LLUUID& inv_obj_id = getInventoryObjectId(item_name,
  9468. is_category);
  9469. if (inv_obj_id.notNull())
  9470. {
  9471. if (is_category)
  9472. {
  9473. LLViewerInventoryCategory* cat =
  9474. gInventory.getCategory(inv_obj_id);
  9475. if (cat)
  9476. {
  9477. LL_DEBUGS("Lua") << "avatar_id=" << avatar_id
  9478. << " - cat_id=" << cat->getUUID()
  9479. << LL_ENDL;
  9480. LLToolDragAndDrop::giveInventoryCategory(avatar_id, cat);
  9481. success = true;
  9482. }
  9483. }
  9484. else
  9485. {
  9486. LLViewerInventoryItem* item = gInventory.getItem(inv_obj_id);
  9487. if (item)
  9488. {
  9489. LL_DEBUGS("Lua") << "avatar_id=" << avatar_id
  9490. << " - item_id=" << item->getUUID()
  9491. << LL_ENDL;
  9492. LLToolDragAndDrop::giveInventory(avatar_id, item);
  9493. success = true;
  9494. }
  9495. }
  9496. }
  9497. }
  9498. lua_pushboolean(state, success);
  9499. return 1;
  9500. }
  9501. //static
  9502. int HBViewerAutomation::makeInventoryLink(lua_State* state)
  9503. {
  9504. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  9505. HBViewerAutomation* self = findInstance(state);
  9506. if (!self) return 0;
  9507. if (self->isThreaded())
  9508. {
  9509. HBAutomationThread* threadp = (HBAutomationThread*)self;
  9510. return threadp->callMainFunction("MakeInventoryLink");
  9511. }
  9512. S32 n = lua_gettop(state);
  9513. if (n != 2)
  9514. {
  9515. luaL_error(state, "%d arguments passed; expected 2.", n);
  9516. }
  9517. std::string item_path(luaL_checkstring(state, 1));
  9518. if (item_path.empty())
  9519. {
  9520. luaL_error(state, "Empty item name");
  9521. }
  9522. std::string link_cat_path(luaL_checkstring(state, 2));
  9523. lua_pop(state, 2);
  9524. bool success = false;
  9525. bool is_category = false;
  9526. const LLUUID& item_id = getInventoryObjectId(item_path, is_category);
  9527. if (!is_category && item_id.notNull())
  9528. {
  9529. LLUUID cat_id;
  9530. if (link_cat_path.empty())
  9531. {
  9532. cat_id = gInventory.getRootFolderID();
  9533. }
  9534. else
  9535. {
  9536. cat_id = getInventoryObjectId(link_cat_path, is_category);
  9537. if (!is_category || gInventory.isInTrash(cat_id) ||
  9538. gInventory.isInMarketPlace(cat_id))
  9539. {
  9540. cat_id.setNull();
  9541. }
  9542. }
  9543. if (cat_id.notNull())
  9544. {
  9545. link_inventory_object(cat_id, item_id);
  9546. success = true;
  9547. }
  9548. }
  9549. lua_pushboolean(state, success);
  9550. return 1;
  9551. }
  9552. //static
  9553. int HBViewerAutomation::deleteInventoryLink(lua_State* state)
  9554. {
  9555. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  9556. HBViewerAutomation* self = findInstance(state);
  9557. if (!self) return 0;
  9558. if (self->isThreaded())
  9559. {
  9560. HBAutomationThread* threadp = (HBAutomationThread*)self;
  9561. return threadp->callMainFunction("DeleteInventoryLink");
  9562. }
  9563. S32 n = lua_gettop(state);
  9564. if (n != 1)
  9565. {
  9566. luaL_error(state, "%d arguments passed; expected 1.", n);
  9567. }
  9568. std::string link_path(luaL_checkstring(state, 1));
  9569. if (link_path.empty())
  9570. {
  9571. luaL_error(state, "Empty link name");
  9572. }
  9573. lua_pop(state, 1);
  9574. bool success = false;
  9575. bool is_category = false;
  9576. const LLUUID& item_id = getInventoryObjectId(link_path, is_category);
  9577. if (!is_category && item_id.notNull())
  9578. {
  9579. LLViewerInventoryItem* item = gInventory.getItem(item_id);
  9580. if (item && item->getIsLinkType() && !gInventory.isInTrash(item_id) &&
  9581. !gInventory.isInMarketPlace(item_id))
  9582. {
  9583. remove_inventory_item(item_id);
  9584. success = true;
  9585. }
  9586. }
  9587. lua_pushboolean(state, success);
  9588. return 1;
  9589. }
  9590. //static
  9591. int HBViewerAutomation::newInventoryFolder(lua_State* state)
  9592. {
  9593. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  9594. HBViewerAutomation* self = findInstance(state);
  9595. if (!self) return 0;
  9596. if (self->isThreaded())
  9597. {
  9598. HBAutomationThread* threadp = (HBAutomationThread*)self;
  9599. return threadp->callMainFunction("NewInventoryFolder");
  9600. }
  9601. S32 n = lua_gettop(state);
  9602. if (n != 2)
  9603. {
  9604. luaL_error(state, "%d arguments passed; expected 2.", n);
  9605. }
  9606. std::string folder_path(luaL_checkstring(state, 1));
  9607. std::string folder_name(luaL_checkstring(state, 2));
  9608. lua_pop(state, 2);
  9609. LLUUID cat_id;
  9610. if (folder_path.empty())
  9611. {
  9612. cat_id = gInventory.getRootFolderID();
  9613. }
  9614. else
  9615. {
  9616. bool is_category = false;
  9617. cat_id = getInventoryObjectId(folder_path, is_category);
  9618. if (!is_category ||
  9619. // Forbid to make a folder in trash or market place.
  9620. gInventory.isInTrash(cat_id) || gInventory.isInMarketPlace(cat_id))
  9621. {
  9622. cat_id.setNull();
  9623. }
  9624. }
  9625. // Verify that the folder name is valid. Skip folder creation if not.
  9626. std::string tmp = folder_name;
  9627. LLStringFn::replace_nonprintable_and_pipe_in_ascii(tmp, LL_UNKNOWN_CHAR);
  9628. if (tmp != folder_name)
  9629. {
  9630. cat_id.setNull();
  9631. }
  9632. if (cat_id.notNull())
  9633. {
  9634. cat_id = gInventory.createCategoryUDP(cat_id, LLFolderType::FT_NONE,
  9635. folder_name);
  9636. }
  9637. lua_pushstring(state, cat_id.asString().c_str());
  9638. return 1;
  9639. }
  9640. //static
  9641. int HBViewerAutomation::listInventoryFolder(lua_State* state)
  9642. {
  9643. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  9644. HBViewerAutomation* self = findInstance(state);
  9645. if (!self) return 0;
  9646. if (self->isThreaded())
  9647. {
  9648. HBAutomationThread* threadp = (HBAutomationThread*)self;
  9649. return threadp->callMainFunction("ListInventoryFolder");
  9650. }
  9651. S32 n = lua_gettop(state);
  9652. if (n != 1)
  9653. {
  9654. luaL_error(state, "%d arguments passed; expected 1.", n);
  9655. }
  9656. std::string folder_path(luaL_checkstring(state, 1));
  9657. lua_pop(state, 1);
  9658. LLUUID cat_id;
  9659. if (folder_path.empty())
  9660. {
  9661. cat_id = gInventory.getRootFolderID();
  9662. }
  9663. else
  9664. {
  9665. bool is_category = false;
  9666. cat_id = getInventoryObjectId(folder_path, is_category);
  9667. if (!is_category)
  9668. {
  9669. cat_id.setNull();
  9670. }
  9671. }
  9672. if (cat_id.isNull())
  9673. {
  9674. lua_pushnil(state);
  9675. return 1;
  9676. }
  9677. LLInventoryModel::cat_array_t* cats;
  9678. LLInventoryModel::item_array_t* items;
  9679. gInventory.getDirectDescendentsOf(cat_id, cats, items);
  9680. lua_newtable(state);
  9681. for (S32 i = 0, count = cats->size(); i < count; ++i)
  9682. {
  9683. LLViewerInventoryCategory* cat = (*cats)[i];
  9684. if (cat) // Paranoia
  9685. {
  9686. folder_path = cat->getName() + "|";
  9687. lua_pushstring(state, cat->getUUID().asString().c_str());
  9688. lua_pushstring(state, folder_path.c_str());
  9689. lua_rawset(state, -3);
  9690. }
  9691. }
  9692. for (S32 i = 0, count = items->size(); i < count; ++i)
  9693. {
  9694. LLViewerInventoryItem* item = (*items)[i];
  9695. if (item) // Paranoia
  9696. {
  9697. lua_pushstring(state, item->getUUID().asString().c_str());
  9698. lua_pushstring(state, item->getName().c_str());
  9699. lua_rawset(state, -3);
  9700. }
  9701. }
  9702. return 1;
  9703. }
  9704. //static
  9705. int HBViewerAutomation::moveToInventoryFolder(lua_State* state)
  9706. {
  9707. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  9708. HBViewerAutomation* self = findInstance(state);
  9709. if (!self) return 0;
  9710. if (self->isThreaded())
  9711. {
  9712. HBAutomationThread* threadp = (HBAutomationThread*)self;
  9713. return threadp->callMainFunction("MoveToInventoryFolder");
  9714. }
  9715. S32 n = lua_gettop(state);
  9716. if (n != 2)
  9717. {
  9718. luaL_error(state, "%d arguments passed; expected 2.", n);
  9719. }
  9720. std::string folder_path(luaL_checkstring(state, 1));
  9721. LLUUID cat_id;
  9722. if (folder_path.empty())
  9723. {
  9724. cat_id = gInventory.getRootFolderID();
  9725. }
  9726. else
  9727. {
  9728. bool is_category = false;
  9729. cat_id = getInventoryObjectId(folder_path, is_category);
  9730. if (!is_category)
  9731. {
  9732. cat_id.setNull();
  9733. }
  9734. }
  9735. if (cat_id.isNull())
  9736. {
  9737. llwarns << "Could not find destination folder: " << folder_path
  9738. << llendl;
  9739. }
  9740. // Forbid to move to trash, COF or market place folders.
  9741. else if (gInventory.isInTrash(cat_id) || gInventory.isInCOF(cat_id) ||
  9742. gInventory.isInMarketPlace(cat_id))
  9743. {
  9744. llwarns << "Invalid destination folder." << llendl;
  9745. cat_id.setNull();
  9746. }
  9747. if (cat_id.isNull())
  9748. {
  9749. lua_pop(state, n);
  9750. lua_pushboolean(state, false);
  9751. return 1;
  9752. }
  9753. LL_DEBUGS("Lua") << "Destination folder found. Id = " << cat_id << LL_ENDL;
  9754. bool success = true;
  9755. uuid_vec_t inv_objects;
  9756. std::string invobj_path;
  9757. LLUUID obj_id;
  9758. bool is_category = false;
  9759. int type = lua_type(state, 2);
  9760. if (type == LUA_TTABLE)
  9761. {
  9762. // We accept either a list of string values (i.e. with numbers as keys)
  9763. // representing inventory items paths or UUIDs, or a table with UUIDs
  9764. // as keys and paths as values (as returned by ListInventoryFolder()).
  9765. lua_pushnil(state);
  9766. while (lua_next(state, 2))
  9767. {
  9768. int key_type = lua_type(state, -2);
  9769. if (key_type == LUA_TNUMBER)
  9770. {
  9771. // It could be an element of a list of strings.
  9772. if (lua_type(state, -1) != LUA_TSTRING)
  9773. {
  9774. llwarns << "Table element key is a number but value is not a string."
  9775. << llendl;
  9776. success = false;
  9777. break;
  9778. }
  9779. // Use the string value to find the inventory object
  9780. invobj_path = lua_tostring(state, -1);
  9781. }
  9782. else if (key_type == LUA_TSTRING)
  9783. {
  9784. // It is a pair of key,value, and we expect the key to be the
  9785. // UUID or the full path name for an inventory object.
  9786. invobj_path = lua_tostring(state, -2);
  9787. }
  9788. else
  9789. {
  9790. llwarns << "Table element key is not a number or string."
  9791. << llendl;
  9792. success = false;
  9793. break;
  9794. }
  9795. if (invobj_path.empty())
  9796. {
  9797. llwarns << "Inventory object path/UUID empty." << llendl;
  9798. success = false;
  9799. break;
  9800. }
  9801. obj_id = getInventoryObjectId(invobj_path, is_category);
  9802. if (obj_id.isNull())
  9803. {
  9804. llwarns << "Could not find inventory object: " << invobj_path
  9805. << llendl;
  9806. success = false;
  9807. break;
  9808. }
  9809. LL_DEBUGS("Lua") << "Inventory object found. Id = " << obj_id
  9810. << LL_ENDL;
  9811. inv_objects.emplace_back(obj_id);
  9812. lua_pop(state, 1);
  9813. }
  9814. }
  9815. else
  9816. {
  9817. // We accept a single inventory object path or UUID too, passed as a
  9818. // string.
  9819. invobj_path = luaL_checkstring(state, 2);
  9820. if (!invobj_path.empty())
  9821. {
  9822. obj_id = getInventoryObjectId(invobj_path, is_category);
  9823. }
  9824. success = obj_id.notNull();
  9825. if (success)
  9826. {
  9827. inv_objects.emplace_back(obj_id);
  9828. LL_DEBUGS("Lua") << "Inventory object found. Id = " << obj_id
  9829. << LL_ENDL;
  9830. }
  9831. else
  9832. {
  9833. llwarns << "Could not find inventory object: " << invobj_path
  9834. << llendl;
  9835. }
  9836. }
  9837. lua_pop(state, lua_gettop(state));
  9838. if (success)
  9839. {
  9840. success = !inv_objects.empty() &&
  9841. reparent_to_folder(cat_id, inv_objects);
  9842. }
  9843. lua_pushboolean(state, success);
  9844. return 1;
  9845. }
  9846. //static
  9847. void HBViewerAutomation::onPickInventoryItem(const std::vector<std::string>& names,
  9848. const uuid_vec_t& ids,
  9849. void* userdata, bool on_close)
  9850. {
  9851. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  9852. lua_State* state = (lua_State*)userdata;
  9853. HBViewerAutomation* self = findInstance(state);
  9854. if (!self || !self->mHasOnPickInventoryItem) return;
  9855. S32 count = ids.size();
  9856. LL_DEBUGS("Lua") << "Invoking OnPickInventoryItem Lua callback with "
  9857. << count << " selected inventory item"
  9858. << (count > 1 ? "s." : ".") << LL_ENDL;
  9859. lua_getglobal(state, "OnPickInventoryItem");
  9860. if (count)
  9861. {
  9862. lua_newtable(state);
  9863. for (S32 i = 0; i < count; ++i)
  9864. {
  9865. lua_pushstring(state, ids[i].asString().c_str());
  9866. lua_pushstring(state, names[i].c_str());
  9867. lua_rawset(state, -3);
  9868. }
  9869. }
  9870. else
  9871. {
  9872. lua_pushnil(state);
  9873. }
  9874. lua_pushboolean(state, on_close);
  9875. self->resetTimer();
  9876. if (lua_pcall(state, 2, 0, 0) != LUA_OK)
  9877. {
  9878. self->reportError();
  9879. }
  9880. }
  9881. //static
  9882. int HBViewerAutomation::pickInventoryItem(lua_State* state)
  9883. {
  9884. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  9885. if (!state) return 0; // Paranoia
  9886. S32 n = lua_gettop(state);
  9887. if (n < 1 || n > 7)
  9888. {
  9889. luaL_error(state, "%d arguments passed; expected 2 to 7.", n);
  9890. }
  9891. S32 type = lua_tointeger(state, 1);
  9892. S32 subtype = -1;
  9893. if (n > 1)
  9894. {
  9895. subtype = lua_tointeger(state, 2);
  9896. }
  9897. bool allow_multiple = n >= 3 && lua_toboolean(state, 3);
  9898. bool exclude_library = n < 4 || lua_toboolean(state, 4);
  9899. bool can_apply_immediately = false;
  9900. bool apply_immediately = false;
  9901. if (n >= 5)
  9902. {
  9903. can_apply_immediately = true;
  9904. apply_immediately = lua_toboolean(state, 5);
  9905. }
  9906. PermissionMask mask = PERM_NONE; // No restriction on permissions
  9907. if (n >= 6)
  9908. {
  9909. mask = lua_tointeger(state, 6);
  9910. }
  9911. bool callback_on_close = n >= 7 && lua_toboolean(state, 7);
  9912. lua_pop(state, n);
  9913. // NOTE: the inventory item picker will auto-close on selection or cancel
  9914. // action. We therefore do not need to track its pointer...
  9915. HBFloaterInvItemsPicker* pickerp =
  9916. new HBFloaterInvItemsPicker(NULL, &onPickInventoryItem, state);
  9917. pickerp->setAssetType((LLAssetType::EType)type, subtype);
  9918. pickerp->setAllowMultiple(allow_multiple);
  9919. pickerp->setExcludeLibrary(exclude_library);
  9920. pickerp->setFilterPermMask(mask);
  9921. if (can_apply_immediately)
  9922. {
  9923. pickerp->allowApplyImmediately();
  9924. pickerp->setApplyImmediately(apply_immediately);
  9925. }
  9926. if (callback_on_close)
  9927. {
  9928. pickerp->callBackOnClose();
  9929. }
  9930. return 0;
  9931. }
  9932. //static
  9933. void HBViewerAutomation::onPickAvatar(const std::vector<std::string>& names,
  9934. const std::vector<LLUUID>& ids,
  9935. void* userdata)
  9936. {
  9937. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  9938. lua_State* state = (lua_State*)userdata;
  9939. HBViewerAutomation* self = findInstance(state);
  9940. if (!self || !self->mHasOnPickAvatar) return;
  9941. S32 count = ids.size();
  9942. LL_DEBUGS("Lua") << "Invoking OnPickAvatar Lua callback with "
  9943. << count << " picked avatars" << (count > 1 ? "s." : ".")
  9944. << LL_ENDL;
  9945. lua_getglobal(state, "OnPickAvatar");
  9946. if (count)
  9947. {
  9948. lua_newtable(state);
  9949. for (S32 i = 0; i < count; ++i)
  9950. {
  9951. lua_pushstring(state, ids[i].asString().c_str());
  9952. lua_pushstring(state, names[i].c_str());
  9953. lua_rawset(state, -3);
  9954. }
  9955. }
  9956. else
  9957. {
  9958. lua_pushnil(state);
  9959. }
  9960. self->resetTimer();
  9961. if (lua_pcall(state, 1, 0, 0) != LUA_OK)
  9962. {
  9963. self->reportError();
  9964. }
  9965. }
  9966. //static
  9967. int HBViewerAutomation::pickAvatar(lua_State* state)
  9968. {
  9969. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  9970. if (!state) return 0; // Paranoia
  9971. S32 n = lua_gettop(state);
  9972. if (n > 2)
  9973. {
  9974. luaL_error(state, "%d arguments passed; expected 0 to 2.", n);
  9975. }
  9976. bool allow_multiple = n >= 1 && lua_toboolean(state, 1);
  9977. std::string search_name;
  9978. if (n > 1)
  9979. {
  9980. search_name.assign(luaL_checkstring(state, 2));
  9981. }
  9982. lua_pop(state, n);
  9983. // NOTE: the avatar picker will auto-close on selection or cancel action.
  9984. // We therefore do not need to track its pointer...
  9985. LLFloaterAvatarPicker::show(&onPickAvatar, state, allow_multiple, true,
  9986. search_name);
  9987. return 0;
  9988. }
  9989. //static
  9990. int HBViewerAutomation::getAgentAttachments(lua_State* state)
  9991. {
  9992. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  9993. HBViewerAutomation* self = findInstance(state);
  9994. if (!self || !isAgentAvatarValid()) return 0;
  9995. if (self->isThreaded())
  9996. {
  9997. HBAutomationThread* threadp = (HBAutomationThread*)self;
  9998. return threadp->callMainFunction("GetAgentAttachments");
  9999. }
  10000. S32 n = lua_gettop(state);
  10001. if (n > 1)
  10002. {
  10003. luaL_error(state, "%d arguments passed; expected 0 or 1.", n);
  10004. }
  10005. std::string search_string;
  10006. if (n)
  10007. {
  10008. search_string.assign(luaL_checkstring(state, 1));
  10009. lua_pop(state, 1);
  10010. LLStringUtil::toLower(search_string);
  10011. }
  10012. bool has_search_string = !search_string.empty();
  10013. lua_newtable(state);
  10014. std::string inv_item_uuid, item_name, lc_name, joint_name;
  10015. for (S32 i = 0, count = gAgentAvatarp->mAttachedObjectsVector.size();
  10016. i < count; ++i)
  10017. {
  10018. LLViewerJointAttachment* vatt =
  10019. gAgentAvatarp->mAttachedObjectsVector[i].second;
  10020. if (!vatt) continue; // Paranoia
  10021. joint_name = LLTrans::getString(vatt->getName());
  10022. LLStringUtil::toLower(joint_name);
  10023. LLViewerObject* vobj = gAgentAvatarp->mAttachedObjectsVector[i].first;
  10024. if (!vobj) continue; // Paranoia
  10025. const LLUUID& item_id = vobj->getAttachmentItemID();
  10026. if (item_id.isNull()) continue;
  10027. LLViewerInventoryItem* inv_item = gInventory.getItem(item_id);
  10028. if (inv_item)
  10029. {
  10030. inv_item_uuid = inv_item->getLinkedUUID().asString();
  10031. item_name = inv_item->getName();
  10032. }
  10033. else if (vobj->isTempAttachment())
  10034. {
  10035. inv_item_uuid = item_id.asString();
  10036. item_name = "temp_attachment:" + inv_item_uuid;
  10037. }
  10038. else
  10039. {
  10040. llwarns << "Could not find any valid object for attachment Id: "
  10041. << item_id << llendl;
  10042. continue;
  10043. }
  10044. if (has_search_string)
  10045. {
  10046. lc_name = item_name;
  10047. LLStringUtil::toLower(lc_name);
  10048. }
  10049. if (!has_search_string || joint_name == search_string ||
  10050. inv_item_uuid == search_string ||
  10051. lc_name.find(search_string) != std::string::npos)
  10052. {
  10053. item_name += "|" + joint_name;
  10054. lua_pushstring(state, inv_item_uuid.c_str());
  10055. lua_pushstring(state, item_name.c_str());
  10056. lua_rawset(state, -3);
  10057. }
  10058. }
  10059. return 1;
  10060. }
  10061. //static
  10062. int HBViewerAutomation::getAgentWearables(lua_State* state)
  10063. {
  10064. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  10065. HBViewerAutomation* self = findInstance(state);
  10066. if (!self || !isAgentAvatarValid()) return 0;
  10067. if (self->isThreaded())
  10068. {
  10069. HBAutomationThread* threadp = (HBAutomationThread*)self;
  10070. return threadp->callMainFunction("GetAgentWearables");
  10071. }
  10072. S32 n = lua_gettop(state);
  10073. if (n > 1)
  10074. {
  10075. luaL_error(state, "%d arguments passed; expected 0 or 1.", n);
  10076. }
  10077. std::string search_string;
  10078. if (n)
  10079. {
  10080. search_string.assign(luaL_checkstring(state, 1));
  10081. lua_pop(state, 1);
  10082. LLStringUtil::toLower(search_string);
  10083. }
  10084. bool has_search_string = !search_string.empty();
  10085. lua_newtable(state);
  10086. std::string inv_item_uuid, item_name, lc_name, type_name;
  10087. for (U32 i = 0; i < (U32)LLWearableType::WT_COUNT; ++i)
  10088. {
  10089. LLWearableType::EType type = (LLWearableType::EType)i;
  10090. type_name = LLTrans::getString(LLWearableType::getTypeLabel(type));
  10091. LLStringUtil::toLower(type_name);
  10092. for (U32 j = 0, count = gAgentWearables.getWearableCount(type);
  10093. j < count; ++j)
  10094. {
  10095. LLViewerWearable* wearable =
  10096. gAgentWearables.getViewerWearable(type, j);
  10097. if (!wearable) continue;
  10098. LLViewerInventoryItem* inv_item =
  10099. gInventory.getItem(wearable->getItemID());
  10100. if (!inv_item) continue;
  10101. inv_item_uuid = inv_item->getLinkedUUID().asString();
  10102. item_name = inv_item->getName();
  10103. if (has_search_string)
  10104. {
  10105. lc_name = item_name;
  10106. LLStringUtil::toLower(lc_name);
  10107. }
  10108. if (!has_search_string || type_name == search_string ||
  10109. inv_item_uuid == search_string ||
  10110. lc_name.find(search_string) != std::string::npos)
  10111. {
  10112. item_name += "|" + type_name;
  10113. lua_pushstring(state, inv_item_uuid.c_str());
  10114. lua_pushstring(state, item_name.c_str());
  10115. lua_rawset(state, -3);
  10116. }
  10117. }
  10118. }
  10119. return 1;
  10120. }
  10121. //static
  10122. int HBViewerAutomation::getGridSimAndPos(lua_State* state)
  10123. {
  10124. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  10125. HBViewerAutomation* self = findInstance(state);
  10126. if (!self) return 0;
  10127. if (self->isThreaded())
  10128. {
  10129. HBAutomationThread* threadp = (HBAutomationThread*)self;
  10130. return threadp->callMainFunction("GetGridSimAndPos");
  10131. }
  10132. S32 n = lua_gettop(state);
  10133. if (n != 0)
  10134. {
  10135. luaL_error(state, "%d arguments passed; expected 0.", n);
  10136. }
  10137. self->pushGridSimAndPos();
  10138. return 1;
  10139. }
  10140. //static
  10141. int HBViewerAutomation::getParcelInfo(lua_State* state)
  10142. {
  10143. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  10144. HBViewerAutomation* self = findInstance(state);
  10145. if (!self) return 0;
  10146. if (self->isThreaded())
  10147. {
  10148. HBAutomationThread* threadp = (HBAutomationThread*)self;
  10149. return threadp->callMainFunction("GetParcelInfo");
  10150. }
  10151. S32 n = lua_gettop(state);
  10152. if (n != 0)
  10153. {
  10154. luaL_error(state, "%d arguments passed; expected 0.", n);
  10155. }
  10156. self->pushParcelInfo();
  10157. return 1;
  10158. }
  10159. //static
  10160. int HBViewerAutomation::getCameraMode(lua_State* state)
  10161. {
  10162. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  10163. HBViewerAutomation* self = findInstance(state);
  10164. if (!self) return 0;
  10165. if (self->isThreaded())
  10166. {
  10167. HBAutomationThread* threadp = (HBAutomationThread*)self;
  10168. return threadp->callMainFunction("GetCameraMode");
  10169. }
  10170. S32 n = lua_gettop(state);
  10171. if (n != 0)
  10172. {
  10173. luaL_error(state, "%d arguments passed; expected 0.", n);
  10174. }
  10175. lua_pushnumber(state, gAgent.getCameraMode());
  10176. return 1;
  10177. }
  10178. //static
  10179. int HBViewerAutomation::setCameraMode(lua_State* state)
  10180. {
  10181. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  10182. HBViewerAutomation* self = findInstance(state);
  10183. if (!self) return 0;
  10184. if (self->isThreaded())
  10185. {
  10186. HBAutomationThread* threadp = (HBAutomationThread*)self;
  10187. return threadp->callMainFunction("SetCameraMode");
  10188. }
  10189. S32 n = lua_gettop(state);
  10190. if (n != 1 && n != 2)
  10191. {
  10192. luaL_error(state, "%d arguments passed; expected 1 or 2.", n);
  10193. }
  10194. S32 mode = lua_tointeger(state, 1);
  10195. bool animate = n < 2 || lua_toboolean(state, 2);
  10196. lua_pop(state, n);
  10197. HBIgnoreCallback lock_on_camera_change(E_ONCAMERAMODECHANGE);
  10198. bool success = false;
  10199. if (mode == -2)
  10200. {
  10201. success = handle_reset_view();
  10202. }
  10203. else if (mode == -1)
  10204. {
  10205. success = gAgent.changeCameraToDefault(animate);
  10206. }
  10207. else if (mode == (S32)CAMERA_MODE_THIRD_PERSON)
  10208. {
  10209. success = gAgent.changeCameraToThirdPerson(animate);
  10210. }
  10211. else if (mode == (S32)CAMERA_MODE_MOUSELOOK)
  10212. {
  10213. success = gAgent.changeCameraToMouselook(animate);
  10214. }
  10215. lua_pushboolean(state, success);
  10216. return 1;
  10217. }
  10218. //static
  10219. int HBViewerAutomation::setCameraFocus(lua_State* state)
  10220. {
  10221. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  10222. HBViewerAutomation* self = findInstance(state);
  10223. if (!self) return 0;
  10224. if (self->isThreaded())
  10225. {
  10226. HBAutomationThread* threadp = (HBAutomationThread*)self;
  10227. return threadp->callMainFunction("SetCameraFocus");
  10228. }
  10229. S32 n = lua_gettop(state);
  10230. if (n > 1)
  10231. {
  10232. luaL_error(state, "%d arguments passed; expected 0 or 1.", n);
  10233. }
  10234. std::string id_str;
  10235. if (n)
  10236. {
  10237. id_str = luaL_checkstring(state, 1);
  10238. if (!id_str.empty() && !LLUUID::validate(id_str))
  10239. {
  10240. luaL_error(state, "Invalid UUID: %s", id_str.c_str());
  10241. }
  10242. lua_pop(state, 1);
  10243. }
  10244. HBIgnoreCallback lock_on_camera_change(E_ONCAMERAMODECHANGE);
  10245. if (id_str.empty())
  10246. {
  10247. gAgent.setFocusOnAvatar(true);
  10248. }
  10249. else
  10250. {
  10251. gAgent.lookAtObject(LLUUID(id_str), CAMERA_POSITION_OBJECT);
  10252. }
  10253. return 0;
  10254. }
  10255. //static
  10256. int HBViewerAutomation::setVisualMute(lua_State* state)
  10257. {
  10258. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  10259. HBViewerAutomation* self = findInstance(state);
  10260. if (!self) return 0;
  10261. if (self->isThreaded())
  10262. {
  10263. HBAutomationThread* threadp = (HBAutomationThread*)self;
  10264. return threadp->callMainFunction("SetVisualMute");
  10265. }
  10266. S32 n = lua_gettop(state);
  10267. if (n != 2)
  10268. {
  10269. luaL_error(state, "%d arguments passed; expected 2.", n);
  10270. }
  10271. LLUUID avid = LLUUID(luaL_checkstring(state, 1), false);
  10272. if (avid.isNull())
  10273. {
  10274. luaL_error(state, "Invalid avatar Id");
  10275. }
  10276. if (avid == gAgentID)
  10277. {
  10278. luaL_error(state, "Cannot visually mute your own avatar");
  10279. }
  10280. S32 val = luaL_checknumber(state, 2);
  10281. if (val < 0 || val > 2)
  10282. {
  10283. luaL_error(state, "Invalid visual mute value passed: %d", val);
  10284. }
  10285. lua_pop(state, 2);
  10286. bool success = false;
  10287. LLVOAvatar* avatarp = gObjectList.findAvatar(avid);
  10288. if (avatarp)
  10289. {
  10290. avatarp->setVisualMuteSettings((LLVOAvatar::VisualMuteSettings)val);
  10291. success = true;
  10292. }
  10293. lua_pushboolean(state, success);
  10294. return 1;
  10295. }
  10296. static void on_name_cache_mute(const LLUUID& id, const std::string& name,
  10297. bool is_group, S32 flags, bool mute_it)
  10298. {
  10299. LLMute mute(id, name, is_group ? LLMute::GROUP : LLMute::AGENT);
  10300. if (mute_it)
  10301. {
  10302. LLMuteList::add(mute, flags);
  10303. }
  10304. else
  10305. {
  10306. LLMuteList::remove(mute, flags);
  10307. }
  10308. }
  10309. //static
  10310. int HBViewerAutomation::addMute(lua_State* state)
  10311. {
  10312. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  10313. HBViewerAutomation* self = findInstance(state);
  10314. if (!self) return 0;
  10315. if (self->isThreaded())
  10316. {
  10317. HBAutomationThread* threadp = (HBAutomationThread*)self;
  10318. return threadp->callMainFunction("AddMute");
  10319. }
  10320. S32 n = lua_gettop(state);
  10321. if (n < 1 || n > 3)
  10322. {
  10323. luaL_error(state, "%d arguments passed; expected 1 to 3.", n);
  10324. }
  10325. std::string name = luaL_checkstring(state, 1);
  10326. LLUUID id;
  10327. if (LLUUID::validate(name))
  10328. {
  10329. id.set(name);
  10330. name.clear();
  10331. }
  10332. S32 type = LLMute::BY_NAME;
  10333. if (n > 1)
  10334. {
  10335. type = luaL_checknumber(state, 2);
  10336. if (type < 0 || type >= (S32)LLMute::COUNT)
  10337. {
  10338. luaL_error(state, "Invalid mute type passed: %d", type);
  10339. }
  10340. }
  10341. if (type == (S32)LLMute::BY_NAME && id.notNull())
  10342. {
  10343. luaL_error(state, "Cannot mute by name with an UUID");
  10344. }
  10345. S32 flags = 0;
  10346. if (n > 2)
  10347. {
  10348. flags = luaL_checknumber(state, 3);
  10349. if (flags < 0)
  10350. {
  10351. luaL_error(state, "Invalid mute flag(s) passed: %d", flags);
  10352. }
  10353. }
  10354. lua_pop(state, n);
  10355. bool success = false;
  10356. switch (type)
  10357. {
  10358. case (S32)LLMute::AGENT:
  10359. case (S32)LLMute::GROUP:
  10360. {
  10361. if (gCacheNamep)
  10362. {
  10363. gCacheNamep->get(id, type == (S32)LLMute::GROUP,
  10364. boost::bind(&on_name_cache_mute, _1, _2, _3,
  10365. flags, true));
  10366. success = true;
  10367. }
  10368. break;
  10369. }
  10370. case (S32)LLMute::OBJECT:
  10371. {
  10372. success = requestObjectPropertiesFamily(id, 0);
  10373. break;
  10374. }
  10375. case (S32)LLMute::BY_NAME:
  10376. {
  10377. LLMute mute(LLUUID::null, name, LLMute::BY_NAME);
  10378. success = LLMuteList::add(mute, flags);
  10379. break;
  10380. }
  10381. default: // Never happens, unless the LLMute::EType enum got changed
  10382. llerrs << "Invalid mute type: " << type << llendl;
  10383. }
  10384. lua_pushboolean(state, success);
  10385. return 1;
  10386. }
  10387. //static
  10388. int HBViewerAutomation::removeMute(lua_State* state)
  10389. {
  10390. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  10391. HBViewerAutomation* self = findInstance(state);
  10392. if (!self) return 0;
  10393. if (self->isThreaded())
  10394. {
  10395. HBAutomationThread* threadp = (HBAutomationThread*)self;
  10396. return threadp->callMainFunction("RemoveMute");
  10397. }
  10398. S32 n = lua_gettop(state);
  10399. if (n < 1 || n > 3)
  10400. {
  10401. luaL_error(state, "%d arguments passed; expected 1 to 3.", n);
  10402. }
  10403. std::string name = luaL_checkstring(state, 1);
  10404. LLUUID id;
  10405. if (LLUUID::validate(name))
  10406. {
  10407. id.set(name);
  10408. name.clear();
  10409. }
  10410. S32 type = LLMute::BY_NAME;
  10411. if (n > 1)
  10412. {
  10413. type = luaL_checknumber(state, 2);
  10414. if (type < 0 || type >= (S32)LLMute::COUNT)
  10415. {
  10416. luaL_error(state, "Invalid mute type passed: %d", type);
  10417. }
  10418. }
  10419. if (type == (S32)LLMute::BY_NAME && id.notNull())
  10420. {
  10421. luaL_error(state, "Cannot unmute by name with an UUID");
  10422. }
  10423. S32 flags = 0;
  10424. if (n > 2)
  10425. {
  10426. flags = luaL_checknumber(state, 3);
  10427. if (flags < 0)
  10428. {
  10429. luaL_error(state, "Negative mute flag passed: %d", flags);
  10430. }
  10431. }
  10432. lua_pop(state, n);
  10433. bool success = false;
  10434. switch (type)
  10435. {
  10436. case (S32)LLMute::AGENT:
  10437. case (S32)LLMute::GROUP:
  10438. {
  10439. if (gCacheNamep)
  10440. {
  10441. gCacheNamep->get(id, type == (S32)LLMute::GROUP,
  10442. boost::bind(&on_name_cache_mute, _1, _2, _3,
  10443. flags, false));
  10444. success = true;
  10445. }
  10446. break;
  10447. }
  10448. case (S32)LLMute::OBJECT:
  10449. {
  10450. success = requestObjectPropertiesFamily(id, 1);
  10451. break;
  10452. }
  10453. case (S32)LLMute::BY_NAME:
  10454. {
  10455. LLMute mute(LLUUID::null, name, LLMute::BY_NAME);
  10456. success = LLMuteList::remove(mute);
  10457. break;
  10458. }
  10459. default: // Never happens, unless the LLMute::EType enum got changed
  10460. llerrs << "Invalid mute type: " << type << llendl;
  10461. }
  10462. lua_pushboolean(state, success);
  10463. return 1;
  10464. }
  10465. //static
  10466. int HBViewerAutomation::isMuted(lua_State* state)
  10467. {
  10468. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  10469. HBViewerAutomation* self = findInstance(state);
  10470. if (!self) return 0;
  10471. if (self->isThreaded())
  10472. {
  10473. HBAutomationThread* threadp = (HBAutomationThread*)self;
  10474. return threadp->callMainFunction("IsMuted");
  10475. }
  10476. S32 n = lua_gettop(state);
  10477. if (n < 1 || n > 3)
  10478. {
  10479. luaL_error(state, "%d arguments passed; expected 1 to 3.", n);
  10480. }
  10481. std::string name = luaL_checkstring(state, 1);
  10482. LLUUID object_id;
  10483. if (LLUUID::validate(name))
  10484. {
  10485. object_id.set(name);
  10486. name.clear();
  10487. }
  10488. S32 type = LLMute::COUNT;
  10489. if (n > 1)
  10490. {
  10491. type = luaL_checknumber(state, 2);
  10492. if (type < 0 || type > (S32)LLMute::COUNT)
  10493. {
  10494. luaL_error(state, "Invalid mute type passed: %d", type);
  10495. }
  10496. }
  10497. S32 flags = 0;
  10498. if (n > 2)
  10499. {
  10500. flags = luaL_checknumber(state, 3);
  10501. if (flags < 0)
  10502. {
  10503. luaL_error(state, "Negative mute flag passed: %d", flags);
  10504. }
  10505. }
  10506. lua_pop(state, n);
  10507. lua_pushboolean(state, LLMuteList::isMuted(object_id, name, flags,
  10508. (LLMute::EType)type));
  10509. return 1;
  10510. }
  10511. //static
  10512. int HBViewerAutomation::blockSound(lua_State* state)
  10513. {
  10514. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  10515. HBViewerAutomation* self = findInstance(state);
  10516. if (!self) return 0;
  10517. if (self->isThreaded())
  10518. {
  10519. HBAutomationThread* threadp = (HBAutomationThread*)self;
  10520. return threadp->callMainFunction("BlockSound");
  10521. }
  10522. S32 n = lua_gettop(state);
  10523. if (n != 1 && n != 2)
  10524. {
  10525. luaL_error(state, "%d arguments passed; expected 1 or 2.", n);
  10526. }
  10527. std::string id_str = luaL_checkstring(state, 1);
  10528. if (!LLUUID::validate(id_str))
  10529. {
  10530. luaL_error(state, "Invalid UUID: %s", id_str.c_str());
  10531. }
  10532. bool block = n < 2 || lua_toboolean(state, 2);
  10533. lua_pop(state, n);
  10534. LLAudioData::blockSound(LLUUID(id_str), block);
  10535. // Inform the sounds list floater (if opened) that blocked sounds changed.
  10536. HBFloaterSoundsList::setDirty();
  10537. return 0;
  10538. }
  10539. //static
  10540. int HBViewerAutomation::isBlockedSound(lua_State* state)
  10541. {
  10542. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  10543. HBViewerAutomation* self = findInstance(state);
  10544. if (!self) return 0;
  10545. if (self->isThreaded())
  10546. {
  10547. HBAutomationThread* threadp = (HBAutomationThread*)self;
  10548. return threadp->callMainFunction("IsBlockedSound");
  10549. }
  10550. S32 n = lua_gettop(state);
  10551. if (n != 1)
  10552. {
  10553. luaL_error(state, "%d arguments passed; expected 1.", n);
  10554. }
  10555. std::string id_str = luaL_checkstring(state, 1);
  10556. if (!LLUUID::validate(id_str))
  10557. {
  10558. luaL_error(state, "Invalid UUID: %s", id_str.c_str());
  10559. }
  10560. lua_pop(state, 1);
  10561. lua_pushboolean(state, LLAudioData::isBlockedSound(LLUUID(id_str)));
  10562. return 1;
  10563. }
  10564. //static
  10565. int HBViewerAutomation::getBlockedSounds(lua_State* state)
  10566. {
  10567. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  10568. HBViewerAutomation* self = findInstance(state);
  10569. if (!self) return 0;
  10570. if (self->isThreaded())
  10571. {
  10572. HBAutomationThread* threadp = (HBAutomationThread*)self;
  10573. return threadp->callMainFunction("GetBlockedSounds");
  10574. }
  10575. S32 n = lua_gettop(state);
  10576. if (n)
  10577. {
  10578. luaL_error(state, "%d arguments passed; expected 0.", n);
  10579. }
  10580. const uuid_list_t& sounds = LLAudioData::getBlockedSounds();
  10581. int i = 0;
  10582. lua_newtable(state);
  10583. for (uuid_list_t::const_iterator it = sounds.begin(), end = sounds.end();
  10584. it != end; ++it)
  10585. {
  10586. lua_pushstring(state, it->asString().c_str());
  10587. lua_rawseti(state, -2, ++i);
  10588. }
  10589. return 1;
  10590. }
  10591. //static
  10592. int HBViewerAutomation::derenderObject(lua_State* state)
  10593. {
  10594. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  10595. HBViewerAutomation* self = findInstance(state);
  10596. if (!self) return 0;
  10597. if (self->isThreaded())
  10598. {
  10599. HBAutomationThread* threadp = (HBAutomationThread*)self;
  10600. return threadp->callMainFunction("DerenderObject");
  10601. }
  10602. S32 n = lua_gettop(state);
  10603. if (n > 2)
  10604. {
  10605. luaL_error(state, "%d arguments passed; expected 0 to 2.", n);
  10606. }
  10607. LLUUID object_id;
  10608. if (n > 0)
  10609. {
  10610. object_id.set(luaL_checkstring(state, 1), false);
  10611. }
  10612. bool derender = n < 2 || lua_toboolean(state, 2);
  10613. lua_pop(state, n);
  10614. bool success = true;
  10615. if (n == 0)
  10616. {
  10617. gObjectList.mBlackListedObjects.clear();
  10618. HBFloaterRadar::setRenderStatusDirty();
  10619. }
  10620. else if (derender)
  10621. {
  10622. // Note: HBFloaterRadar::setRenderStatusDirty() will be called if
  10623. // needed by derender_object().
  10624. success = derender_object(object_id);
  10625. }
  10626. else if (gObjectList.mBlackListedObjects.count(object_id))
  10627. {
  10628. gObjectList.mBlackListedObjects.erase(object_id);
  10629. // Call unconditionnaly (even for non-avatar objects): it really does
  10630. // not matter, and searching for the object in the avatars list to
  10631. // check whether it is an avatar or not would take more time.
  10632. HBFloaterRadar::setRenderStatusDirty(object_id);
  10633. }
  10634. else
  10635. {
  10636. success = false;
  10637. }
  10638. lua_pushboolean(state, success);
  10639. return 1;
  10640. }
  10641. //static
  10642. int HBViewerAutomation::getDerenderedObjects(lua_State* state)
  10643. {
  10644. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  10645. HBViewerAutomation* self = findInstance(state);
  10646. if (!self) return 0;
  10647. if (self->isThreaded())
  10648. {
  10649. HBAutomationThread* threadp = (HBAutomationThread*)self;
  10650. return threadp->callMainFunction("GetDerenderedObjects");
  10651. }
  10652. S32 n = lua_gettop(state);
  10653. if (n)
  10654. {
  10655. luaL_error(state, "%d arguments passed; expected 0.", n);
  10656. }
  10657. int i = 0;
  10658. lua_newtable(state);
  10659. for (uuid_list_t::iterator it = gObjectList.mBlackListedObjects.begin(),
  10660. end = gObjectList.mBlackListedObjects.end();
  10661. it != end ; ++it)
  10662. {
  10663. lua_pushstring(state, (*it).asString().c_str());
  10664. lua_rawseti(state, -2, ++i);
  10665. }
  10666. return 1;
  10667. }
  10668. //static
  10669. int HBViewerAutomation::getAgentPushes(lua_State* state)
  10670. {
  10671. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  10672. HBViewerAutomation* self = findInstance(state);
  10673. if (!self) return 0;
  10674. if (self->isThreaded())
  10675. {
  10676. HBAutomationThread* threadp = (HBAutomationThread*)self;
  10677. return threadp->callMainFunction("GetAgentPushes");
  10678. }
  10679. S32 n = lua_gettop(state);
  10680. if (n != 1)
  10681. {
  10682. luaL_error(state, "%d arguments passed; expected 1.", n);
  10683. }
  10684. LLUUID perpetrator_id(luaL_checkstring(state, 1), false);
  10685. lua_pop(state, 1);
  10686. std::string desc = HBFloaterBump::getMeanCollisionsStats(perpetrator_id);
  10687. lua_pushstring(state, desc.c_str());
  10688. return 1;
  10689. }
  10690. //static
  10691. int HBViewerAutomation::applyDaySettings(lua_State* state)
  10692. {
  10693. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  10694. HBViewerAutomation* self = findInstance(state);
  10695. if (!self) return 0;
  10696. if (self->isThreaded())
  10697. {
  10698. HBAutomationThread* threadp = (HBAutomationThread*)self;
  10699. return threadp->callMainFunction("ApplyDaySettings");
  10700. }
  10701. S32 n = lua_gettop(state);
  10702. if (n != 1)
  10703. {
  10704. luaL_error(state, "%d arguments passed; expected 1.", n);
  10705. }
  10706. std::string preset(luaL_checkstring(state, 1));
  10707. lua_pop(state, 1);
  10708. bool success = LLStartUp::isLoggedIn() &&
  10709. //MK
  10710. (!gRLenabled || !gRLInterface.mContainsSetenv);
  10711. //mk
  10712. if (!success)
  10713. {
  10714. lua_pushboolean(state, success);
  10715. return 1;
  10716. }
  10717. HBIgnoreCallback lock_on_wl_change(E_ONWINDLIGHTCHANGE);
  10718. // Check special "settings" that trigger specific environments
  10719. if (preset == "animate")
  10720. {
  10721. LLEnvironment::setRegion();
  10722. }
  10723. else if (preset == "region")
  10724. {
  10725. success = false;
  10726. }
  10727. else if (preset == "sunrise")
  10728. {
  10729. LLEnvironment::setSunrise();
  10730. }
  10731. else if (preset == "midday" || preset == "noon")
  10732. {
  10733. LLEnvironment::setMidday();
  10734. }
  10735. else if (preset == "noon_pbr")
  10736. {
  10737. LLEnvironment::setMiddayPBR();
  10738. }
  10739. else if (preset == "sunset")
  10740. {
  10741. LLEnvironment::setSunset();
  10742. }
  10743. else if (preset == "midnight")
  10744. {
  10745. LLEnvironment::setMidnight();
  10746. }
  10747. else if (preset == "parcel")
  10748. {
  10749. gSavedSettings.setBool("UseParcelEnvironment", true);
  10750. }
  10751. else if (preset == "local")
  10752. {
  10753. gSavedSettings.setBool("UseLocalEnvironment", true);
  10754. }
  10755. else if (preset == "windlight")
  10756. {
  10757. gSavedSettings.setBool("UseParcelEnvironment", false);
  10758. gSavedSettings.setBool("UseLocalEnvironment", false);
  10759. }
  10760. else
  10761. {
  10762. success = false;
  10763. }
  10764. // Then try actual settings (inventory assets or Windlight)
  10765. if (!success)
  10766. {
  10767. success = LLEnvSettingsDay::applyPresetByName(preset);
  10768. }
  10769. lua_pushboolean(state, success);
  10770. return 1;
  10771. }
  10772. //static
  10773. int HBViewerAutomation::applySkySettings(lua_State* state)
  10774. {
  10775. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  10776. HBViewerAutomation* self = findInstance(state);
  10777. if (!self) return 0;
  10778. if (self->isThreaded())
  10779. {
  10780. HBAutomationThread* threadp = (HBAutomationThread*)self;
  10781. return threadp->callMainFunction("ApplySkySettings");
  10782. }
  10783. S32 n = lua_gettop(state);
  10784. if (n != 1)
  10785. {
  10786. luaL_error(state, "%d arguments passed; expected 1.", n);
  10787. }
  10788. std::string preset(luaL_checkstring(state, 1));
  10789. lua_pop(state, 1);
  10790. bool success = LLStartUp::isLoggedIn() &&
  10791. //MK
  10792. (!gRLenabled || !gRLInterface.mContainsSetenv);
  10793. //mk
  10794. if (success)
  10795. {
  10796. HBIgnoreCallback lock_on_wl_change(E_ONWINDLIGHTCHANGE);
  10797. success = LLEnvSettingsSky::applyPresetByName(preset);
  10798. }
  10799. lua_pushboolean(state, success);
  10800. return 1;
  10801. }
  10802. //static
  10803. int HBViewerAutomation::applyWaterSettings(lua_State* state)
  10804. {
  10805. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  10806. HBViewerAutomation* self = findInstance(state);
  10807. if (!self) return 0;
  10808. if (self->isThreaded())
  10809. {
  10810. HBAutomationThread* threadp = (HBAutomationThread*)self;
  10811. return threadp->callMainFunction("ApplyWaterSettings");
  10812. }
  10813. S32 n = lua_gettop(state);
  10814. if (n != 1)
  10815. {
  10816. luaL_error(state, "%d arguments passed; expected 1.", n);
  10817. }
  10818. std::string preset(luaL_checkstring(state, 1));
  10819. lua_pop(state, 1);
  10820. bool success = LLStartUp::isLoggedIn() &&
  10821. //MK
  10822. (!gRLenabled || !gRLInterface.mContainsSetenv);
  10823. //mk
  10824. if (success)
  10825. {
  10826. HBIgnoreCallback lock_on_wl_change(E_ONWINDLIGHTCHANGE);
  10827. success = LLEnvSettingsWater::applyPresetByName(preset);
  10828. }
  10829. lua_pushboolean(state, success);
  10830. return 1;
  10831. }
  10832. //static
  10833. int HBViewerAutomation::setDayTime(lua_State* state)
  10834. {
  10835. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  10836. HBViewerAutomation* self = findInstance(state);
  10837. if (!self) return 0;
  10838. if (self->isThreaded())
  10839. {
  10840. HBAutomationThread* threadp = (HBAutomationThread*)self;
  10841. return threadp->callMainFunction("SetDayTime");
  10842. }
  10843. S32 n = lua_gettop(state);
  10844. if (n != 1)
  10845. {
  10846. luaL_error(state, "%d arguments passed; expected 1.", n);
  10847. }
  10848. F32 time = luaL_checknumber(state, 1);
  10849. lua_pop(state, 1);
  10850. if (!LLStartUp::isLoggedIn() || time > 1.f ||
  10851. //MK
  10852. (gRLenabled && gRLInterface.mContainsSetenv))
  10853. //mk
  10854. {
  10855. return 0;
  10856. }
  10857. HBIgnoreCallback lock_on_wl_change(E_ONWINDLIGHTCHANGE);
  10858. if (time < 0.f)
  10859. {
  10860. // Revert to parcel environment...
  10861. gSavedSettings.setBool("UseParcelEnvironment", true);
  10862. return 0;
  10863. }
  10864. // Extended environment time of day, using a fixed sky setting...
  10865. if (gEnvironment.hasEnvironment(LLEnvironment::ENV_LOCAL))
  10866. {
  10867. if (gEnvironment.getEnvironmentDay(LLEnvironment::ENV_LOCAL))
  10868. {
  10869. // We have a full day cycle in the local environment: freeze the
  10870. // sky.
  10871. LLSettingsSky::ptr_t skyp =
  10872. gEnvironment.getEnvironmentFixedSky(LLEnvironment::ENV_LOCAL)->buildClone();
  10873. gEnvironment.setEnvironment(LLEnvironment::ENV_LOCAL, skyp, 0);
  10874. }
  10875. }
  10876. else
  10877. {
  10878. // Use a copy of the parcel environment sky instead.
  10879. LLSettingsSky::ptr_t skyp =
  10880. gEnvironment.getEnvironmentFixedSky(LLEnvironment::ENV_PARCEL,
  10881. true)->buildClone();
  10882. gEnvironment.setEnvironment(LLEnvironment::ENV_LOCAL, skyp, 0);
  10883. }
  10884. gEnvironment.setSelectedEnvironment(LLEnvironment::ENV_LOCAL,
  10885. LLEnvironment::TRANSITION_INSTANT);
  10886. // Set the time now...
  10887. gEnvironment.setFixedTimeOfDay(time);
  10888. return 0;
  10889. }
  10890. //static
  10891. int HBViewerAutomation::getEESettingsList(lua_State* state)
  10892. {
  10893. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  10894. HBViewerAutomation* self = findInstance(state);
  10895. if (!self) return 0;
  10896. if (self->isThreaded())
  10897. {
  10898. HBAutomationThread* threadp = (HBAutomationThread*)self;
  10899. return threadp->callMainFunction("GetEESettingsList");
  10900. }
  10901. S32 n = lua_gettop(state);
  10902. if (n != 0 && n != 1)
  10903. {
  10904. luaL_error(state, "%d arguments passed; expected 0 or 1.", n);
  10905. }
  10906. S32 wanted_type = -1;
  10907. if (n)
  10908. {
  10909. wanted_type = luaL_checknumber(state, 1);
  10910. lua_pop(state, n);
  10911. if (wanted_type < 0 || wanted_type > 2)
  10912. {
  10913. wanted_type = -1;
  10914. }
  10915. }
  10916. if (!gAgent.hasInventorySettings())
  10917. {
  10918. lua_pushnil(state);
  10919. return 1;
  10920. }
  10921. const LLUUID& folder_id =
  10922. gInventory.findCategoryUUIDForType(LLFolderType::FT_SETTINGS, false);
  10923. if (folder_id.isNull())
  10924. {
  10925. lua_pushnil(state);
  10926. return 1;
  10927. }
  10928. typedef std::map<std::string, std::string> smap_t;
  10929. smap_t settings;
  10930. LLEnvSettingsCollector collector;
  10931. LLInventoryModel::cat_array_t cats;
  10932. LLInventoryModel::item_array_t items;
  10933. gInventory.collectDescendentsIf(folder_id, cats, items, false, collector);
  10934. std::string name, type_str;
  10935. for (LLInventoryModel::item_array_t::iterator iter = items.begin(),
  10936. end = items.end();
  10937. iter != end; ++iter)
  10938. {
  10939. LLViewerInventoryItem* itemp = *iter;
  10940. S32 type = (S32)itemp->getSettingsType();
  10941. if (type < 0 || type > 2 || (wanted_type != -1 && type != wanted_type))
  10942. {
  10943. continue;
  10944. }
  10945. name = itemp->getName();
  10946. smap_t::iterator sit = settings.find(name);
  10947. if (sit == settings.end())
  10948. {
  10949. settings[name] = sEnvSettingsTypes[type];
  10950. }
  10951. else if (sit->second.find(sEnvSettingsTypes[type]) == std::string::npos)
  10952. {
  10953. sit->second += "," + sEnvSettingsTypes[type];
  10954. }
  10955. }
  10956. if (settings.empty())
  10957. {
  10958. lua_pushnil(state);
  10959. return 1;
  10960. }
  10961. lua_newtable(state);
  10962. for (smap_t::iterator it = settings.begin(), end = settings.end();
  10963. it != end; ++it)
  10964. {
  10965. lua_pushstring(state, it->first.c_str());
  10966. lua_pushstring(state, it->second.c_str());
  10967. lua_rawset(state, -3);
  10968. }
  10969. return 1;
  10970. }
  10971. //static
  10972. int HBViewerAutomation::getWLSettingsList(lua_State* state)
  10973. {
  10974. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  10975. HBViewerAutomation* self = findInstance(state);
  10976. if (!self) return 0;
  10977. if (self->isThreaded())
  10978. {
  10979. HBAutomationThread* threadp = (HBAutomationThread*)self;
  10980. return threadp->callMainFunction("GetWLSettingsList");
  10981. }
  10982. S32 n = lua_gettop(state);
  10983. if (n != 0 && n != 1)
  10984. {
  10985. luaL_error(state, "%d arguments passed; expected 0 or 1.", n);
  10986. }
  10987. S32 wanted_type = -1;
  10988. if (n)
  10989. {
  10990. wanted_type = luaL_checknumber(state, 1);
  10991. lua_pop(state, n);
  10992. if (wanted_type < 0 || wanted_type > 2)
  10993. {
  10994. wanted_type = -1;
  10995. }
  10996. }
  10997. if (!gAgent.hasInventorySettings())
  10998. {
  10999. lua_pushnil(state);
  11000. return 1;
  11001. }
  11002. typedef std::map<std::string, std::string> smap_t;
  11003. smap_t settings;
  11004. std::vector<std::string> presets;
  11005. if (wanted_type == 0 || wanted_type == -1)
  11006. {
  11007. presets = LLWLSkyParamMgr::getLoadedPresetsList();
  11008. for (S32 i = 0, count = presets.size(); i < count; ++i)
  11009. {
  11010. const std::string& name = presets[i];
  11011. settings[name] = "sky";
  11012. }
  11013. }
  11014. if (wanted_type == 1 || wanted_type == -1)
  11015. {
  11016. presets = LLWLWaterParamMgr::getLoadedPresetsList();
  11017. for (S32 i = 0, count = presets.size(); i < count; ++i)
  11018. {
  11019. const std::string& name = presets[i];
  11020. smap_t::iterator sit = settings.find(name);
  11021. if (sit == settings.end())
  11022. {
  11023. settings[name] = "water";
  11024. }
  11025. else if (sit->second.find("water") == std::string::npos)
  11026. {
  11027. sit->second += ",water";
  11028. }
  11029. }
  11030. }
  11031. if (wanted_type == 2 || wanted_type == -1)
  11032. {
  11033. presets = LLWLDayCycle::getLoadedPresetsList();
  11034. for (S32 i = 0, count = presets.size(); i < count; ++i)
  11035. {
  11036. const std::string& name = presets[i];
  11037. smap_t::iterator sit = settings.find(name);
  11038. if (sit == settings.end())
  11039. {
  11040. settings[name] = "day";
  11041. }
  11042. else if (sit->second.find("day") == std::string::npos)
  11043. {
  11044. sit->second += ",day";
  11045. }
  11046. }
  11047. }
  11048. if (settings.empty())
  11049. {
  11050. lua_pushnil(state);
  11051. return 1;
  11052. }
  11053. lua_newtable(state);
  11054. for (smap_t::iterator it = settings.begin(), end = settings.end();
  11055. it != end; ++it)
  11056. {
  11057. lua_pushstring(state, it->first.c_str());
  11058. lua_pushstring(state, it->second.c_str());
  11059. lua_rawset(state, -3);
  11060. }
  11061. return 1;
  11062. }
  11063. //static
  11064. int HBViewerAutomation::getEnvironmentStatus(lua_State* state)
  11065. {
  11066. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  11067. HBViewerAutomation* self = findInstance(state);
  11068. if (!self) return 0;
  11069. if (self->isThreaded())
  11070. {
  11071. HBAutomationThread* threadp = (HBAutomationThread*)self;
  11072. return threadp->callMainFunction("GetEnvironmentStatus");
  11073. }
  11074. S32 n = lua_gettop(state);
  11075. if (n)
  11076. {
  11077. luaL_error(state, "%d arguments passed; expected 0.", n);
  11078. }
  11079. lua_newtable(state);
  11080. #if 1 // *TODO: remove ?
  11081. lua_pushstring(state, "enhanced rendering");
  11082. lua_pushboolean(state, true);
  11083. lua_rawset(state, -3);
  11084. lua_pushstring(state, "windlight override");
  11085. lua_pushboolean(state, true);
  11086. lua_rawset(state, -3);
  11087. #endif
  11088. static LLCachedControl<bool> local(gSavedSettings, "UseLocalEnvironment");
  11089. lua_pushstring(state, "local environment");
  11090. lua_pushboolean(state, (bool)local);
  11091. lua_rawset(state, -3);
  11092. static LLCachedControl<bool> parcel(gSavedSettings,
  11093. "UseParcelEnvironment");
  11094. lua_pushstring(state, "parcel environment");
  11095. lua_pushboolean(state, (bool)parcel);
  11096. lua_rawset(state, -3);
  11097. static LLCachedControl<bool> estate(gSavedSettings, "UseWLEstateTime");
  11098. bool region_time = estate;
  11099. if (region_time)
  11100. {
  11101. region_time = gWLSkyParamMgr.mAnimator.mIsRunning;
  11102. }
  11103. lua_pushstring(state, "region time");
  11104. lua_pushboolean(state, region_time);
  11105. lua_rawset(state, -3);
  11106. lua_pushstring(state, "rlv locked");
  11107. lua_pushboolean(state, gRLenabled && gRLInterface.mContainsSetenv);
  11108. lua_rawset(state, -3);
  11109. return 1;
  11110. }
  11111. void HBViewerAutomation::onAutoPilotFinished(const std::string& type,
  11112. bool reached, bool user_cancel)
  11113. {
  11114. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  11115. if (!mHasOnAutoPilotFinished || !mLuaState)
  11116. {
  11117. return;
  11118. }
  11119. LL_DEBUGS("Lua") << "Invoking OnAutoPilotFinished Lua callback. type="
  11120. << type << " - reached=" << reached << " - user_cancel="
  11121. << user_cancel << LL_ENDL;
  11122. lua_getglobal(mLuaState, "OnAutoPilotFinished");
  11123. lua_pushstring(mLuaState, type.c_str());
  11124. lua_pushboolean(mLuaState, reached);
  11125. lua_pushboolean(mLuaState, user_cancel);
  11126. resetTimer();
  11127. if (lua_pcall(mLuaState, 3, 0, 0) != LUA_OK)
  11128. {
  11129. reportError();
  11130. }
  11131. }
  11132. //static
  11133. int HBViewerAutomation::agentAutoPilotToPos(lua_State* state)
  11134. {
  11135. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  11136. HBViewerAutomation* self = findInstance(state);
  11137. if (!self || !isAgentAvatarValid()) return 0;
  11138. if (self->isThreaded())
  11139. {
  11140. HBAutomationThread* threadp = (HBAutomationThread*)self;
  11141. return threadp->callMainFunction("AgentAutoPilotToPos");
  11142. }
  11143. S32 n = lua_gettop(state);
  11144. if (n < 2 || n > 5)
  11145. {
  11146. luaL_error(state, "%d arguments passed; expected 2 to 5.", n);
  11147. }
  11148. F64 pos_x = luaL_checknumber(state, 1);
  11149. F64 pos_y = luaL_checknumber(state, 2);
  11150. F64 pos_z = -1.0;
  11151. if (n >= 3)
  11152. {
  11153. pos_z = luaL_checknumber(state, 3);
  11154. }
  11155. if (pos_z < 0.0)
  11156. {
  11157. pos_z = gAgentAvatarp->getPositionGlobal().mdV[VZ];
  11158. }
  11159. bool allow_flying = n >= 4 && lua_toboolean(state, 4);
  11160. F32 stop_distance = 1.f;
  11161. if (n >= 5)
  11162. {
  11163. stop_distance = luaL_checknumber(state, 5);
  11164. }
  11165. lua_pop(state, n);
  11166. static S32 counter = 0;
  11167. std::string type = llformat("Lua auto-pilot %d", ++counter);
  11168. gAgentPilot.startAutoPilotGlobal(LLVector3d(pos_x, pos_y, pos_z),
  11169. type, NULL, NULL, NULL, stop_distance,
  11170. 0.03f, allow_flying);
  11171. lua_pushstring(state, type.c_str());
  11172. return 1;
  11173. }
  11174. //static
  11175. int HBViewerAutomation::agentAutoPilotFollow(lua_State* state)
  11176. {
  11177. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  11178. HBViewerAutomation* self = findInstance(state);
  11179. if (!self) return 0;
  11180. if (self->isThreaded())
  11181. {
  11182. HBAutomationThread* threadp = (HBAutomationThread*)self;
  11183. return threadp->callMainFunction("AgentAutoPilotFollow");
  11184. }
  11185. S32 n = lua_gettop(state);
  11186. if (n < 1 || n > 3)
  11187. {
  11188. luaL_error(state, "%d arguments passed; expected 1 to 3.", n);
  11189. }
  11190. LLUUID id(luaL_checkstring(state, 1), false);
  11191. bool allow_flying = n >= 2 && lua_toboolean(state, 2);
  11192. F32 stop_distance = 1.f;
  11193. if (n >= 3)
  11194. {
  11195. stop_distance = luaL_checknumber(state, 3);
  11196. }
  11197. lua_pop(state, n);
  11198. bool success = gAgentPilot.startFollowPilot(id, allow_flying,
  11199. stop_distance);
  11200. lua_pushboolean(state, success);
  11201. return 1;
  11202. }
  11203. //static
  11204. int HBViewerAutomation::agentAutoPilotStop(lua_State* state)
  11205. {
  11206. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  11207. HBViewerAutomation* self = findInstance(state);
  11208. if (!self) return 0;
  11209. if (self->isThreaded())
  11210. {
  11211. HBAutomationThread* threadp = (HBAutomationThread*)self;
  11212. return threadp->callMainFunction("AgentAutoPilotStop");
  11213. }
  11214. S32 n = lua_gettop(state);
  11215. if (n)
  11216. {
  11217. luaL_error(state, "%d arguments passed; expected 0.", n);
  11218. }
  11219. gAgentPilot.stopAutoPilot();
  11220. return 0;
  11221. }
  11222. //static
  11223. int HBViewerAutomation::agentAutoPilotLoad(lua_State* state)
  11224. {
  11225. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  11226. HBViewerAutomation* self = findInstance(state);
  11227. if (!self) return 0;
  11228. if (self->isThreaded())
  11229. {
  11230. HBAutomationThread* threadp = (HBAutomationThread*)self;
  11231. return threadp->callMainFunction("AgentAutoPilotLoad");
  11232. }
  11233. S32 n = lua_gettop(state);
  11234. if (n > 1)
  11235. {
  11236. luaL_error(state, "%d arguments passed; expected 0 or 1.", n);
  11237. }
  11238. std::string filename;
  11239. if (n)
  11240. {
  11241. filename = luaL_checkstring(state, 1);
  11242. lua_pop(state, 1);
  11243. }
  11244. else
  11245. {
  11246. filename = gSavedSettings.getString("AutoPilotFile");
  11247. }
  11248. lua_pushboolean(state, gAgentPilot.load(filename));
  11249. return 1;
  11250. }
  11251. //static
  11252. int HBViewerAutomation::agentAutoPilotSave(lua_State* state)
  11253. {
  11254. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  11255. HBViewerAutomation* self = findInstance(state);
  11256. if (!self) return 0;
  11257. if (self->isThreaded())
  11258. {
  11259. HBAutomationThread* threadp = (HBAutomationThread*)self;
  11260. return threadp->callMainFunction("AgentAutoPilotSave");
  11261. }
  11262. S32 n = lua_gettop(state);
  11263. if (n > 1)
  11264. {
  11265. luaL_error(state, "%d arguments passed; expected 0 or 1.", n);
  11266. }
  11267. std::string filename;
  11268. if (n)
  11269. {
  11270. filename = luaL_checkstring(state, 1);
  11271. lua_pop(state, 1);
  11272. }
  11273. else
  11274. {
  11275. filename = gSavedSettings.getString("AutoPilotFile");
  11276. }
  11277. lua_pushboolean(state, gAgentPilot.save(filename));
  11278. return 1;
  11279. }
  11280. //static
  11281. int HBViewerAutomation::agentAutoPilotRemove(lua_State* state)
  11282. {
  11283. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  11284. HBViewerAutomation* self = findInstance(state);
  11285. if (!self) return 0;
  11286. if (self->isThreaded())
  11287. {
  11288. HBAutomationThread* threadp = (HBAutomationThread*)self;
  11289. return threadp->callMainFunction("AgentAutoPilotRemove");
  11290. }
  11291. S32 n = lua_gettop(state);
  11292. if (n > 1)
  11293. {
  11294. luaL_error(state, "%d arguments passed; expected 0 or 1.", n);
  11295. }
  11296. std::string filename;
  11297. if (n)
  11298. {
  11299. filename = luaL_checkstring(state, 1);
  11300. lua_pop(state, 1);
  11301. }
  11302. else
  11303. {
  11304. filename = gSavedSettings.getString("AutoPilotFile");
  11305. }
  11306. LLAgentPilot::remove(filename);
  11307. return 0;
  11308. }
  11309. //static
  11310. int HBViewerAutomation::agentAutoPilotRecord(lua_State* state)
  11311. {
  11312. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  11313. HBViewerAutomation* self = findInstance(state);
  11314. if (!self) return 0;
  11315. if (self->isThreaded())
  11316. {
  11317. HBAutomationThread* threadp = (HBAutomationThread*)self;
  11318. return threadp->callMainFunction("AgentAutoPilotRecord");
  11319. }
  11320. S32 n = lua_gettop(state);
  11321. if (n != 1)
  11322. {
  11323. luaL_error(state, "%d arguments passed; expected 1.", n);
  11324. }
  11325. bool start = lua_toboolean(state, 1);
  11326. lua_pop(state, 1);
  11327. bool success = start ? gAgentPilot.startRecord()
  11328. : gAgentPilot.stopRecord();
  11329. lua_pushboolean(state, success);
  11330. return 1;
  11331. }
  11332. //static
  11333. int HBViewerAutomation::agentAutoPilotReplay(lua_State* state)
  11334. {
  11335. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  11336. HBViewerAutomation* self = findInstance(state);
  11337. if (!self) return 0;
  11338. if (self->isThreaded())
  11339. {
  11340. HBAutomationThread* threadp = (HBAutomationThread*)self;
  11341. return threadp->callMainFunction("AgentAutoPilotReplay");
  11342. }
  11343. S32 n = lua_gettop(state);
  11344. if (n < 1 || n > 3)
  11345. {
  11346. luaL_error(state, "%d arguments passed; expected 1 to 3.", n);
  11347. }
  11348. bool start = lua_toboolean(state, 1);
  11349. if (!start && n > 1)
  11350. {
  11351. luaL_error(state,
  11352. "%d arguments passed; expected only 1 for a stop action.",
  11353. n);
  11354. }
  11355. S32 runs = -1;
  11356. if (n >= 2)
  11357. {
  11358. runs = lua_tointeger(state, 2);
  11359. }
  11360. bool allow_flying = n >= 3 && lua_toboolean(state, 3);
  11361. lua_pop(state, n);
  11362. bool success = start ? gAgentPilot.startPlayback(runs, allow_flying)
  11363. : gAgentPilot.stopPlayback();
  11364. lua_pushboolean(state, success);
  11365. return 1;
  11366. }
  11367. #if LL_PUPPETRY
  11368. //static
  11369. int HBViewerAutomation::agentPuppetryStart(lua_State* state)
  11370. {
  11371. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  11372. S32 n = lua_gettop(state);
  11373. if (n > 2)
  11374. {
  11375. luaL_error(state, "%d arguments passed; expected 0 to 2.", n);
  11376. }
  11377. bool is_plugin_filename = n >= 2 && lua_toboolean(state, 2);
  11378. bool is_saved_cmd;
  11379. std::string command;
  11380. if (n)
  11381. {
  11382. is_saved_cmd = false;
  11383. command = luaL_checkstring(state, 1);
  11384. lua_pop(state, n);
  11385. }
  11386. else
  11387. {
  11388. is_saved_cmd = true;
  11389. command = gSavedSettings.getString("PuppetryLastCommand");
  11390. }
  11391. bool success = false;
  11392. if (!command.empty() && LLPuppetMotion::enabled())
  11393. {
  11394. LLPuppetModule* modulep = LLPuppetModule::getInstance();
  11395. // Only try and launch when no module is already running
  11396. if (!modulep->havePuppetModule())
  11397. {
  11398. if (is_plugin_filename)
  11399. {
  11400. success = LLFile::exists(command);
  11401. if (success)
  11402. {
  11403. success = modulep->launchLeapPlugin(command);
  11404. }
  11405. }
  11406. else
  11407. {
  11408. success = modulep->launchLeapCommand(command);
  11409. if (!success && is_saved_cmd)
  11410. {
  11411. // Clear the command, since it is obviously invalid... HB
  11412. gSavedSettings.setString("PuppetryLastCommand", "");
  11413. }
  11414. }
  11415. }
  11416. }
  11417. lua_pushboolean(state, success);
  11418. return 1;
  11419. }
  11420. //static
  11421. int HBViewerAutomation::agentPuppetryStop(lua_State* state)
  11422. {
  11423. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  11424. S32 n = lua_gettop(state);
  11425. if (n)
  11426. {
  11427. luaL_error(state, "%d arguments passed; expected 0.", n);
  11428. }
  11429. if (LLPuppetMotion::enabled())
  11430. {
  11431. LLPuppetModule* modulep = LLPuppetModule::getInstance();
  11432. if (modulep->havePuppetModule())
  11433. {
  11434. modulep->setSending(false);
  11435. modulep->setEcho(false);
  11436. modulep->clearLeapModule();
  11437. }
  11438. }
  11439. return 0;
  11440. }
  11441. #endif
  11442. //static
  11443. int HBViewerAutomation::agentRotate(lua_State* state)
  11444. {
  11445. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  11446. HBViewerAutomation* self = findInstance(state);
  11447. if (!self) return 0;
  11448. if (self->isThreaded())
  11449. {
  11450. HBAutomationThread* threadp = (HBAutomationThread*)self;
  11451. return threadp->callMainFunction("AgentRotate");
  11452. }
  11453. S32 n = lua_gettop(state);
  11454. if (n != 1)
  11455. {
  11456. luaL_error(state, "%d arguments passed; expected 1.", n);
  11457. }
  11458. F32 angle = luaL_checknumber(state, 1);
  11459. if (angle > 360.f)
  11460. {
  11461. angle = fmodf(angle, 360.f);
  11462. }
  11463. else if (angle < 0.f)
  11464. {
  11465. angle = 360.f - fmodf(-angle, 360.f);
  11466. }
  11467. lua_pop(state, 1);
  11468. gAgent.startCameraAnimation();
  11469. LLVector3 rot(0.f, 1.f, 0.f);
  11470. rot = rot.rotVec(-angle * DEG_TO_RAD, LLVector3::z_axis);
  11471. rot.normalize();
  11472. gAgent.resetAxes(rot);
  11473. return 0;
  11474. }
  11475. //static
  11476. int HBViewerAutomation::getAgentRotation(lua_State* state)
  11477. {
  11478. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  11479. if (!state) return 0; // Paranoia
  11480. S32 n = lua_gettop(state);
  11481. if (n != 0)
  11482. {
  11483. luaL_error(state, "%d arguments passed; expected 0.", n);
  11484. }
  11485. const LLVector3& at_axis = gAgent.getAtAxis();
  11486. F32 rotation = atan2f(at_axis.mV[VX], at_axis.mV[VY]) * RAD_TO_DEG;
  11487. if (rotation < 0.f)
  11488. {
  11489. rotation += 360.f;
  11490. }
  11491. lua_pushnumber(state, rotation);
  11492. return 1;
  11493. }
  11494. //static
  11495. int HBViewerAutomation::teleportAgentHome(lua_State* state)
  11496. {
  11497. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  11498. HBViewerAutomation* self = findInstance(state);
  11499. if (!self) return 0;
  11500. if (self->isThreaded())
  11501. {
  11502. HBAutomationThread* threadp = (HBAutomationThread*)self;
  11503. return threadp->callMainFunction("TeleportAgentHome");
  11504. }
  11505. S32 n = lua_gettop(state);
  11506. if (n)
  11507. {
  11508. luaL_error(state, "%d arguments passed; expected 0.", n);
  11509. }
  11510. gAgent.teleportHome();
  11511. return 0;
  11512. }
  11513. //static
  11514. int HBViewerAutomation::teleportAgentToPos(lua_State* state)
  11515. {
  11516. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  11517. HBViewerAutomation* self = findInstance(state);
  11518. if (!self) return 0;
  11519. if (self->isThreaded())
  11520. {
  11521. HBAutomationThread* threadp = (HBAutomationThread*)self;
  11522. return threadp->callMainFunction("TeleportAgentToPos");
  11523. }
  11524. F64 pos_x, pos_y, pos_z;
  11525. bool preserve_look_at;
  11526. S32 n = lua_gettop(state);
  11527. if ((n == 1 || n == 2) && lua_type(state, 1) == LUA_TSTRING)
  11528. {
  11529. std::string pos_str(luaL_checkstring(state, 1));
  11530. LLVector3d global_pos;
  11531. if (!LLVector3d::parseVector3d(pos_str, &global_pos))
  11532. {
  11533. luaL_error(state, "Invalid position string: %s", pos_str.c_str());
  11534. }
  11535. pos_x = global_pos.mdV[VX];
  11536. pos_y = global_pos.mdV[VY];
  11537. pos_z = global_pos.mdV[VZ];
  11538. preserve_look_at = n == 2 && lua_toboolean(state, 2);
  11539. }
  11540. else if (n >= 2 && n <= 4)
  11541. {
  11542. pos_x = luaL_checknumber(state, 1);
  11543. pos_y = luaL_checknumber(state, 2);
  11544. pos_z = n >= 3 ? luaL_checknumber(state, 3) : 0.0;
  11545. preserve_look_at = n == 4 && lua_toboolean(state, 4);
  11546. }
  11547. else
  11548. {
  11549. luaL_error(state, "%d arguments passed; expected 2 to 4.", n);
  11550. return 0; // To avoid "<var> may be used uninitialized" gcc warnings
  11551. }
  11552. lua_pop(state, n);
  11553. if (preserve_look_at)
  11554. {
  11555. gAgent.teleportViaLocationLookAt(LLVector3d(pos_x, pos_y, pos_z));
  11556. }
  11557. else
  11558. {
  11559. gAgent.teleportViaLocation(LLVector3d(pos_x, pos_y, pos_z));
  11560. }
  11561. return 0;
  11562. }
  11563. //static
  11564. void HBViewerAutomation::onIdleSimChange(void* userdata)
  11565. {
  11566. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  11567. HBViewerAutomation* self = (HBViewerAutomation*)userdata;
  11568. if (!self || self != gAutomationp || !self->mHasOnFailedTPSimChange ||
  11569. // Is a teleport in progress ?
  11570. gAgent.teleportInProgress())
  11571. {
  11572. return;
  11573. }
  11574. // Are there a failed teleported sim handle and valid TP coordinates ?
  11575. U64 handle = gAgent.getTeleportedSimHandle();
  11576. if (!handle || gAgent.getTeleportedPosGlobal().isExactlyZero())
  11577. {
  11578. return;
  11579. }
  11580. LLSimInfo* siminfo = gWorldMap.simInfoFromHandle(handle);
  11581. if (!siminfo)
  11582. {
  11583. return;
  11584. }
  11585. bool sim_is_down = siminfo->mAccess == SIM_ACCESS_DOWN;
  11586. F64 update_interval = sim_is_down ? 15.0 : 4.0;
  11587. F64 current_time = LLTimer::getElapsedSeconds();
  11588. F64 delta = current_time - siminfo->mAgentsUpdateTime;
  11589. if (delta > update_interval)
  11590. {
  11591. // Time to update our sim info
  11592. siminfo->mAgentsUpdateTime = current_time;
  11593. if (sim_is_down)
  11594. {
  11595. gWorldMap.sendHandleRegionRequest(handle);
  11596. }
  11597. else
  11598. {
  11599. gWorldMap.sendItemRequest(MAP_ITEM_AGENT_LOCATIONS, handle);
  11600. }
  11601. }
  11602. else if (!sim_is_down)
  11603. {
  11604. // Count the number of agents in sim, if that data is available
  11605. LLWorldMap::agent_list_map_t::iterator counts_iter =
  11606. gWorldMap.mAgentLocationsMap.find(handle);
  11607. if (counts_iter != gWorldMap.mAgentLocationsMap.end())
  11608. {
  11609. S32 sim_agent_count = 0;
  11610. LLWorldMap::item_info_list_t& agentcounts = counts_iter->second;
  11611. for (LLWorldMap::item_info_list_t::iterator
  11612. iter = agentcounts.begin(), end = agentcounts.end();
  11613. iter != end; ++iter)
  11614. {
  11615. sim_agent_count += iter->mExtra;
  11616. }
  11617. // If the number of agents in the sim changed then fire the
  11618. // OnFailedTPSimChange() Lua callback.
  11619. if (sim_agent_count != siminfo->mAgentsCount)
  11620. {
  11621. siminfo->mAgentsCount = sim_agent_count;
  11622. self->onFailedTPSimChange(sim_agent_count);
  11623. }
  11624. }
  11625. }
  11626. }
  11627. //static
  11628. int HBViewerAutomation::callbackAfter(lua_State* state)
  11629. {
  11630. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  11631. if (!state) return 0; // Paranoia
  11632. S32 n = lua_gettop(state);
  11633. if (n < 2)
  11634. {
  11635. luaL_error(state, "%d arguments passed; expected at least 2.", n);
  11636. }
  11637. F32 delay = llclamp((F64)luaL_checknumber(state, 1), 1.0, (F64)F32_MAX);
  11638. if (lua_type(state, 2) != LUA_TFUNCTION)
  11639. {
  11640. luaL_error(state, "The second argument must be a function");
  11641. }
  11642. // Store the function and the parameters into a table
  11643. lua_newtable(state);
  11644. for (S32 i = 2; i <= n; ++i)
  11645. {
  11646. lua_pushvalue(state, i);
  11647. lua_rawseti(state, -2, i - 1);
  11648. }
  11649. // Store the number of elements in the table
  11650. lua_pushliteral(state, "n");
  11651. lua_pushinteger(state, n - 1);
  11652. lua_rawset(state, -3);
  11653. // Store the table into registry and get the corresponding unique reference
  11654. int ref = luaL_ref(state, LUA_REGISTRYINDEX);
  11655. lua_settop(state, 0);
  11656. LL_DEBUGS("Lua") << "Queuing Lua callback with reference: " << ref
  11657. << " - Number of function arguments: " << n - 2
  11658. << LL_ENDL;
  11659. doAfterInterval(boost::bind(&doAfterIntervalCallback, state, ref), delay);
  11660. return 0;
  11661. }
  11662. //static
  11663. void HBViewerAutomation::doAfterIntervalCallback(lua_State* state, int ref)
  11664. {
  11665. LL_TRACY_TIMER(TRC_LUA_CALLBACK);
  11666. HBViewerAutomation* self = findInstance(state);
  11667. if (!self) return;
  11668. LL_DEBUGS("Lua") << "Invoking Lua callback associated with reference: "
  11669. << ref << LL_ENDL;
  11670. // Get our table back from registry
  11671. int type = lua_rawgeti(state, LUA_REGISTRYINDEX, ref);
  11672. if (type != LUA_TTABLE)
  11673. {
  11674. llwarns << "Bad type (" << lua_typename(state, type)
  11675. << ") for object referenced at: " << ref << ". Aborting."
  11676. << llendl;
  11677. lua_settop(state, 0);
  11678. return;
  11679. }
  11680. // Get the number of elements in the table
  11681. lua_pushliteral(state, "n");
  11682. type = lua_rawget(state, -2);
  11683. if (type != LUA_TNUMBER)
  11684. {
  11685. llwarns << "Bad callback table format ('n' is missing or bears an invalid type). Aborting."
  11686. << llendl;
  11687. lua_settop(state, 0);
  11688. return;
  11689. }
  11690. S32 n = lua_tointeger(state, -1);
  11691. lua_pop(state, 1);
  11692. // Copy each table element back onto the stack
  11693. LL_DEBUGS("Lua") << "Retrieving the function and " << n - 1
  11694. << " argument(s)" << LL_ENDL;
  11695. for (S32 i = 1; i <= n; ++i)
  11696. {
  11697. lua_rawgeti(state, 1, i);
  11698. if (i == 1 && lua_type(state, -1) != LUA_TFUNCTION)
  11699. {
  11700. llwarns << "Invalid callback table (no function). Aborting."
  11701. << llendl;
  11702. return;
  11703. }
  11704. }
  11705. // Remove the table
  11706. lua_remove(state, -n - 1);
  11707. // Dereference the callback data from LUA_REGISTRYINDEX
  11708. luaL_unref(state, LUA_REGISTRYINDEX, ref);
  11709. LL_DEBUGS("Lua") << "Calling the Lua function with " << n - 1
  11710. << " argument(s)" << LL_ENDL;
  11711. self->resetTimer();
  11712. if (lua_pcall(state, n - 1, 0, 0) != LUA_OK)
  11713. {
  11714. self->reportError();
  11715. }
  11716. }
  11717. static void lua_force_quit()
  11718. {
  11719. gAppViewerp->forceQuit();
  11720. }
  11721. //static
  11722. int HBViewerAutomation::forceQuit(lua_State* state)
  11723. {
  11724. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  11725. HBViewerAutomation* self = findInstance(state);
  11726. if (!self || self != gAutomationp) return 0;
  11727. S32 n = lua_gettop(state);
  11728. if (n > 1)
  11729. {
  11730. luaL_error(state, "%d arguments passed; expected 0 or 1.", n);
  11731. }
  11732. S32 exit_code = 0;
  11733. if (n)
  11734. {
  11735. exit_code = luaL_checknumber(state, 1);
  11736. lua_pop(state, 1);
  11737. }
  11738. if (exit_code &&
  11739. (exit_code < LLAppViewer::VIEWER_EXIT_CODES || exit_code > 125))
  11740. {
  11741. luaL_error(state,
  11742. "Invalid exit code (must be 0 or in the range [%d-125]).",
  11743. LLAppViewer::VIEWER_EXIT_CODES);
  11744. }
  11745. gExitCode = exit_code;
  11746. LLSD args;
  11747. args["CODE"] = exit_code;
  11748. gNotifications.add("LuaForceQuit", args);
  11749. doAfterInterval(lua_force_quit, 5.f);
  11750. return 0;
  11751. }
  11752. //static
  11753. int HBViewerAutomation::minimizeWindow(lua_State* state)
  11754. {
  11755. LL_TRACY_TIMER(TRC_LUA_FUNCTION);
  11756. if (!state || !gWindowp) return 0; // Paranoia
  11757. S32 n = lua_gettop(state);
  11758. if (n)
  11759. {
  11760. luaL_error(state, "%d arguments passed; expected 0.", n);
  11761. }
  11762. gWindowp->minimize();
  11763. return 0;
  11764. }
  11765. ///////////////////////////////////////////////////////////////////////////////
  11766. // HBLuaSideBar class
  11767. ///////////////////////////////////////////////////////////////////////////////
  11768. // This is the maximum number of buttons in the Lua side bar. The buttons must
  11769. // be named "btnN" with N=1 to 20 and appear in a sequence without hole in the
  11770. // numbering.
  11771. constexpr U32 MAX_NUMBER_OF_BUTTONS = 20;
  11772. HBLuaSideBar* gLuaSideBarp = NULL;
  11773. HBLuaSideBar::HBLuaSideBar()
  11774. : LLPanel("lua side bar", LLRect(), BORDER_NO),
  11775. mNumberOfButtons(0),
  11776. mLeftSide(false),
  11777. mHidden(false),
  11778. mHideOnRightClick(false)
  11779. {
  11780. llassert_always(gLuaSideBarp == NULL); // Only one instance allowed
  11781. LLUICtrlFactory::getInstance()->buildPanel(this,
  11782. "panel_lua_sidebar.xml");
  11783. LLControlVariable* ctrl = gSavedSettings.getControl("LuaSideBarOnLeft");
  11784. if (ctrl)
  11785. {
  11786. ctrl->getSignal()->connect(boost::bind(&HBLuaSideBar::handleSideChanged,
  11787. _2));
  11788. mLeftSide = ctrl->getValue().asBoolean();
  11789. }
  11790. if (!mLeftSide)
  11791. {
  11792. setFollows(FOLLOWS_TOP | FOLLOWS_RIGHT);
  11793. }
  11794. setMouseOpaque(false);
  11795. setIsChrome(true);
  11796. setFocusRoot(true);
  11797. setShape();
  11798. std::string name;
  11799. mCommands.resize(MAX_NUMBER_OF_BUTTONS);
  11800. for (U32 i = 1; i <= MAX_NUMBER_OF_BUTTONS; ++i)
  11801. {
  11802. name = llformat("btn%d", i);
  11803. LLButton* button = getChild<LLButton>(name.c_str(), true, false);
  11804. if (!button) break;
  11805. ++mNumberOfButtons;
  11806. mCommands.emplace_back("");
  11807. button->setClickedCallback(onButtonClicked, (void*)(intptr_t)i);
  11808. button->setVisible(false);
  11809. button->setImageDisabled("square_button_disabled.tga");
  11810. button->setImageUnselected("square_button_enabled.tga");
  11811. button->setImageSelected("square_button_selected.tga");
  11812. }
  11813. LL_DEBUGS("Lua") << "Found " << mNumberOfButtons << " in the side bar"
  11814. << LL_ENDL;
  11815. gLuaSideBarp = this;
  11816. }
  11817. //virtual
  11818. HBLuaSideBar::~HBLuaSideBar()
  11819. {
  11820. gLuaSideBarp = NULL;
  11821. }
  11822. //virtual
  11823. void HBLuaSideBar::draw()
  11824. {
  11825. if (!mActiveButtons.empty() && LLStartUp::isLoggedIn())
  11826. {
  11827. LLPanel::draw();
  11828. }
  11829. }
  11830. //virtual
  11831. void HBLuaSideBar::reshape(S32 width, S32 height, bool called_from_parent)
  11832. {
  11833. LLView::reshape(width, height, called_from_parent);
  11834. setShape();
  11835. }
  11836. //virtual
  11837. void HBLuaSideBar::setVisible(bool visible)
  11838. {
  11839. LLPanel::setVisible(visible && !mHidden);
  11840. }
  11841. //virtual
  11842. bool HBLuaSideBar::handleRightMouseDown(S32 x, S32 y, MASK mask)
  11843. {
  11844. if (mHideOnRightClick)
  11845. {
  11846. setHidden(true);
  11847. return true;
  11848. }
  11849. return LLPanel::handleRightMouseDown(x, y, mask);
  11850. }
  11851. void HBLuaSideBar::setShape()
  11852. {
  11853. if (gViewerWindowp)
  11854. {
  11855. LLRect rect = getRect();
  11856. S32 height = rect.getHeight();
  11857. S32 width = rect.getWidth();
  11858. rect.mBottom = CHAT_BAR_HEIGHT +
  11859. (gViewerWindowp->getWindowHeight() - height) / 2;
  11860. rect.mTop = rect.mBottom + height;
  11861. if (mLeftSide)
  11862. {
  11863. rect.mLeft = 1;
  11864. rect.mRight = rect.mLeft + width;
  11865. }
  11866. else
  11867. {
  11868. rect.mRight = gViewerWindowp->getWindowWidth() - 1;
  11869. rect.mLeft = rect.mRight - width;
  11870. }
  11871. setRect(rect);
  11872. updateBoundingRect();
  11873. }
  11874. }
  11875. void HBLuaSideBar::setHidden(bool hidden)
  11876. {
  11877. mHidden = hidden;
  11878. LLPanel::setVisible(!hidden && !gAgent.cameraMouselook());
  11879. if (gAutomationp)
  11880. {
  11881. gAutomationp->onSideBarVisibilityChange(!hidden);
  11882. }
  11883. }
  11884. U32 HBLuaSideBar::setButton(U32 number, std::string icon, std::string command,
  11885. const std::string& tooltip)
  11886. {
  11887. if (number > mNumberOfButtons)
  11888. {
  11889. llwarns << "Invalid button number: " << number
  11890. << ". Valid range is 1 to " << mNumberOfButtons
  11891. << ", inclusive (and 0 for auto slot affectation)." << llendl;
  11892. return 0;
  11893. }
  11894. if (!number)
  11895. {
  11896. // Find the first empty button slot, if any.
  11897. for (U32 i = 1; i <= mNumberOfButtons; ++i)
  11898. {
  11899. if (!mActiveButtons.count(i))
  11900. {
  11901. number = i;
  11902. break;
  11903. }
  11904. }
  11905. if (!number)
  11906. {
  11907. llwarns << "No free button slot left: all "
  11908. << mNumberOfButtons << " are in use in the side bar."
  11909. << llendl;
  11910. return 0;
  11911. }
  11912. }
  11913. std::string name = llformat("btn%d", number);
  11914. LLButton* button = getChild<LLButton>(name.c_str(), true, false);
  11915. if (!button) return 0;
  11916. if (command.empty() && !mCommands[number - 1].empty())
  11917. {
  11918. command = mCommands[number - 1];
  11919. }
  11920. else
  11921. {
  11922. // Reset any existing debug setting control and toggle state
  11923. button->setControlName("", NULL);
  11924. button->setToggleState(false);
  11925. button->setIsToggle(false);
  11926. }
  11927. bool visible = !icon.empty() && !command.empty();
  11928. if (visible)
  11929. {
  11930. // If first character is an UTF-8 one, or there are only 1 or 2 ASCII
  11931. // characters, interpret the icon name as a text label.
  11932. if ((U8)icon[0] > 127 || icon.length() < 3)
  11933. {
  11934. button->setLabel(icon);
  11935. button->setImageOverlay(LLUIImagePtr(NULL));
  11936. }
  11937. else
  11938. {
  11939. LLFontGL::HAlign alignment = LLFontGL::HCENTER;
  11940. size_t i = icon.find('|');
  11941. if (i != std::string::npos && i < icon.length() - 1)
  11942. {
  11943. std::string align_str = icon.substr(0, i);
  11944. icon = icon.substr(i + 1);
  11945. if (align_str == "left")
  11946. {
  11947. alignment = LLFontGL::LEFT;
  11948. }
  11949. else if (align_str == "right")
  11950. {
  11951. alignment = LLFontGL::RIGHT;
  11952. }
  11953. }
  11954. LLUIImagePtr image = LLUI::getUIImage(icon);
  11955. if (image.notNull())
  11956. {
  11957. button->setLabel(LLStringUtil::null);
  11958. button->setImageOverlay(image, alignment);
  11959. }
  11960. }
  11961. mActiveButtons.insert(number);
  11962. mCommands[number - 1] = command;
  11963. button->setToolTip(tooltip);
  11964. }
  11965. else
  11966. {
  11967. mActiveButtons.erase(number);
  11968. mCommands[number - 1].clear();
  11969. button->setToolTip(LLStringUtil::null);
  11970. }
  11971. button->setVisible(visible);
  11972. button->setEnabled(visible);
  11973. LL_DEBUGS("Lua") << (visible ? "Set" : "Reset") << " button " << number
  11974. << LL_ENDL;
  11975. return number;
  11976. }
  11977. S32 HBLuaSideBar::buttonToggle(U32 number, S32 toggle)
  11978. {
  11979. if (number == 0 || number > mNumberOfButtons)
  11980. {
  11981. llwarns << "Invalid button number: " << number
  11982. << ". Valid range is 1 to " << mNumberOfButtons
  11983. << ", inclusive." << llendl;
  11984. return -1;
  11985. }
  11986. std::string name = llformat("btn%d", number);
  11987. LLButton* button = getChild<LLButton>(name.c_str(), true, false);
  11988. if (!button || mCommands[number - 1].empty())
  11989. {
  11990. return -1;
  11991. }
  11992. S32 result = toggle;
  11993. switch (toggle)
  11994. {
  11995. case 0:
  11996. case 1:
  11997. button->setIsToggle(true);
  11998. button->setToggleState(toggle == 1);
  11999. break;
  12000. default:
  12001. result = button->getIsToggle() ? button->getToggleState() : -1;
  12002. }
  12003. return result;
  12004. }
  12005. void HBLuaSideBar::buttonSetControl(U32 number, LLControlVariable* control)
  12006. {
  12007. if (number == 0 || number > mNumberOfButtons)
  12008. {
  12009. llwarns << "Invalid button number: " << number
  12010. << ". Valid range is 1 to " << mNumberOfButtons
  12011. << ", inclusive." << llendl;
  12012. return;
  12013. }
  12014. std::string name = llformat("btn%d", number);
  12015. LLButton* button = getChild<LLButton>(name.c_str(), true, false);
  12016. if (button && !mCommands[number - 1].empty())
  12017. {
  12018. // Avoid changing the control debug setting value
  12019. if (control)
  12020. {
  12021. button->setIsToggle(true);
  12022. button->setToggleState(control->getValue().asBoolean());
  12023. button->setControlName(control->getName().c_str(), NULL);
  12024. }
  12025. else
  12026. {
  12027. button->setControlName(NULL, NULL);
  12028. button->setIsToggle(false);
  12029. button->setToggleState(false);
  12030. }
  12031. }
  12032. }
  12033. void HBLuaSideBar::setButtonEnabled(U32 number, bool enabled)
  12034. {
  12035. if (number == 0 || number > mNumberOfButtons)
  12036. {
  12037. llwarns << "Invalid button number: " << number
  12038. << ". Valid range is 1 to " << mNumberOfButtons
  12039. << ", inclusive." << llendl;
  12040. return;
  12041. }
  12042. std::string name = llformat("btn%d", number);
  12043. LLButton* button = getChild<LLButton>(name.c_str(), true, false);
  12044. if (button && !mCommands[number - 1].empty())
  12045. {
  12046. button->setEnabled(enabled);
  12047. }
  12048. }
  12049. void HBLuaSideBar::setButtonVisible(U32 number, bool visible)
  12050. {
  12051. if (number == 0 || number > mNumberOfButtons)
  12052. {
  12053. llwarns << "Invalid button number: " << number
  12054. << ". Valid range is 1 to " << mNumberOfButtons
  12055. << ", inclusive." << llendl;
  12056. return;
  12057. }
  12058. std::string name = llformat("btn%d", number);
  12059. LLButton* button = getChild<LLButton>(name.c_str(), true, false);
  12060. if (button && !mCommands[number - 1].empty())
  12061. {
  12062. button->setVisible(visible);
  12063. }
  12064. }
  12065. void HBLuaSideBar::removeAllButtons()
  12066. {
  12067. std::string name;
  12068. for (U32 i = 1; i <= mNumberOfButtons; ++i)
  12069. {
  12070. name = llformat("btn%d", i);
  12071. LLButton* button = getChild<LLButton>(name.c_str(), true, false);
  12072. if (button)
  12073. {
  12074. mCommands[i - 1].clear();
  12075. button->setEnabled(false);
  12076. button->setVisible(false);
  12077. button->setControlName("", NULL);
  12078. button->setToggleState(false);
  12079. button->setIsToggle(false);
  12080. }
  12081. }
  12082. mActiveButtons.clear();
  12083. }
  12084. //static
  12085. bool HBLuaSideBar::handleSideChanged(const LLSD& newvalue)
  12086. {
  12087. if (gLuaSideBarp)
  12088. {
  12089. gLuaSideBarp->mLeftSide = newvalue.asBoolean();
  12090. if (gLuaSideBarp->mLeftSide)
  12091. {
  12092. gLuaSideBarp->setFollows(FOLLOWS_TOP | FOLLOWS_LEFT);
  12093. }
  12094. else
  12095. {
  12096. gLuaSideBarp->setFollows(FOLLOWS_TOP | FOLLOWS_RIGHT);
  12097. }
  12098. gLuaSideBarp->setShape();
  12099. }
  12100. return true;
  12101. }
  12102. //static
  12103. void HBLuaSideBar::onButtonClicked(void* user_data)
  12104. {
  12105. U32 button = (U32)(intptr_t)user_data;
  12106. if (gLuaSideBarp && button > 0 && button <= gLuaSideBarp->mNumberOfButtons)
  12107. {
  12108. const std::string& command = gLuaSideBarp->mCommands[button - 1];
  12109. if (!command.empty() && command != "nop")
  12110. {
  12111. LL_DEBUGS("Lua") << "Executing command associated with button "
  12112. << button << LL_ENDL;
  12113. HBViewerAutomation::eval(command);
  12114. }
  12115. }
  12116. }
  12117. ///////////////////////////////////////////////////////////////////////////////
  12118. // HBLuaPieMenu class
  12119. ///////////////////////////////////////////////////////////////////////////////
  12120. HBLuaPieMenu* gLuaPiep = NULL;
  12121. HBLuaPieMenu::HBLuaPieMenu()
  12122. : LLPieMenu("Lua pie menu"),
  12123. mLastPickType(0)
  12124. {
  12125. llassert_always(gLuaPiep == NULL); // Only one instance allowed
  12126. if (!gMenuHolderp)
  12127. {
  12128. llwarns << "Menu holder is NULL ! Aborted." << llendl;
  12129. return;
  12130. }
  12131. const std::string filename = "menu_pie_lua.xml";
  12132. LLXMLNodePtr root;
  12133. if (!LLUICtrlFactory::getLayeredXMLNode(filename, root))
  12134. {
  12135. return;
  12136. }
  12137. if (!root->hasName(LL_PIE_MENU_TAG))
  12138. {
  12139. llwarns << "Root node should be named " << LL_PIE_MENU_TAG << " in: "
  12140. << filename << ". Aborted." << llendl;
  12141. return;
  12142. }
  12143. gMenuHolderp->addChild(this);
  12144. initXML(root, gMenuHolderp, LLUICtrlFactory::getInstance());
  12145. if (LLUI::sShowXUINames)
  12146. {
  12147. setToolTip(filename);
  12148. }
  12149. mLabels.reserve(48);
  12150. mCommands.reserve(48);
  12151. for (S32 i = 0; i < 48; ++i)
  12152. {
  12153. mLabels.emplace_back("");
  12154. mCommands.emplace_back("");
  12155. }
  12156. gLuaPiep = this;
  12157. }
  12158. //virtual
  12159. HBLuaPieMenu::~HBLuaPieMenu()
  12160. {
  12161. gLuaPiep = NULL;
  12162. }
  12163. void HBLuaPieMenu::removeAllSlices()
  12164. {
  12165. for (S32 i = 0; i < 48; ++i)
  12166. {
  12167. mLabels[i].clear();
  12168. mCommands[i].clear();
  12169. }
  12170. }
  12171. // Here, we duplicate the same logic for pie menu types selection as found in
  12172. // LLToolPie::handleRightClickPick()
  12173. S32 HBLuaPieMenu::getPickedType(const LLPickInfo& pick, LLViewerObject* object)
  12174. {
  12175. S32 type = PICKED_INVALID;
  12176. if ((!object || !object->isHUDAttachment()) &&
  12177. pick.mPickParticle && pick.mParticleOwnerID.notNull())
  12178. {
  12179. type = PICKED_PARTICLE;
  12180. }
  12181. else if (pick.mPickType == LLPickInfo::PICK_LAND)
  12182. {
  12183. type = PICKED_LAND;
  12184. }
  12185. else if (pick.mObjectID == gAgentID)
  12186. {
  12187. type = PICKED_SELF;
  12188. }
  12189. else if (object)
  12190. {
  12191. if (object->isAvatar())
  12192. {
  12193. type = PICKED_AVATAR;
  12194. }
  12195. else if (object->isAttachment())
  12196. {
  12197. type = PICKED_ATTACHMENT;
  12198. }
  12199. else
  12200. {
  12201. type = PICKED_OBJECT;
  12202. }
  12203. }
  12204. return type;
  12205. }
  12206. S32 HBLuaPieMenu::getPickedType(const LLPickInfo& pick)
  12207. {
  12208. const LLUUID& object_id = pick.mObjectID;
  12209. if (!mLastPickType || mLastPickId.isNull() || mLastPickId != object_id)
  12210. {
  12211. mLastPickId = object_id;
  12212. LLViewerObject* object = gObjectList.findObject(object_id);
  12213. if (object && object->isAttachment() && !object->isHUDAttachment() &&
  12214. !object->permYouOwner())
  12215. {
  12216. // Find the avatar corresponding to any attachment object we do not
  12217. // own
  12218. while (object->isAttachment())
  12219. {
  12220. object = (LLViewerObject*)object->getParent();
  12221. if (!object) return PICKED_INVALID; // Orphaned object ?
  12222. }
  12223. }
  12224. mLastPickType = getPickedType(pick, object);
  12225. }
  12226. return mLastPickType;
  12227. }
  12228. bool HBLuaPieMenu::onPieMenu(const LLPickInfo& pick, LLViewerObject* object)
  12229. {
  12230. mLastPickId = pick.mObjectID;
  12231. mLastPickType = getPickedType(pick, object);
  12232. if (mLastPickType == PICKED_INVALID)
  12233. {
  12234. return false;
  12235. }
  12236. LL_DEBUGS("Lua") << "Considering Lua pie menu type " << mLastPickType
  12237. << " for object " << mLastPickId << LL_ENDL;
  12238. if (object && mLastPickType >= PICKED_OBJECT)
  12239. {
  12240. //MK
  12241. if (gRLenabled && !object->isAvatar() && LLFloaterTools::isVisible() &&
  12242. !gRLInterface.canEdit(object))
  12243. {
  12244. gFloaterToolsp->close();
  12245. }
  12246. //mk
  12247. gMenuHolderp->setObjectSelection(gSelectMgr.getSelection());
  12248. }
  12249. bool got_slice = false;
  12250. if (mLastPickType)
  12251. {
  12252. // Setup the pie slices, if any, according to the pick type
  12253. std::string name;
  12254. for (S32 i = 0; i < 8; ++i)
  12255. {
  12256. S32 j = 8 * mLastPickType + i;
  12257. const std::string& label = mLabels[j];
  12258. bool enabled = !label.empty() && !mCommands[j].empty();
  12259. if (enabled)
  12260. {
  12261. got_slice = true;
  12262. }
  12263. name = llformat("slice%d", i + 1);
  12264. LLMenuItemGL* item = getChild<LLMenuItemGL>(name.c_str(), true,
  12265. false);
  12266. if (item)
  12267. {
  12268. item->setValue(label);
  12269. item->setEnabled(enabled);
  12270. }
  12271. else
  12272. {
  12273. llwarns_once << "Malformed menu_pie_lua.xml file" << llendl;
  12274. }
  12275. }
  12276. }
  12277. return got_slice;
  12278. }
  12279. void HBLuaPieMenu::onPieSliceClick(U32 slice, const LLPickInfo& pick)
  12280. {
  12281. if (slice < 1 || slice > 8) return;
  12282. S32 type = getPickedType(pick);
  12283. if (type == PICKED_INVALID) return;
  12284. S32 i = 8 * type + slice - 1;
  12285. const std::string& command = mCommands[i];
  12286. if (!command.empty() && command != "nop")
  12287. {
  12288. LL_DEBUGS("Lua") << "Executing command associated with pie slice "
  12289. << slice << " for pick type " << type << LL_ENDL;
  12290. // Setup a pie menu specific Lua global variable
  12291. std::string functions = "V_PIE_OBJ_ID=\"" + mLastPickId.asString() +
  12292. "\";";
  12293. // Setup a pie menu specific Lua function using the global variable
  12294. functions += "function GetPickedObjectID();return V_PIE_OBJ_ID;end;";
  12295. HBViewerAutomation::eval(functions + command);
  12296. }
  12297. if (gAutomationp)
  12298. {
  12299. gAutomationp->onLuaPieMenu(slice, mLastPickType, pick);
  12300. }
  12301. }
  12302. void HBLuaPieMenu::setSlice(S32 type, U32 slice, const std::string& label,
  12303. const std::string& command)
  12304. {
  12305. if (type < 0 || type >= PICKED_INVALID)
  12306. {
  12307. llwarns << "Invalid type value: " << type << ". Valid range is "
  12308. << PICKED_LAND << " to " << PICKED_INVALID - 1
  12309. << ", inclusive." << llendl;
  12310. return;
  12311. }
  12312. if (!slice)
  12313. {
  12314. LL_DEBUGS("Lua") << "Resetting pie type " << type << LL_ENDL;
  12315. for (S32 i = 8 * type; i < 8 * type + 8; ++i)
  12316. {
  12317. mLabels[i].clear();
  12318. mCommands[i].clear();
  12319. }
  12320. return;
  12321. }
  12322. if (slice > 8)
  12323. {
  12324. llwarns << "Invalid slice number: " << slice
  12325. << ". Valid range is 0 to 8, inclusive." << llendl;
  12326. return;
  12327. }
  12328. S32 i = 8 * type + slice - 1;
  12329. if (label.empty())
  12330. {
  12331. mLabels[i].clear();
  12332. mCommands[i].clear();
  12333. LL_DEBUGS("Lua") << "Reset slice " << slice << " for pie type " << type
  12334. << LL_ENDL;
  12335. }
  12336. else
  12337. {
  12338. mLabels[i] = label;
  12339. if (!command.empty())
  12340. {
  12341. mCommands[i] = command;
  12342. }
  12343. LL_DEBUGS("Lua") << "Set slice " << slice << " for pie type " << type
  12344. << LL_ENDL;
  12345. }
  12346. }
  12347. ///////////////////////////////////////////////////////////////////////////////
  12348. // HBLuaConsole class (floater to execute Lua code and print its output)
  12349. ///////////////////////////////////////////////////////////////////////////////
  12350. //static
  12351. std::vector<std::string> HBLuaConsole::sHistoryStorage;
  12352. constexpr U32 SIZE_FUDGE = 3; // *HACK: to account for lazy resizing...
  12353. HBLuaConsole::HBLuaConsole(const LLSD&)
  12354. : mHistoryIndex(sHistoryStorage.size()),
  12355. mSizeDelta(0),
  12356. mResizingAttempts(0)
  12357. {
  12358. LLUICtrlFactory::getInstance()->buildFloater(this,
  12359. "floater_lua_console.xml");
  12360. // If the user did not yet change the floater position, center the latter.
  12361. LLControlVariable* controlp =
  12362. gSavedSettings.getControl(getRectControl().c_str());
  12363. if (!controlp || controlp->isDefault())
  12364. {
  12365. center();
  12366. }
  12367. // See if we need to resize the input layout panel.
  12368. S32 height = gSavedSettings.getU32("LuaConsoleInputHeight");
  12369. if (height)
  12370. {
  12371. height = llmax(mInputLayout->getMinHeight(), height);
  12372. if (abs(mInputLayoutRect.getHeight() - height) > 4)
  12373. {
  12374. mResizingAttempts = 50;
  12375. }
  12376. }
  12377. }
  12378. //virtual
  12379. HBLuaConsole::~HBLuaConsole()
  12380. {
  12381. const LLRect& rect = mInputLayout->getRect();
  12382. if (rect != mInputLayoutRect)
  12383. {
  12384. // Not applicable any more: this panel has since been resized by the
  12385. // user !
  12386. mSizeDelta = 0;
  12387. }
  12388. U32 height = llmax(mInputLayout->getMinHeight(),
  12389. rect.getHeight() + mSizeDelta);
  12390. gSavedSettings.setU32("LuaConsoleInputHeight", height);
  12391. }
  12392. //virtual
  12393. bool HBLuaConsole::postBuild()
  12394. {
  12395. mInputLayout = (LLLayoutStack*)getChild<LLView>("layout_input");
  12396. mOutputText = getChild<LLTextEditor>("output_text");
  12397. mInputCode = getChild<LLTextEditor>("input_text");
  12398. mInputCode->setHandleEditKeysDirectly(true);
  12399. mInputCode->makePristine();
  12400. mClearOutput = getChild<LLButton>("clear_output_btn");
  12401. mClearOutput->setCommitCallback(onClearButton);
  12402. mClearOutput->setCallbackUserData(this);
  12403. mClearInput = getChild<LLButton>("clear_input_btn");
  12404. mClearInput->setCommitCallback(onClearButton);
  12405. mClearInput->setCallbackUserData(this);
  12406. mLoadCode = getChild<LLButton>("load_btn");
  12407. mLoadCode->setCommitCallback(onLoadButton);
  12408. mLoadCode->setCallbackUserData(this);
  12409. mBackward = getChild<LLButton>("previous_btn");
  12410. mBackward->setCommitCallback(onBrowseButton);
  12411. mBackward->setCallbackUserData(this);
  12412. mForward = getChild<LLButton>("next_btn");
  12413. mForward->setCommitCallback(onBrowseButton);
  12414. mForward->setCallbackUserData(this);
  12415. mExecute = getChild<LLButton>("execute_btn");
  12416. mExecute->setCommitCallback(onExecuteButton);
  12417. mExecute->setCallbackUserData(this);
  12418. LLButton* buttonp = getChild<LLButton>("help_btn");
  12419. buttonp->setCommitCallback(onHelpButton);
  12420. buttonp->setCallbackUserData(this);
  12421. buttonp = getChild<LLButton>("list_btn");
  12422. buttonp->setCommitCallback(onListButton);
  12423. buttonp->setCallbackUserData(this);
  12424. return true;
  12425. }
  12426. //virtual
  12427. void HBLuaConsole::draw()
  12428. {
  12429. // *HACK: for some reason, we need to issue two endOfDoc()'s at one frame
  12430. // interval to actually get this damned thing to scroll down to the end.
  12431. // *FIXME: find out why and fix the underlying UI bug.
  12432. static bool scroll_again = false;
  12433. if (scroll_again)
  12434. {
  12435. scroll_again = false;
  12436. mOutputText->endOfDoc();
  12437. }
  12438. if (!mTextBuffer.empty())
  12439. {
  12440. bool prepend_newline = mOutputText->getLength() > 0;
  12441. mOutputText->appendText(mTextBuffer, false, prepend_newline);
  12442. mOutputText->setCursorAndScrollToEnd(); // Issues a 1st endOfDoc()
  12443. mTextBuffer.clear();
  12444. scroll_again = true;
  12445. }
  12446. mClearOutput->setEnabled(mOutputText->getLength() > 0);
  12447. bool has_code = mInputCode->getLength() > 0;
  12448. mClearInput->setEnabled(has_code);
  12449. mExecute->setEnabled(has_code);
  12450. mLoadCode->setEnabled(!HBFileSelector::isInUse());
  12451. size_t history_size = sHistoryStorage.size();
  12452. mBackward->setEnabled(history_size && mHistoryIndex > 0);
  12453. mForward->setEnabled(mHistoryIndex + 1 < history_size);
  12454. LLFloater::draw();
  12455. // *HACK: due to how layout stacks are resized progressively at each frame,
  12456. // we need to keep asking for a resize for as long as the height of our
  12457. // layout panel has not reached the saved height (or close enough to it);
  12458. // sadly, even with this method, the requested size is not always reached
  12459. // (likely because of rounding bugs in the layout stack code), so we also
  12460. // limit the number of attempts to avoid retrying forever and counter-
  12461. //acting possible manual resizing by the user...
  12462. if (mResizingAttempts)
  12463. {
  12464. static LLCachedControl<U32> height(gSavedSettings,
  12465. "LuaConsoleInputHeight");
  12466. LLRect orig_rect = mInputLayout->getRect();
  12467. LLRect scaled_rect = orig_rect;
  12468. scaled_rect.mTop = scaled_rect.mBottom + height + SIZE_FUDGE;
  12469. mInputLayout->setRect(scaled_rect);
  12470. mInputLayout->setRect(orig_rect);
  12471. mInputLayout->reshape(scaled_rect.getWidth(), scaled_rect.getHeight(),
  12472. false);
  12473. LLFloater::draw(); // Propagate the changes.
  12474. // Remember this delta to adjust the saved size on floater closing.
  12475. mSizeDelta = (S32)height - mInputLayout->getRect().getHeight();
  12476. // Remember the rect we reached for use in the destructor, to verify
  12477. // that the above delta is still valid.
  12478. mInputLayoutRect = mInputLayout->getRect();
  12479. if (abs(mSizeDelta) <= SIZE_FUDGE)
  12480. {
  12481. mResizingAttempts = 0;
  12482. }
  12483. else
  12484. {
  12485. --mResizingAttempts;
  12486. }
  12487. }
  12488. }
  12489. //virtual
  12490. void HBLuaConsole::onFocusReceived()
  12491. {
  12492. // Focus our input text editor
  12493. mInputCode->setFocus(true);
  12494. // Short-circuit LLUICtrl::onFocusReceived()
  12495. LLFocusableElement::onFocusReceived();
  12496. }
  12497. //virtual
  12498. bool HBLuaConsole::handleKeyHere(KEY key, MASK mask)
  12499. {
  12500. if (mask == MASK_CONTROL)
  12501. {
  12502. switch (key)
  12503. {
  12504. case KEY_RETURN:
  12505. onExecuteButton(mExecute, (void*)this);
  12506. return true;
  12507. case KEY_UP:
  12508. onBrowseButton(mBackward, (void*)this);
  12509. return true;
  12510. case KEY_DOWN:
  12511. onBrowseButton(mForward, (void*)this);
  12512. return true;
  12513. default:
  12514. break;
  12515. }
  12516. }
  12517. return LLFloater::handleKeyHere(key, mask);
  12518. }
  12519. void HBLuaConsole::loadFile(const std::string& filename)
  12520. {
  12521. if (!filename.empty())
  12522. {
  12523. llifstream file(filename.c_str());
  12524. if (file.is_open())
  12525. {
  12526. mInputCode->clear();
  12527. std::string line, text;
  12528. while (!file.eof())
  12529. {
  12530. getline(file, line);
  12531. text += line + "\n";
  12532. }
  12533. file.close();
  12534. LLWString wtext = utf8str_to_wstring(text);
  12535. LLWStringUtil::replaceTabsWithSpaces(wtext, 4);
  12536. text = wstring_to_utf8str(wtext);
  12537. mInputCode->appendText(text, false, false);
  12538. mInputCode->makePristine();
  12539. mHistoryIndex = sHistoryStorage.size();
  12540. }
  12541. }
  12542. }
  12543. //static
  12544. bool HBLuaConsole::print(const std::string& text)
  12545. {
  12546. HBLuaConsole* self = findInstance();
  12547. if (self)
  12548. {
  12549. if (!self->mTextBuffer.empty())
  12550. {
  12551. self->mTextBuffer += "\n";
  12552. }
  12553. self->mTextBuffer += text;
  12554. return true;
  12555. }
  12556. return false;
  12557. }
  12558. //static
  12559. void HBLuaConsole::onClearButton(LLUICtrl* ctrlp, void* userdata)
  12560. {
  12561. HBLuaConsole* self = (HBLuaConsole*)userdata;
  12562. if (!self || !ctrlp) return;
  12563. if (ctrlp == (LLUICtrl*)self->mClearOutput)
  12564. {
  12565. self->mOutputText->clear();
  12566. }
  12567. else if (ctrlp == (LLUICtrl*)self->mClearInput)
  12568. {
  12569. self->mInputCode->clear();
  12570. self->mHistoryIndex = sHistoryStorage.size();
  12571. }
  12572. }
  12573. //static
  12574. void HBLuaConsole::onBrowseButton(LLUICtrl* ctrlp, void* userdata)
  12575. {
  12576. HBLuaConsole* self = (HBLuaConsole*)userdata;
  12577. if (!self || !ctrlp || sHistoryStorage.empty()) return;
  12578. if (ctrlp == (LLUICtrl*)self->mBackward)
  12579. {
  12580. if (self->mHistoryIndex > 0)
  12581. {
  12582. self->mInputCode->clear();
  12583. self->mInputCode->setText(sHistoryStorage[--self->mHistoryIndex]);
  12584. self->mInputCode->setCursorAndScrollToEnd();
  12585. }
  12586. }
  12587. else if (ctrlp == (LLUICtrl*)self->mForward)
  12588. {
  12589. if (self->mHistoryIndex + 1 < sHistoryStorage.size())
  12590. {
  12591. self->mInputCode->clear();
  12592. self->mInputCode->setText(sHistoryStorage[++self->mHistoryIndex]);
  12593. self->mInputCode->setCursorAndScrollToEnd();
  12594. }
  12595. }
  12596. }
  12597. //static
  12598. void HBLuaConsole::onExecuteButton(LLUICtrl*, void* userdata)
  12599. {
  12600. HBLuaConsole* self = (HBLuaConsole*)userdata;
  12601. if (!self || !self->mInputCode->getLength())
  12602. {
  12603. return;
  12604. }
  12605. HBViewerAutomation lua;
  12606. lua.mUseConsoleOutput = true;
  12607. std::string code = self->mInputCode->getText();
  12608. if (lua.loadString(code))
  12609. {
  12610. // Store the successful command in history, if different from last one.
  12611. if (sHistoryStorage.empty() || sHistoryStorage.back() != code)
  12612. {
  12613. sHistoryStorage.emplace_back(code);
  12614. }
  12615. self->mHistoryIndex = sHistoryStorage.size();
  12616. // Clear input text editor.
  12617. self->mInputCode->clear();
  12618. self->mInputCode->makePristine();
  12619. }
  12620. }
  12621. static void load_file_cb(HBFileSelector::ELoadFilter, std::string& filename,
  12622. void*)
  12623. {
  12624. if (!filename.empty())
  12625. {
  12626. HBLuaConsole* floaterp = HBLuaConsole::showInstance();
  12627. if (floaterp) // This should always be true
  12628. {
  12629. floaterp->loadFile(filename);
  12630. }
  12631. }
  12632. }
  12633. //static
  12634. void HBLuaConsole::onLoadButton(LLUICtrl*, void*)
  12635. {
  12636. HBFileSelector::loadFile(HBFileSelector::FFLOAD_LUA, load_file_cb, NULL);
  12637. }
  12638. //static
  12639. void HBLuaConsole::onHelpButton(LLUICtrl*, void* userdata)
  12640. {
  12641. HBLuaConsole* self = (HBLuaConsole*)userdata;
  12642. if (self)
  12643. {
  12644. LLWeb::loadURL(self->getString("lua_manual_url"));
  12645. }
  12646. }
  12647. //static
  12648. void HBLuaConsole::onListButton(LLUICtrl*, void* userdata)
  12649. {
  12650. HBLuaConsole* self = (HBLuaConsole*)userdata;
  12651. if (self)
  12652. {
  12653. // Focus back the input text editor
  12654. self->mInputCode->setFocus(true);
  12655. // Execute our Lua snippet to list our custom viewer functions.
  12656. HBViewerAutomation lua;
  12657. lua.mUseConsoleOutput = true;
  12658. lua.loadString(self->getString("print_lua_funcs"));
  12659. }
  12660. }