mkrlinterface.cpp 208 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764
  1. /**
  2. * @file mkrlinterface.cpp
  3. * @author Marine Kelley (many parts rewritten/expanded by Henri Beauchamp)
  4. * @brief Implementation of the RLV features
  5. *
  6. * RLV Source Code
  7. * The source code in this file("Source Code") is provided by Marine Kelley
  8. * to you under the terms of the GNU General Public License, version 2.0
  9. * ("GPL"), unless you have obtained a separate licensing agreement
  10. * ("Other License"), formally executed by you and Marine Kelley. Terms of
  11. * the GPL can be found in doc/GPL-license.txt in the distribution of the
  12. * original source of the Second Life Viewer, or online at
  13. * http://secondlifegrid.net/programs/open_source/licensing/gplv2
  14. *
  15. * By copying, modifying or distributing this software, you acknowledge
  16. * that you have read and understood your obligations described above,
  17. * and agree to abide by those obligations.
  18. *
  19. * ALL SOURCE CODE FROM MARINE KELLEY IS PROVIDED "AS IS." MARINE KELLEY
  20. * MAKES NO WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING
  21. * ITS ACCURACY, COMPLETENESS OR PERFORMANCE.
  22. */
  23. #include "llviewerprecompiledheaders.h"
  24. #include "mkrlinterface.h"
  25. #include "llapp.h"
  26. #include "llcachename.h"
  27. #include "llregionhandle.h"
  28. #include "llrenderutils.h" // For gSphere
  29. #include "llagent.h"
  30. #include "llagentwearables.h"
  31. #include "llappearancemgr.h"
  32. #include "llappviewer.h" // For gFrameTimeSeconds
  33. #include "lldrawpoolalpha.h"
  34. #include "llenvironment.h"
  35. #include "llenvsettings.h"
  36. #include "llfloaterchat.h"
  37. #include "hbfloaterrlv.h"
  38. #include "llfloaterwindlight.h"
  39. #include "llgesturemgr.h"
  40. #include "llhudtext.h"
  41. #include "llinventorybridge.h"
  42. #include "llpipeline.h"
  43. #include "llselectmgr.h"
  44. #include "llsky.h"
  45. #include "llstartup.h"
  46. #include "lltracker.h"
  47. #include "lltooldraganddrop.h"
  48. #include "hbviewerautomation.h"
  49. #include "llviewercamera.h"
  50. #include "llviewercontrol.h"
  51. #include "llviewerinventory.h"
  52. #include "llviewerfoldertype.h"
  53. #include "llviewerjointattachment.h"
  54. #include "llviewermenu.h"
  55. #include "llviewermessage.h" // For send_agent_update()
  56. #include "llviewerobjectlist.h"
  57. #include "llviewerparcelmgr.h"
  58. #include "llviewerregion.h"
  59. #include "llviewertexture.h"
  60. #include "llviewerwearable.h"
  61. #include "llvoavatarself.h"
  62. #include "llworld.h"
  63. #include "llworldmap.h"
  64. #include "roles_constants.h"
  65. RLInterface gRLInterface;
  66. // Global and static variables initialization.
  67. bool gRLenabled = true;
  68. bool RLInterface::sRLNoSetEnv = false;
  69. bool RLInterface::sUntruncatedEmotes = false;
  70. bool RLInterface::sCanOoc = true;
  71. std::string RLInterface::sRecvimMessage;
  72. std::string RLInterface::sSendimMessage;
  73. std::string RLInterface::sBlackList;
  74. std::string RLInterface::sRolePlayBlackList;
  75. std::string RLInterface::sVanillaBlackList;
  76. RLInterface::rl_command_map_t RLInterface::sCommandsMap;
  77. //----------------------------------------------------------------------------
  78. // Helper functions
  79. //----------------------------------------------------------------------------
  80. static std::string dumpList2String(std::deque<std::string> list,
  81. std::string sep, S32 size = -1)
  82. {
  83. if (size < 0)
  84. {
  85. size = (S32)list.size();
  86. }
  87. std::string res;
  88. for (S32 i = 0; i < (S32)list.size() && i < size; ++i)
  89. {
  90. if (i != 0)
  91. {
  92. res += sep;
  93. }
  94. res += list[i];
  95. }
  96. return res;
  97. }
  98. static S32 match(std::deque<std::string> list, std::string str,
  99. bool& exact_match)
  100. {
  101. // does str contain list[0]/list[1]/.../list[n] ?
  102. // yes => return the size of the list
  103. // no => try again after removing the last element
  104. // return 0 if never found
  105. // exact_match is an output, set to true when strict matching is found,
  106. // false otherwise.
  107. U32 size = list.size();
  108. std::string dump;
  109. exact_match = false;
  110. while (size > 0)
  111. {
  112. dump = dumpList2String(list, "/", (S32) size);
  113. if (str == dump)
  114. {
  115. exact_match = true;
  116. return (S32)size;
  117. }
  118. else if (str.find(dump) != std::string::npos)
  119. {
  120. return (S32)size;
  121. }
  122. --size;
  123. }
  124. return 0;
  125. }
  126. static std::deque<std::string> getSubList(std::deque<std::string> list,
  127. S32 min, S32 max = -1)
  128. {
  129. if (min < 0)
  130. {
  131. min = 0;
  132. }
  133. if (max < 0)
  134. {
  135. max = list.size() - 1;
  136. }
  137. std::deque<std::string> res;
  138. for (S32 i = min; i <= max; ++i)
  139. {
  140. res.emplace_back(list[i]);
  141. }
  142. return res;
  143. }
  144. static bool findMultiple(std::deque<std::string> list, std::string str)
  145. {
  146. // returns true if all the tokens in list are contained into str
  147. U32 size = list.size();
  148. for (U32 i = 0; i < size; ++i)
  149. {
  150. if (str.find(list[i]) == std::string::npos) return false;
  151. }
  152. return true;
  153. }
  154. static void updateAllHudTexts()
  155. {
  156. for (LLHUDText::htobj_list_it_t it = LLHUDText::sTextObjects.begin(),
  157. end = LLHUDText::sTextObjects.end();
  158. it != end; ++it)
  159. {
  160. LLHUDText* hud_text = *it;
  161. if (hud_text && !hud_text->mLastMessageText.empty() &&
  162. hud_text->getDoFade())
  163. {
  164. // do not update the floating names of the avatars around
  165. LLViewerObject* obj = hud_text->getSourceObject();
  166. if (obj && !obj->isAvatar())
  167. {
  168. hud_text->setStringUTF8(hud_text->mLastMessageText);
  169. }
  170. }
  171. }
  172. }
  173. static void updateOneHudText(LLUUID id)
  174. {
  175. LLViewerObject* obj = gObjectList.findObject(id);
  176. if (obj && obj->mText.notNull())
  177. {
  178. LLHUDText* hud_text = obj->mText.get();
  179. if (hud_text && !hud_text->mLastMessageText.empty() &&
  180. hud_text->getDoFade())
  181. {
  182. hud_text->setStringUTF8(hud_text->mLastMessageText);
  183. }
  184. }
  185. }
  186. //----------------------------------------------------------------------------
  187. // RLInterface() class proper
  188. //----------------------------------------------------------------------------
  189. RLInterface::RLInterface()
  190. : mInventoryFetched(false),
  191. mAllowCancelTp(true),
  192. mReattaching(false),
  193. mReattachTimeout(false),
  194. mRestoringOutfit(false),
  195. mSnappingBackToLastStandingLocation(false),
  196. mSitGroundOnStandUp(false),
  197. mHasLockedHuds(false),
  198. mContainsDetach(false),
  199. mContainsShowinv(false),
  200. mContainsUnsit(false),
  201. mContainsStandtp(false),
  202. mContainsInteract(false),
  203. mContainsShowworldmap(false),
  204. mContainsShowminimap(false),
  205. mContainsShowloc(false),
  206. mContainsShownames(false),
  207. mContainsShownametags(false),
  208. mContainsShowNearby(false),
  209. mContainsSetenv(false),
  210. mContainsSetdebug(false),
  211. mContainsFly(false),
  212. mContainsEdit(false),
  213. mContainsRez(false),
  214. mContainsShowhovertextall(false),
  215. mContainsShowhovertexthud(false),
  216. mContainsShowhovertextworld(false),
  217. mContainsDefaultwear(false),
  218. mContainsPermissive(false),
  219. mContainsRun(false),
  220. mContainsAlwaysRun(false),
  221. mContainsViewscript(false),
  222. mContainsCamTextures(false),
  223. mNeedsVisibilityRefresh(false),
  224. mContainsTp(false),
  225. mGotSit(false),
  226. mGotUnsit(false),
  227. mSkipAll(false),
  228. mHandleBackToLastStanding(false),
  229. mHandleNoStrip(false),
  230. mHandleNoRelay(false),
  231. mLastCmdBlacklisted(false),
  232. mLaunchTimestamp((U32)LLTimer::getEpochSeconds()),
  233. // Give the garbage collector a moment before even kicking in the first
  234. // time, in case we are logging in a very laggy place, taking time to rez
  235. mNextGarbageCollection(30.f),
  236. mVisionRestricted(false),
  237. mRenderLimitRenderedThisFrame(false),
  238. mCamDistNbGradients(10),
  239. mCamDistDrawFromJoint(NULL),
  240. mCamZoomMax(EXTREMUM),
  241. mCamZoomMin(-EXTREMUM),
  242. mCamDistMax(EXTREMUM),
  243. mCamDistMin(-EXTREMUM),
  244. mCamDistDrawMax(EXTREMUM),
  245. mCamDistDrawMin(EXTREMUM),
  246. mShowavsDistMax(EXTREMUM),
  247. mFartouchMax(EXTREMUM),
  248. mSittpMax(EXTREMUM),
  249. mTplocalMax(EXTREMUM)
  250. {
  251. mAllowedGetDebug.emplace_back("AvatarSex");
  252. mAllowedGetDebug.emplace_back("RenderResolutionDivisor");
  253. mAllowedGetDebug.emplace_back("RestrainedLoveForbidGiveToRLV");
  254. mAllowedGetDebug.emplace_back("RestrainedLoveNoSetEnv");
  255. // 0 female, 1 male (unreliable: depends on shape)
  256. mAllowedSetDebug.emplace_back("AvatarSex");
  257. // To allow simulating blur; default is 1 for no blur
  258. mAllowedSetDebug.emplace_back("RenderResolutionDivisor");
  259. mJustDetached.mId.setNull();
  260. mJustDetached.mName.clear();
  261. #if 0
  262. mJustReattached.mId.setNull();
  263. mJustReattached.mName.clear();
  264. #endif
  265. }
  266. RLInterface::~RLInterface()
  267. {
  268. mCamTexturesCustom = NULL;
  269. }
  270. // init() must be called at an early stage, to setup all RestrainedLove session
  271. // variables. It is called from LLAppViewer::init() in llappviewer.cpp. This
  272. // cannot be done in the constructor for RLInterface, because calling
  273. // gSavedSettings.get*() at that stage would cause crashes under Windows
  274. // (working fine under Linux): probably a race condition in constructors.
  275. //static
  276. void RLInterface::init()
  277. {
  278. // Info commands (not "blacklistable").
  279. sCommandsMap.emplace("version", RL_INFO);
  280. sCommandsMap.emplace("versionnew", RL_INFO);
  281. sCommandsMap.emplace("versionnum", RL_INFO);
  282. sCommandsMap.emplace("versionnumbl", RL_INFO);
  283. sCommandsMap.emplace("getcommand", RL_INFO);
  284. sCommandsMap.emplace("getstatus", RL_INFO);
  285. sCommandsMap.emplace("getstatusall", RL_INFO);
  286. sCommandsMap.emplace("getsitid", RL_INFO);
  287. sCommandsMap.emplace("getoutfit", RL_INFO);
  288. sCommandsMap.emplace("getattach", RL_INFO);
  289. sCommandsMap.emplace("getinv", RL_INFO);
  290. sCommandsMap.emplace("getinvworn", RL_INFO);
  291. sCommandsMap.emplace("getpath", RL_INFO);
  292. sCommandsMap.emplace("getpathnew", RL_INFO);
  293. sCommandsMap.emplace("findfolder", RL_INFO);
  294. sCommandsMap.emplace("findfolders", RL_INFO);
  295. sCommandsMap.emplace("getgroup", RL_INFO);
  296. sCommandsMap.emplace("getdebug_", RL_INFO);
  297. sCommandsMap.emplace("getenv_", RL_INFO);
  298. sCommandsMap.emplace("getcam_", RL_INFO);
  299. // Miscellaneous non-info commands that are not "blacklistable".
  300. sCommandsMap.emplace("notify", RL_MISCELLANEOUS);
  301. sCommandsMap.emplace("clear", RL_MISCELLANEOUS);
  302. sCommandsMap.emplace("detachme%f", RL_MISCELLANEOUS);
  303. sCommandsMap.emplace("setrot%f", RL_MISCELLANEOUS);
  304. sCommandsMap.emplace("adjustheight%f", RL_MISCELLANEOUS);
  305. sCommandsMap.emplace("emote", RL_MISCELLANEOUS);
  306. sCommandsMap.emplace("relayed", RL_MISCELLANEOUS);
  307. // Normal commands, "blacklistable".
  308. // Movement restrictions
  309. sCommandsMap.emplace("fly", RL_MOVE);
  310. sCommandsMap.emplace("temprun", RL_MOVE);
  311. sCommandsMap.emplace("alwaysrun", RL_MOVE);
  312. sVanillaBlackList += "fly,temprun,alwaysrun,";
  313. // Chat sending restrictions
  314. sCommandsMap.emplace("sendchat", RL_SENDCHAT);
  315. sCommandsMap.emplace("chatshout", RL_SENDCHAT);
  316. sCommandsMap.emplace("chatnormal", RL_SENDCHAT);
  317. sCommandsMap.emplace("chatwhisper", RL_SENDCHAT);
  318. sCommandsMap.emplace("sendgesture", RL_SENDCHAT);
  319. sVanillaBlackList += "sendchat,chatshout,chatnormal,chatwhisper,sendgesture,";
  320. // Chat receiving restrictions
  321. sCommandsMap.emplace("recvchat", RL_RECEIVECHAT);
  322. sCommandsMap.emplace("recvchat_sec", RL_RECEIVECHAT);
  323. sCommandsMap.emplace("recvchatfrom", RL_RECEIVECHAT);
  324. sVanillaBlackList += "recvchat,recvchat_sec,recvchatfrom,";
  325. // Chat on private channels restrictions
  326. sCommandsMap.emplace("sendchannel", RL_CHANNEL);
  327. sCommandsMap.emplace("sendchannel_sec", RL_CHANNEL);
  328. sCommandsMap.emplace("sendchannel_except", RL_CHANNEL);
  329. sRolePlayBlackList += "sendchannel,sendchannel_sec,sendchannel_except,";
  330. sVanillaBlackList += "sendchannel,sendchannel_sec,sendchannel_except,";
  331. // Chat and emotes redirections
  332. sCommandsMap.emplace("redirchat", RL_REDIRECTION);
  333. sCommandsMap.emplace("rediremote", RL_REDIRECTION);
  334. // Emotes restrictions
  335. sCommandsMap.emplace("recvemote", RL_EMOTE);
  336. sCommandsMap.emplace("recvemote_sec", RL_EMOTE);
  337. sCommandsMap.emplace("recvemotefrom", RL_EMOTE);
  338. sRolePlayBlackList += "recvemote,recvemote_sec,recvemotefrom,";
  339. sVanillaBlackList += "recvemote,recvemote_sec,recvemotefrom,";
  340. // Instant messaging restrictions
  341. sCommandsMap.emplace("sendim", RL_INSTANTMESSAGE);
  342. sCommandsMap.emplace("sendim_sec", RL_INSTANTMESSAGE);
  343. sCommandsMap.emplace("sendimto", RL_INSTANTMESSAGE);
  344. sCommandsMap.emplace("startim", RL_INSTANTMESSAGE);
  345. sCommandsMap.emplace("startimto", RL_INSTANTMESSAGE);
  346. sCommandsMap.emplace("recvim", RL_INSTANTMESSAGE);
  347. sCommandsMap.emplace("recvim_sec", RL_INSTANTMESSAGE);
  348. sCommandsMap.emplace("recvimfrom", RL_INSTANTMESSAGE);
  349. sRolePlayBlackList += "sendim,sendim_sec,sendimto,startim,startimto,recvim,recvim_sec,recvimfrom,";
  350. sVanillaBlackList += "sendim,sendim_sec,sendimto,startim,startimto,recvim,recvim_sec,recvimfrom,";
  351. // Teleport restrictions
  352. sCommandsMap.emplace("tplm", RL_TELEPORT);
  353. sCommandsMap.emplace("tploc", RL_TELEPORT);
  354. sCommandsMap.emplace("tplocal", RL_TELEPORT);
  355. sCommandsMap.emplace("tplure", RL_TELEPORT);
  356. sCommandsMap.emplace("tplure_sec", RL_TELEPORT);
  357. sCommandsMap.emplace("sittp", RL_TELEPORT);
  358. sCommandsMap.emplace("standtp", RL_TELEPORT);
  359. sCommandsMap.emplace("tpto%f", RL_TELEPORT);
  360. sCommandsMap.emplace("accepttp", RL_TELEPORT);
  361. sCommandsMap.emplace("accepttprequest", RL_TELEPORT);
  362. sCommandsMap.emplace("tprequest", RL_TELEPORT);
  363. // Note: tpto is used by teleporters: allow
  364. sVanillaBlackList += "tplm,tploc,tplocal,tplure,tplure_sec,sittp,standtp,accepttp,accepttprequest,tprequest,";
  365. // Inventory access restrictions
  366. sCommandsMap.emplace("showinv", RL_INVENTORY);
  367. sCommandsMap.emplace("viewnote", RL_INVENTORY);
  368. sCommandsMap.emplace("viewscript", RL_INVENTORY);
  369. sCommandsMap.emplace("viewtexture", RL_INVENTORY);
  370. sCommandsMap.emplace("sharedwear", RL_INVENTORYLOCK);
  371. sCommandsMap.emplace("unsharedwear", RL_INVENTORYLOCK);
  372. sCommandsMap.emplace("unsharedunwear", RL_INVENTORYLOCK);
  373. sRolePlayBlackList += "showinv,viewnote,viewscript,viewtexture,sharedwear,unsharedwear,unsharedunwear,";
  374. sVanillaBlackList += "showinv,viewnote,viewscript,viewtexture,sharedwear,unsharedwear,unsharedunwear,";
  375. // Building restrictions
  376. sCommandsMap.emplace("edit", RL_BUILD);
  377. sCommandsMap.emplace("editattach", RL_BUILD);
  378. sCommandsMap.emplace("editobj", RL_BUILD);
  379. sCommandsMap.emplace("editworld", RL_BUILD);
  380. sCommandsMap.emplace("rez", RL_BUILD);
  381. sRolePlayBlackList += "edit,editattach,editobj,editworld,rez,";
  382. sVanillaBlackList += "edit,editattach,editobj,editworld,rez,";
  383. // Sitting restrictions
  384. sCommandsMap.emplace("unsit", RL_SIT);
  385. sCommandsMap.emplace("unsit%f", RL_SIT);
  386. sCommandsMap.emplace("sit", RL_SIT);
  387. sCommandsMap.emplace("sit%f", RL_SIT);
  388. sCommandsMap.emplace("sitground%f", RL_SIT);
  389. sVanillaBlackList += "unsit,unsit%f,sit,sit%f,sitground%f";
  390. // Locking commands
  391. sCommandsMap.emplace("detach", RL_LOCK);
  392. sCommandsMap.emplace("detachthis", RL_LOCK);
  393. sCommandsMap.emplace("detachallthis", RL_LOCK);
  394. sCommandsMap.emplace("detachthis_except", RL_LOCK);
  395. sCommandsMap.emplace("detachallthis_except", RL_LOCK);
  396. sCommandsMap.emplace("attachthis", RL_LOCK);
  397. sCommandsMap.emplace("attachallthis", RL_LOCK);
  398. sCommandsMap.emplace("attachthis_except", RL_LOCK);
  399. sCommandsMap.emplace("attachallthis_except", RL_LOCK);
  400. sCommandsMap.emplace("addattach", RL_LOCK);
  401. sCommandsMap.emplace("remattach", RL_LOCK);
  402. sCommandsMap.emplace("addoutfit", RL_LOCK);
  403. sCommandsMap.emplace("remoutfit", RL_LOCK);
  404. sCommandsMap.emplace("defaultwear", RL_LOCK);
  405. sVanillaBlackList += "detach,detachthis,detachallthis,detachthis_except,detachallthis_except,attachthis,attachallthis,attachthis_except,attachallthis_except,addattach,remattach,addoutfit,remoutfit,defaultwear,";
  406. // Detach/remove commands
  407. sCommandsMap.emplace("detach%f", RL_DETACH);
  408. sCommandsMap.emplace("detachall%f", RL_DETACH);
  409. sCommandsMap.emplace("detachthis%f", RL_DETACH);
  410. sCommandsMap.emplace("detachallthis%f", RL_DETACH);
  411. sCommandsMap.emplace("remattach%f", RL_DETACH);
  412. sCommandsMap.emplace("remoutfit%f", RL_DETACH);
  413. // Attach/wear commands
  414. sCommandsMap.emplace("attach%f", RL_ATTACH);
  415. sCommandsMap.emplace("attachover%f", RL_ATTACH);
  416. sCommandsMap.emplace("attachoverorreplace%f", RL_ATTACH);
  417. sCommandsMap.emplace("attachall%f", RL_ATTACH);
  418. sCommandsMap.emplace("attachallover%f", RL_ATTACH);
  419. sCommandsMap.emplace("attachalloverorreplace%f", RL_ATTACH);
  420. sCommandsMap.emplace("attachthis%f", RL_ATTACH);
  421. sCommandsMap.emplace("attachthisover%f", RL_ATTACH);
  422. sCommandsMap.emplace("attachthisover%f", RL_ATTACH);
  423. sCommandsMap.emplace("attachthisoverorreplace%f", RL_ATTACH);
  424. sCommandsMap.emplace("attachallthis%f", RL_ATTACH);
  425. sCommandsMap.emplace("attachallthisover%f", RL_ATTACH);
  426. sCommandsMap.emplace("attachallthisoverorreplace%f", RL_ATTACH);
  427. // Touch restrictions
  428. sCommandsMap.emplace("fartouch", RL_TOUCH);
  429. sCommandsMap.emplace("interact", RL_TOUCH);
  430. sCommandsMap.emplace("touchfar", RL_TOUCH);
  431. sCommandsMap.emplace("touchall", RL_TOUCH);
  432. sCommandsMap.emplace("touchworld", RL_TOUCH);
  433. sCommandsMap.emplace("touchthis", RL_TOUCH);
  434. sCommandsMap.emplace("touchme", RL_TOUCH);
  435. sCommandsMap.emplace("touchattach", RL_TOUCH);
  436. sCommandsMap.emplace("touchattachself", RL_TOUCH);
  437. sCommandsMap.emplace("touchhud", RL_TOUCH);
  438. sCommandsMap.emplace("touchattachother", RL_TOUCH);
  439. sVanillaBlackList += "fartouch,interact,touchfar,touchall,touchworld,touchthis,touchme,touchattach,touchattachself,touchhud,touchattachother,";
  440. // Location/mapping restrictions
  441. sCommandsMap.emplace("showworldmap", RL_LOCATION);
  442. sCommandsMap.emplace("showminimap", RL_LOCATION);
  443. sCommandsMap.emplace("showloc", RL_LOCATION);
  444. sRolePlayBlackList += "showworldmap,showminimap,showloc,";
  445. sVanillaBlackList += "showworldmap,showminimap,showloc,";
  446. // Name viewing restrictions
  447. sCommandsMap.emplace("shownames", RL_NAME);
  448. sCommandsMap.emplace("shownames_sec", RL_NAME);
  449. sCommandsMap.emplace("shownametags", RL_NAME);
  450. sCommandsMap.emplace("shownearby", RL_NAME);
  451. sCommandsMap.emplace("showhovertextall", RL_NAME);
  452. sCommandsMap.emplace("showhovertext", RL_NAME);
  453. sCommandsMap.emplace("showhovertexthud", RL_NAME);
  454. sCommandsMap.emplace("showhovertextworld", RL_NAME);
  455. sRolePlayBlackList += "shownames,shownametags,showhovertextall,showhovertext,showhovertexthud,showhovertextworld,";
  456. sVanillaBlackList += "shownames,shownametags,showhovertextall,showhovertext,showhovertexthud,showhovertextworld,";
  457. // Group restrictions
  458. sCommandsMap.emplace("setgroup", RL_GROUP);
  459. sCommandsMap.emplace("setgroup%f", RL_GROUP);
  460. sRolePlayBlackList += "setgroup,";
  461. sVanillaBlackList += "setgroup,"; // @setgroup=force May be used as a helper: allow
  462. // Sharing restrictions
  463. sCommandsMap.emplace("share", RL_SHARE);
  464. sCommandsMap.emplace("share_sec", RL_SHARE);
  465. sRolePlayBlackList += "share,share_sec,";
  466. sVanillaBlackList += "share,share_sec,";
  467. // Permissions/extra-restriction commands.
  468. sCommandsMap.emplace("permissive", RL_PERM);
  469. sCommandsMap.emplace("acceptpermission", RL_PERM);
  470. sVanillaBlackList += "permissive,acceptpermission,";
  471. // Camera restriction commands.
  472. sCommandsMap.emplace("camtextures", RL_CAMERA);
  473. sCommandsMap.emplace("camunlock", RL_CAMERA);
  474. sCommandsMap.emplace("camzoommax", RL_CAMERA);
  475. sCommandsMap.emplace("camzoommin", RL_CAMERA);
  476. sCommandsMap.emplace("camdistmax", RL_CAMERA);
  477. sCommandsMap.emplace("camdistmin", RL_CAMERA);
  478. sCommandsMap.emplace("camdrawmax", RL_CAMERA);
  479. sCommandsMap.emplace("camdrawmin", RL_CAMERA);
  480. sCommandsMap.emplace("camdrawalphamax", RL_CAMERA);
  481. sCommandsMap.emplace("camdrawalphamin", RL_CAMERA);
  482. sCommandsMap.emplace("camdrawcolor", RL_CAMERA);
  483. sCommandsMap.emplace("camavdist", RL_CAMERA);
  484. sCommandsMap.emplace("setcam_", RL_CAMERA);
  485. sCommandsMap.emplace("setcam_fov%f", RL_CAMERA);
  486. sRolePlayBlackList += "camtextures,camunlock,camzoommax,camzoommin,camdistmax,camdistmin,camdrawmax,camdrawmin,camdrawalphamax,camdrawalphamin,camdrawcolor,camavdist,setcam_,setcam_fov%f,";
  487. sVanillaBlackList += "camtextures,camunlock,camzoommax,camzoommin,camdistmax,camdistmin,camdrawmax,camdrawmin,camdrawalphamax,camdrawalphamin,camdrawcolor,camavdist,setcam_,setcam_fov%f,";
  488. // Debug settings commands.
  489. sCommandsMap.emplace("setdebug", RL_DEBUG);
  490. sCommandsMap.emplace("setdebug_%f", RL_DEBUG);
  491. sRolePlayBlackList += "setdebug";
  492. sVanillaBlackList += "setdebug,setdebug_%f,";
  493. sVanillaBlackList += "setenv";
  494. gRLInterface.mCamTexturesCustom = LLViewerFetchedTexture::sDefaultImagep;
  495. gRLenabled = gSavedSettings.getBool("RestrainedLove");
  496. if (gRLenabled)
  497. {
  498. sRLNoSetEnv = gSavedSettings.getBool("RestrainedLoveNoSetEnv");
  499. sUntruncatedEmotes =
  500. gSavedSettings.getBool("RestrainedLoveUntruncatedEmotes");
  501. sCanOoc = gSavedSettings.getBool("RestrainedLoveCanOoc");
  502. sBlackList = gSavedSettings.getString("RestrainedLoveBlacklist");
  503. if (!sRLNoSetEnv)
  504. {
  505. sCommandsMap.emplace("setenv", RL_ENVIRONMENT);
  506. sCommandsMap.emplace("setenv_%f", RL_ENVIRONMENT);
  507. }
  508. gRLInterface.updateCameraLimits();
  509. gRLInterface.updateLimits();
  510. llinfos << "RestrainedLove enabled and initialized." << llendl;
  511. }
  512. }
  513. //static
  514. void RLInterface::usePerAccountSettings()
  515. {
  516. if (gRLenabled)
  517. {
  518. sRecvimMessage =
  519. gSavedPerAccountSettings.getString("RestrainedLoveRecvimMessage");
  520. sSendimMessage =
  521. gSavedPerAccountSettings.getString("RestrainedLoveSendimMessage");
  522. }
  523. }
  524. // Call this function when adding/removing a restriction only, i.e. in this
  525. // file. Test the cached variables in the code of the viewer itself.
  526. void RLInterface::refreshCachedVariable(const std::string& var)
  527. {
  528. if (!isAgentAvatarValid()) return;
  529. bool update_names_exceptions = false;
  530. bool contained = contains(var);
  531. if (var == "detach" || var.compare(0, 7, "detach:") == 0 ||
  532. var.compare(0, 9, "addattach") == 0 ||
  533. var.compare(0, 9, "remattach") == 0)
  534. {
  535. contained = contains("detach") || containsSubstr("detach:") ||
  536. containsSubstr("addattach") || containsSubstr("remattach");
  537. mContainsDetach = contained;
  538. mHasLockedHuds = hasLockedHuds();
  539. if (mHasLockedHuds)
  540. {
  541. // To force the viewer to render the HUDs again, just in case
  542. LLPipeline::sShowHUDAttachments = true;
  543. }
  544. if (gUseWireframe && (mHasLockedHuds || mCamDistDrawMax < EXTREMUM))
  545. {
  546. handle_toggle_wireframe(NULL);
  547. }
  548. }
  549. else if (var == "showinv")
  550. {
  551. mContainsShowinv = contained;
  552. }
  553. else if (var == "unsit")
  554. {
  555. mContainsUnsit = contained;
  556. }
  557. else if (var == "standtp")
  558. {
  559. mContainsStandtp = contained;
  560. }
  561. else if (var == "interact")
  562. {
  563. mContainsInteract = contained;
  564. }
  565. else if (var == "showworldmap")
  566. {
  567. mContainsShowworldmap = contained;
  568. }
  569. else if (var == "showminimap")
  570. {
  571. mContainsShowminimap = contained;
  572. }
  573. else if (var == "showloc")
  574. {
  575. mContainsShowloc = contained;
  576. }
  577. else if (var == "shownames" || var == "shownames_sec")
  578. {
  579. mContainsShownames = contained;
  580. update_names_exceptions = true;
  581. }
  582. else if (var == "shownametags")
  583. {
  584. mContainsShownametags = contained;
  585. update_names_exceptions = true;
  586. }
  587. else if (var == "shownearby")
  588. {
  589. mContainsShowNearby = contained;
  590. }
  591. else if (var == "setenv")
  592. {
  593. mContainsSetenv = contained;
  594. }
  595. else if (var == "setdebug")
  596. {
  597. mContainsSetdebug = contained;
  598. }
  599. else if (var == "fly")
  600. {
  601. mContainsFly = contained;
  602. }
  603. else if (var == "edit")
  604. {
  605. mContainsEdit =
  606. #if 0
  607. containsSubstr("editobj") ||
  608. #endif
  609. containsWithoutException("edit");
  610. }
  611. else if (var == "rez")
  612. {
  613. mContainsRez = contained;
  614. }
  615. else if (var == "showhovertextall")
  616. {
  617. mContainsShowhovertextall = contained;
  618. }
  619. else if (var == "showhovertexthud")
  620. {
  621. mContainsShowhovertexthud = contained;
  622. }
  623. else if (var == "showhovertextworld")
  624. {
  625. mContainsShowhovertextworld = contained;
  626. }
  627. else if (var == "defaultwear")
  628. {
  629. mContainsDefaultwear = contained;
  630. }
  631. else if (var == "permissive")
  632. {
  633. mContainsPermissive = contained;
  634. }
  635. else if (var == "temprun")
  636. {
  637. mContainsRun = contained;
  638. }
  639. else if (var == "alwaysrun")
  640. {
  641. mContainsAlwaysRun = contained;
  642. }
  643. else if (var == "viewscript")
  644. {
  645. mContainsViewscript = contained;
  646. }
  647. else if (var.compare(0, 11, "camtextures") == 0 ||
  648. var.compare(0, 15, "setcam_textures") == 0)
  649. {
  650. mContainsCamTextures = containsSubstr("camtextures") ||
  651. containsSubstr("setcam_textures");
  652. // Is there a uuid specified ?
  653. size_t i = var.find(":");
  654. if (i != std::string::npos)
  655. {
  656. std::string id_str = var.substr(i + 1);
  657. LLUUID tex_id;
  658. tex_id.set(id_str, false);
  659. if (tex_id.notNull())
  660. {
  661. mCamTexturesCustom =
  662. LLViewerTextureManager::getFetchedTexture(tex_id,
  663. FTT_DEFAULT,
  664. true,
  665. LLGLTexture::BOOST_NONE,
  666. LLViewerTexture::LOD_TEXTURE);
  667. }
  668. else
  669. {
  670. mCamTexturesCustom = LLViewerFetchedTexture::sDefaultImagep;
  671. }
  672. }
  673. // Silly hack, but we need to force all textures in world to be updated
  674. mNeedsVisibilityRefresh = true;
  675. }
  676. else if (var == "camzoommax" || var == "camzoommin")
  677. {
  678. gViewerCamera.setDefaultFOV(gSavedSettings.getF32("CameraAngle"));
  679. }
  680. mContainsTp = contains("tplm") || contains("tploc") ||
  681. contains("tplure") ||
  682. (mContainsUnsit && gAgentAvatarp->mIsSitting);
  683. refreshTPflag(true);
  684. if (update_names_exceptions)
  685. {
  686. // Rebuild the list of exceptions for shownames and shownametags
  687. std::string command, behav, option, param;
  688. LLUUID avid;
  689. mExceptions.clear();
  690. for (rl_map_it_t it = mSpecialObjectBehaviours.begin(),
  691. end = mSpecialObjectBehaviours.end();
  692. it != end; ++it)
  693. {
  694. command = it->second;
  695. LLStringUtil::toLower(command);
  696. if (command.compare(0, 10, "shownames:") == 0 ||
  697. command.compare(0, 13, "shownames_sec:") == 0 ||
  698. command.compare(0, 13, "shownametags:") == 0)
  699. {
  700. if (parseCommand(command, behav, option, param))
  701. {
  702. avid.set(option, false);
  703. if (avid.notNull())
  704. {
  705. mExceptions.emplace(avid);
  706. }
  707. }
  708. }
  709. }
  710. }
  711. }
  712. void RLInterface::refreshTPflag(bool save)
  713. {
  714. static bool last_value =
  715. gSavedPerAccountSettings.getBool("RestrainedLoveTPOK");
  716. bool new_value = !mContainsTp;
  717. if (new_value != last_value)
  718. {
  719. last_value = new_value;
  720. gSavedPerAccountSettings.setBool("RestrainedLoveTPOK", new_value);
  721. if (save)
  722. {
  723. gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"));
  724. }
  725. }
  726. }
  727. void RLInterface::idleTasks()
  728. {
  729. static F32 last_refresh = 0.f;
  730. if (mNeedsVisibilityRefresh && gFrameTimeSeconds - last_refresh > 1.f)
  731. {
  732. handle_objects_visibility(NULL);
  733. last_refresh = gFrameTimeSeconds;
  734. mNeedsVisibilityRefresh = false;
  735. }
  736. // If RLV share inventory has not been fetched yet, fetch it now
  737. fetchInventory();
  738. // Perform some maintenance only if no object is waiting to be reattached
  739. if (mAssetsToReattach.empty())
  740. {
  741. // Fire all the stored commands that we received while initializing
  742. fireCommands();
  743. // Fire the garbage collector for orphaned restrictions
  744. if (gFrameTimeSeconds > mNextGarbageCollection)
  745. {
  746. garbageCollector(false);
  747. mNextGarbageCollection = gFrameTimeSeconds + 30.f;
  748. }
  749. }
  750. // We must check whether there is an object waiting to be reattached after
  751. // having been kicked off while locked.
  752. if (!mAssetsToReattach.empty())
  753. {
  754. // Get the elapsed time since detached, and the delay before reattach.
  755. U32 elapsed = (U32)mReattachTimer.getElapsedTimeF32();
  756. static LLCachedControl<U32> reattach_delay(gSavedSettings,
  757. "RestrainedLoveReattachDelay");
  758. // Timeout flag.
  759. bool timeout = mReattaching && elapsed > 4 * reattach_delay;
  760. if (timeout)
  761. {
  762. // If we timed out, reset the timer and tell the interface...
  763. mReattachTimer.reset();
  764. mReattachTimeout = true;
  765. llwarns << "Timeout reattaching an asset, retrying." << llendl;
  766. }
  767. if (!mReattaching || timeout)
  768. {
  769. // We are not reattaching an object (or we timed out), so let's see
  770. // if the delay before auto-reattach has elapsed.
  771. if (elapsed >= reattach_delay)
  772. {
  773. // Let's reattach the object to its default attach point.
  774. const RLAttachment& at = mAssetsToReattach.front();
  775. S32 tmp_attachpt_nb = 0;
  776. LLViewerJointAttachment* attachpt =
  777. findAttachmentPointFromName(at.mName, true);
  778. if (attachpt)
  779. {
  780. tmp_attachpt_nb = findAttachmentPointNumber(attachpt);
  781. }
  782. llinfos << "Reattaching asset " << at.mId << " to point '"
  783. << at.mName << "' (number " << tmp_attachpt_nb << ")"
  784. << llendl;
  785. mReattaching = true;
  786. attachObjectByUUID(at.mId, tmp_attachpt_nb);
  787. }
  788. }
  789. }
  790. }
  791. std::string RLInterface::getVersion()
  792. {
  793. return RL_VIEWER_NAME " viewer v" RL_VERSION;
  794. }
  795. std::string RLInterface::getVersion2()
  796. {
  797. return RL_VIEWER_NAME_NEW " viewer v" RL_VERSION;
  798. }
  799. std::string RLInterface::getVersionNum()
  800. {
  801. std::string res = RL_VERSION_NUM;
  802. if (!sBlackList.empty())
  803. {
  804. res += "," + sBlackList;
  805. }
  806. return res;
  807. }
  808. bool RLInterface::isAllowed(LLUUID object_id, std::string action,
  809. bool log_it)
  810. {
  811. if (log_it)
  812. {
  813. LL_DEBUGS("RestrainedLove") << object_id << " " << action
  814. << LL_ENDL;
  815. }
  816. rl_map_it_t it = mSpecialObjectBehaviours.find(object_id.asString());
  817. while (it != mSpecialObjectBehaviours.end() &&
  818. it != mSpecialObjectBehaviours.upper_bound(object_id.asString()))
  819. {
  820. #if 0
  821. if (log_it)
  822. {
  823. LL_DEBUGS("RestrainedLove") << " checking " << it->second
  824. << LL_ENDL;
  825. }
  826. #endif
  827. if (it->second == action)
  828. {
  829. if (log_it)
  830. {
  831. LL_DEBUGS("RestrainedLove") << " => forbidden. " << LL_ENDL;
  832. }
  833. return false;
  834. }
  835. ++it;
  836. }
  837. if (log_it)
  838. {
  839. LL_DEBUGS("RestrainedLove") << " => allowed. " << LL_ENDL;
  840. }
  841. return true;
  842. }
  843. bool RLInterface::contains(std::string action)
  844. {
  845. LLStringUtil::toLower(action);
  846. for (rl_map_it_t it = mSpecialObjectBehaviours.begin(),
  847. end = mSpecialObjectBehaviours.end();
  848. it != end; ++it)
  849. {
  850. if (it->second == action)
  851. {
  852. return true;
  853. }
  854. }
  855. return false;
  856. }
  857. bool RLInterface::containsSubstr(std::string action)
  858. {
  859. LLStringUtil::toLower(action);
  860. for (rl_map_it_t it = mSpecialObjectBehaviours.begin(),
  861. end = mSpecialObjectBehaviours.end();
  862. it != end; ++it)
  863. {
  864. if (it->second.find(action) != std::string::npos)
  865. {
  866. return true;
  867. }
  868. }
  869. return false;
  870. }
  871. bool RLInterface::containsWithoutException(std::string action,
  872. const std::string& except)
  873. {
  874. // 'action' is a restriction like @sendim, which can accept exceptions
  875. // (@sendim:except_uuid=add)
  876. // action_sec is the same action, with "_sec" appended (like @sendim_sec)
  877. LLStringUtil::toLower(action);
  878. std::string action_sec = action + "_sec";
  879. LLUUID id;
  880. // 1. If except is empty, behave like contains(), but looking for both
  881. // action and action_sec
  882. if (except.empty())
  883. {
  884. return contains(action) || contains(action_sec);
  885. }
  886. // 2. For each action_sec, if we do not find an exception tied to the same
  887. // object, return true. If @permissive is set, then even action needs the
  888. // exception to be tied to the same object, not just action_sec (@permissive
  889. // restrains the scope of all the exceptions to their own objects)
  890. for (rl_map_it_t it = mSpecialObjectBehaviours.begin(),
  891. end = mSpecialObjectBehaviours.end();
  892. it != end; ++it)
  893. {
  894. if (it->second == action_sec ||
  895. (it->second == action && mContainsPermissive))
  896. {
  897. id.set(it->first);
  898. // We use isAllowed because we need to check the object, but it
  899. // really means "does not contain"
  900. if (isAllowed(id, action + ":" + except, false) &&
  901. isAllowed(id, action_sec + ":" + except, false))
  902. {
  903. return true;
  904. }
  905. }
  906. }
  907. // 3. If we did not return yet, but the map contains action, just look for
  908. // except_uuid without regard to its object, if none is found return true
  909. if (contains(action))
  910. {
  911. if (!contains(action + ":" + except) &&
  912. !contains(action_sec + ":" + except))
  913. {
  914. return true;
  915. }
  916. }
  917. // 4. Finally return false if we did not find anything
  918. return false;
  919. }
  920. F32 RLInterface::getMax(std::string action, F32 dflt)
  921. {
  922. LLStringUtil::toLower(action);
  923. // an action may be a comma separated list list of behaviours
  924. action = "," + action + ",";
  925. F32 res = -EXTREMUM;
  926. F32 tmp;
  927. std::string command, behav, option, param;
  928. bool found_one = false;
  929. for (rl_map_it_t it = mSpecialObjectBehaviours.begin(),
  930. end = mSpecialObjectBehaviours.end();
  931. it != end; ++it)
  932. {
  933. command = it->second;
  934. LLStringUtil::toLower(command);
  935. if (parseCommand(command + "=n", behav, option, param))
  936. {
  937. if (action.find("," + behav + ",") != std::string::npos)
  938. {
  939. if (option.empty())
  940. {
  941. tmp = 1.5f;
  942. }
  943. else
  944. {
  945. tmp = atof(option.c_str());
  946. }
  947. if (tmp > res)
  948. {
  949. res = tmp;
  950. found_one = true;
  951. }
  952. }
  953. }
  954. }
  955. return found_one ? res : dflt;
  956. }
  957. F32 RLInterface::getMin(std::string action, F32 dflt)
  958. {
  959. LLStringUtil::toLower(action);
  960. // An action may be a comma separated list list of behaviours
  961. action = "," + action + ",";
  962. F32 res = EXTREMUM;
  963. F32 tmp;
  964. std::string command, behav, option, param;
  965. bool found_one = false;
  966. for (rl_map_it_t it = mSpecialObjectBehaviours.begin(),
  967. end = mSpecialObjectBehaviours.end();
  968. it != end; ++it)
  969. {
  970. command = it->second;
  971. LLStringUtil::toLower(command);
  972. if (parseCommand(command + "=n", behav, option, param))
  973. {
  974. if (action.find("," + behav + ",") != std::string::npos)
  975. {
  976. if (option.empty())
  977. {
  978. tmp = 1.5f;
  979. }
  980. else
  981. {
  982. tmp = atof(option.c_str());
  983. }
  984. if (tmp < res)
  985. {
  986. res = tmp;
  987. found_one = true;
  988. }
  989. }
  990. }
  991. }
  992. return found_one ? res : dflt;
  993. }
  994. LLColor3 RLInterface::getMixedColors(std::string action, LLColor3 dflt)
  995. {
  996. bool found = false;
  997. LLColor3 res = LLColor3::white;
  998. LLStringUtil::toLower(action);
  999. // An action may be a comma separated list list of behaviours
  1000. action = "," + action + ",";
  1001. LLColor3 tmp;
  1002. std::string command, behav, option, param;
  1003. std::deque<std::string> tokens;
  1004. for (rl_map_it_t it = mSpecialObjectBehaviours.begin(),
  1005. end = mSpecialObjectBehaviours.end();
  1006. it != end; ++it)
  1007. {
  1008. command = it->second;
  1009. LLStringUtil::toLower(command);
  1010. if (parseCommand(command + "=n", behav, option, param))
  1011. {
  1012. if (action.find("," + behav + ",") != std::string::npos)
  1013. {
  1014. tokens = parse(option, ";");
  1015. tmp.mV[0] = atof(tokens[0].c_str());
  1016. tmp.mV[1] = atof(tokens[1].c_str());
  1017. tmp.mV[2] = atof(tokens[2].c_str());
  1018. res *= tmp;
  1019. found = true;
  1020. }
  1021. }
  1022. }
  1023. return found ? res : dflt;
  1024. }
  1025. bool RLInterface::isFolderLocked(LLInventoryCategory* cat)
  1026. {
  1027. if (!cat) return false;
  1028. const LLFolderType::EType folder_type = cat->getPreferredType();
  1029. if (LLFolderType::lookupIsProtectedType(folder_type)) return false;
  1030. bool shared = isUnderRlvShare(cat);
  1031. if (!shared && contains("unsharedwear")) return true;
  1032. if (shared && contains("sharedwear")) return true;
  1033. if (isFolderLockedWithoutException(cat, "attach") != FolderNotLocked)
  1034. {
  1035. return true;
  1036. }
  1037. return isFolderLockedWithoutException(cat, "detach") != FolderNotLocked;
  1038. }
  1039. RLInterface::EFolderLock
  1040. RLInterface::isFolderLockedWithoutException(LLInventoryCategory* cat,
  1041. std::string attach_or_detach)
  1042. {
  1043. if (!cat) return FolderNotLocked;
  1044. LL_DEBUGS("RestrainedLove") << "Category: " << cat->getName()
  1045. << " - attach_or_detach: " << attach_or_detach
  1046. << LL_ENDL;
  1047. // For each object that is locking this folder, check whether it also
  1048. // issues exceptions to this lock
  1049. std::deque<std::string> commands_list;
  1050. std::string command, behav, option, param;
  1051. std::string this_command, this_behav, this_option, this_param;
  1052. bool this_object_locks;
  1053. EFolderLock current_lock = FolderNotLocked;
  1054. for (rl_map_it_t it = mSpecialObjectBehaviours.begin(),
  1055. end = mSpecialObjectBehaviours.end();
  1056. it != end; ++it)
  1057. {
  1058. LLUUID id(it->first);
  1059. command = it->second;
  1060. LL_DEBUGS("RestrainedLove") << "command = " << command << LL_ENDL;
  1061. // param will always be equal to "n" in this case since we added it to
  1062. // command, but we do not care about this here
  1063. // detach=n, recvchat=n, recvim=n, unsit=n, recvim:<uuid>=add,
  1064. // clear=tplure...
  1065. // Attention, an option must absolutely be specified here (there must
  1066. // be a ':' character), or we would not be able to tell "detachthis"
  1067. // from "detachthis:" and both have different meanings.
  1068. if (command.find(':') != std::string::npos &&
  1069. parseCommand(command + "=n", behav, option, param))
  1070. {
  1071. // find whether this object has issued a "{attach|detach}[all]this"
  1072. // command on a folder that is either this one, or a parent
  1073. this_object_locks = false;
  1074. if (behav == attach_or_detach + "this")
  1075. {
  1076. if (getCategoryUnderRlvShare(option) == cat)
  1077. {
  1078. this_object_locks = true;
  1079. }
  1080. }
  1081. else if (behav == attach_or_detach + "allthis")
  1082. {
  1083. if (isUnderFolder(getCategoryUnderRlvShare(option), cat))
  1084. {
  1085. this_object_locks = true;
  1086. }
  1087. }
  1088. // This object has issued such a command, check whether it has
  1089. // issued an exception to it as well
  1090. if (this_object_locks)
  1091. {
  1092. commands_list = getListOfRestrictions(id);
  1093. EFolderLock this_lock =
  1094. isFolderLockedWithoutExceptionAux(cat, attach_or_detach,
  1095. commands_list);
  1096. if (this_lock == FolderLockedNoException)
  1097. {
  1098. return FolderLockedNoException;
  1099. }
  1100. else
  1101. {
  1102. current_lock = this_lock;
  1103. }
  1104. LL_DEBUGS("RestrainedLove") << "this_lock=" << this_lock
  1105. << LL_ENDL;
  1106. }
  1107. }
  1108. }
  1109. // Finally, return unlocked since we did not find any lock on this folder
  1110. return current_lock;
  1111. }
  1112. RLInterface::EFolderLock
  1113. RLInterface::isFolderLockedWithoutExceptionAux(LLInventoryCategory* cat,
  1114. std::string attach_or_detach,
  1115. std::deque<std::string> restrictions)
  1116. {
  1117. // 'restrictions' contains the list of restrictions issued by one
  1118. // particular object, at least one is supposed to be a
  1119. // "{attach|detach}[all]this".
  1120. // For each folder from cat up to the root folder, check :
  1121. // - if we are on cat and we find "{attach|detach}this_except", there is an
  1122. // exception, keep looking up
  1123. // - if we are on cat and we find "{attach|detach}this", there is no
  1124. // exception, return FolderLockedNoException
  1125. // - if we are on a parent and we find "{attach|detach}allthis_except",
  1126. // there is an exception, keep looking up
  1127. // - if we are on a parent and we find "{attach|detach}allthis", if we
  1128. // found an exception return FolderLockedWithException, else return
  1129. // FolderLockedNoException
  1130. // - finally, if we are on the root, return FolderLocked_unlocked (whether
  1131. // there was an exception or not)
  1132. if (!cat) return FolderNotLocked;
  1133. LL_DEBUGS("RestrainedLove") << "isFolderLockedWithoutExceptionAux("
  1134. << cat->getName() << ", " << attach_or_detach
  1135. << ", ["
  1136. << dumpList2String(restrictions, ",")
  1137. << "])" << LL_ENDL;
  1138. EFolderLock current_lock = FolderNotLocked;
  1139. std::string command, behav, option, param;
  1140. const LLUUID& root_id = gInventory.getRootFolderID();
  1141. const LLUUID& cat_id = cat->getUUID();
  1142. LLInventoryCategory* it = gInventory.getCategory(cat_id);
  1143. LLInventoryCategory* cat_option = NULL;
  1144. do
  1145. {
  1146. LL_DEBUGS("RestrainedLove") << "it=" << it->getName() << LL_ENDL;
  1147. for (U32 i = 0; i < restrictions.size(); ++i)
  1148. {
  1149. command = restrictions[i];
  1150. LL_DEBUGS("RestrainedLove") << "command2=" << command << LL_ENDL;
  1151. // 'param' will always be equal to "n" in this case since we added
  1152. // it to command, but we do not care about this here
  1153. // detach=n, recvchat=n, recvim=n, unsit=n, recvim:<uuid>=add,
  1154. // clear=tplure:
  1155. if (parseCommand(command + "=n", behav, option, param))
  1156. {
  1157. cat_option = getCategoryUnderRlvShare(option);
  1158. if (cat_option == it)
  1159. {
  1160. if (it == cat)
  1161. {
  1162. if (behav == attach_or_detach + "this_except" ||
  1163. behav == attach_or_detach + "allthis_except")
  1164. {
  1165. current_lock = FolderLockedWithException;
  1166. }
  1167. else if (behav == attach_or_detach + "this" ||
  1168. behav == attach_or_detach + "allthis")
  1169. {
  1170. return FolderLockedNoException;
  1171. }
  1172. }
  1173. else if (behav == attach_or_detach + "allthis_except")
  1174. {
  1175. current_lock = FolderLockedWithException;
  1176. }
  1177. else if (behav == attach_or_detach + "allthis")
  1178. {
  1179. if (current_lock == FolderLockedWithException)
  1180. {
  1181. return FolderLockedWithException;
  1182. }
  1183. else
  1184. {
  1185. return FolderLockedNoException;
  1186. }
  1187. }
  1188. }
  1189. }
  1190. }
  1191. const LLUUID& parent_id = it->getParentUUID();
  1192. it = gInventory.getCategory(parent_id);
  1193. }
  1194. while (it && it->getUUID() != root_id);
  1195. // This should never happen since list_of_commands is supposed to contain
  1196. // at least one "{attach|detach}[all]this" restriction
  1197. return FolderNotLocked;
  1198. }
  1199. bool RLInterface::isBlacklisted(const LLUUID& id, std::string command,
  1200. const std::string& option, bool force)
  1201. {
  1202. // Possibly allow all RestrainedLove commands for Lua scripts (automation
  1203. // script, chat command line script, executed Lua file script, but not a
  1204. // Lua command line relayed from an object, or via D-Bus under Linux), even
  1205. // black-listed ones.
  1206. static LLCachedControl<bool> lua_skip(gSavedSettings,
  1207. "RestrainedLoveLuaNoBlacklist");
  1208. if (lua_skip && id == gAgentID)
  1209. {
  1210. return false;
  1211. }
  1212. if (sRLNoSetEnv && command.compare(0, 6, "setenv") == 0)
  1213. {
  1214. return true;
  1215. }
  1216. if (mHandleNoRelay && !option.empty() &&
  1217. option.find(RL_NORELAY_FOLDER_TAG) != std::string::npos)
  1218. {
  1219. return true;
  1220. }
  1221. if (sBlackList.empty())
  1222. {
  1223. return false;
  1224. }
  1225. size_t i = command.find('_');
  1226. if (i != std::string::npos && command.find("_sec") != i &&
  1227. command.find("_except") != i)
  1228. {
  1229. command = command.substr(0, i + 1);
  1230. }
  1231. if (force)
  1232. {
  1233. command += "%f";
  1234. }
  1235. rl_command_map_it_t it = sCommandsMap.find(command);
  1236. if (it == sCommandsMap.end())
  1237. {
  1238. return false;
  1239. }
  1240. S32 type = it->second;
  1241. if (type == (S32)RL_INFO || type == (S32)RL_MISCELLANEOUS)
  1242. {
  1243. return false;
  1244. }
  1245. std::string blacklist = "," + sBlackList + ",";
  1246. return blacklist.find("," + command + ",") != std::string::npos;
  1247. }
  1248. bool RLInterface::add(const LLUUID& obj_id, std::string action,
  1249. std::string option)
  1250. {
  1251. LL_DEBUGS("RestrainedLove") << obj_id << ": " << action << " / " << option
  1252. << LL_ENDL;
  1253. mLastCmdBlacklisted = false;
  1254. std::string canon_action = action;
  1255. if (!option.empty())
  1256. {
  1257. action += ":" + option;
  1258. }
  1259. if (!isAllowed(obj_id, action))
  1260. {
  1261. return false;
  1262. }
  1263. // Notify if needed
  1264. notify(action, "=n");
  1265. // Check the action against the blacklist
  1266. if (isBlacklisted(obj_id, canon_action, option))
  1267. {
  1268. mLastCmdBlacklisted = true;
  1269. llinfos << "Blacklisted RestrainedLove command: " << action
  1270. << "=n for object " << obj_id << llendl;
  1271. return true;
  1272. }
  1273. // Actions to do BEFORE inserting the new behav
  1274. if (action == "shownames" || action == "shownames_sec" ||
  1275. action == "shownametags")
  1276. {
  1277. LLFloaterChat::getInstance()->childSetVisible("active_speakers_panel",
  1278. false);
  1279. }
  1280. else if (action == "fly")
  1281. {
  1282. gAgent.setFlying(false);
  1283. }
  1284. else if (action == "temprun")
  1285. {
  1286. if (gAgent.getRunning())
  1287. {
  1288. if (gAgent.getAlwaysRun())
  1289. {
  1290. gAgent.clearAlwaysRun();
  1291. }
  1292. gAgent.clearRunning();
  1293. gAgent.sendWalkRun(false);
  1294. }
  1295. }
  1296. else if (action == "alwaysrun")
  1297. {
  1298. if (gAgent.getAlwaysRun())
  1299. {
  1300. if (gAgent.getRunning())
  1301. {
  1302. gAgent.clearRunning();
  1303. }
  1304. gAgent.clearAlwaysRun();
  1305. gAgent.sendWalkRun(false);
  1306. }
  1307. }
  1308. else if (action == "edit")
  1309. {
  1310. gSavedSettings.setBool("BeaconAlwaysOn", false);
  1311. LLDrawPoolAlpha::sShowDebugAlpha = false;
  1312. }
  1313. else if (action == "setenv")
  1314. {
  1315. gSavedSettings.setBool("UseLocalEnvironment", false);
  1316. gSavedSettings.setBool("UseParcelEnvironment", false);
  1317. }
  1318. else if (action == "camunlock" || action == "setcam_unlock")
  1319. {
  1320. gAgent.resetView(true, true);
  1321. }
  1322. // Insert the new behav
  1323. mSpecialObjectBehaviours.emplace(obj_id.asString(), action);
  1324. refreshCachedVariable(action);
  1325. // Actions to do AFTER inserting the new behav
  1326. if (action == "showhovertextall" || action == "showloc" ||
  1327. action == "shownames" || action == "showhovertexthud" ||
  1328. action == "showhovertextworld")
  1329. {
  1330. updateAllHudTexts();
  1331. }
  1332. else if (canon_action == "showhovertext")
  1333. {
  1334. updateOneHudText(LLUUID(option));
  1335. }
  1336. else if (canon_action.compare(0, 3, "cam") == 0 ||
  1337. canon_action.compare(0, 7, "setcam_") == 0)
  1338. {
  1339. updateCameraLimits();
  1340. // Force an update of the zoom if necessary
  1341. if (canon_action == "camzoommax" || canon_action == "camzoommin" ||
  1342. canon_action == "setcam_fovmin" || canon_action == "setcam_fovmax")
  1343. {
  1344. gViewerCamera.setDefaultFOV(gSavedSettings.getF32("CameraAngle"));
  1345. // setView() may have clamped it:
  1346. gSavedSettings.setF32("CameraAngle", gViewerCamera.getView());
  1347. }
  1348. }
  1349. else if (canon_action == "fartouch" || canon_action == "touchfar" ||
  1350. canon_action == "sittp" || canon_action == "tplocal")
  1351. {
  1352. updateLimits();
  1353. }
  1354. // Update the stored last standing location, to allow grabbers to
  1355. // transport a victim inside a cage while sitting, and restrict them
  1356. // before standing up. If we did not do this, the avatar would snap
  1357. // back to a safe location when being unsitted by the grabber, which
  1358. // would be rather silly.
  1359. if (action == "standtp")
  1360. {
  1361. storeLastStandingLoc(true);
  1362. }
  1363. return true;
  1364. }
  1365. bool RLInterface::remove(const LLUUID& obj_id, std::string action,
  1366. std::string option)
  1367. {
  1368. LL_DEBUGS("RestrainedLove") << obj_id << ":" << action << " / " << option
  1369. << LL_ENDL;
  1370. std::string canon_action = action;
  1371. if (!option.empty())
  1372. {
  1373. action += ":" + option;
  1374. }
  1375. // Notify if needed
  1376. notify(action, "=y");
  1377. // Actions to do BEFORE removing the behav
  1378. // Remove the behav
  1379. rl_map_it_t it = mSpecialObjectBehaviours.find(obj_id.asString());
  1380. while (it != mSpecialObjectBehaviours.end() &&
  1381. it != mSpecialObjectBehaviours.upper_bound(obj_id.asString()))
  1382. {
  1383. #if 0
  1384. LL_DEBUGS("RestrainedLove") << " Checking " << it->second << LL_ENDL;
  1385. #endif
  1386. if (it->second == action)
  1387. {
  1388. mSpecialObjectBehaviours.erase(it);
  1389. LL_DEBUGS("RestrainedLove") << " => removed." << LL_ENDL;
  1390. refreshCachedVariable(action);
  1391. // Actions to do AFTER removing the behav
  1392. if (action == "shownames" || action == "showloc" ||
  1393. action == "showhovertexthud" || action == "showhovertextall" ||
  1394. action == "showhovertextworld")
  1395. {
  1396. updateAllHudTexts();
  1397. }
  1398. else if (canon_action == "showhovertext")
  1399. {
  1400. updateOneHudText(LLUUID(option));
  1401. }
  1402. else if (action == "standtp")
  1403. {
  1404. // If not sitting, then we can clear the last standing location
  1405. if (isAgentAvatarValid() && !gAgentAvatarp->mIsSitting)
  1406. {
  1407. mLastStandingLocation.clear();
  1408. gSavedPerAccountSettings.setVector3d("RestrainedLoveLastStandingLocation",
  1409. mLastStandingLocation);
  1410. }
  1411. }
  1412. else if (canon_action.compare(0, 3, "cam") == 0 ||
  1413. canon_action.compare(0, 7, "setcam_") == 0)
  1414. {
  1415. updateCameraLimits();
  1416. }
  1417. else if (canon_action == "fartouch" ||
  1418. canon_action == "touchfar" ||
  1419. canon_action == "sittp" || canon_action == "tplocal")
  1420. {
  1421. updateLimits();
  1422. }
  1423. return true;
  1424. }
  1425. ++it;
  1426. }
  1427. LL_DEBUGS("RestrainedLove") << " => not in force." << LL_ENDL;
  1428. return false;
  1429. }
  1430. bool RLInterface::clear(const LLUUID& obj_id, const std::string& command)
  1431. {
  1432. LL_DEBUGS("RestrainedLove") << obj_id << ": " << command << LL_ENDL;
  1433. // Notify if needed
  1434. notify("clear" + (command.empty() ? "" : ":" + command));
  1435. const std::string id_as_str = obj_id.asString();
  1436. rl_map_it_t it = mSpecialObjectBehaviours.begin();
  1437. while (it != mSpecialObjectBehaviours.end())
  1438. {
  1439. LL_DEBUGS("RestrainedLove") << " removing " << it->second << LL_ENDL;
  1440. if (it->first == id_as_str &&
  1441. (command.empty() || it->second.find(command) != std::string::npos))
  1442. {
  1443. notify(it->second, "=y");
  1444. LL_DEBUGS("RestrainedLove") << it->second << " => removed."
  1445. << LL_ENDL;
  1446. std::string tmp = it->second;
  1447. mSpecialObjectBehaviours.erase(it);
  1448. refreshCachedVariable(tmp);
  1449. it = mSpecialObjectBehaviours.begin();
  1450. }
  1451. else
  1452. {
  1453. ++it;
  1454. }
  1455. }
  1456. // If not still under @standtp restriction, or not sitting, then we can
  1457. // clear the last standing location
  1458. if (!mContainsStandtp ||
  1459. (isAgentAvatarValid() && !gAgentAvatarp->mIsSitting))
  1460. {
  1461. mLastStandingLocation.clear();
  1462. gSavedPerAccountSettings.setVector3d("RestrainedLoveLastStandingLocation",
  1463. mLastStandingLocation);
  1464. }
  1465. updateAllHudTexts();
  1466. updateCameraLimits();
  1467. updateLimits();
  1468. return true;
  1469. }
  1470. void RLInterface::replace(const LLUUID& src_id, const LLUUID& by_id)
  1471. {
  1472. LLUUID id;
  1473. rl_map_it_t it = mSpecialObjectBehaviours.begin();
  1474. while (it != mSpecialObjectBehaviours.end())
  1475. {
  1476. id.set(it->first);
  1477. if (id == src_id)
  1478. {
  1479. // Found the UUID to replace => add a copy of the command with the
  1480. // new UUID
  1481. mSpecialObjectBehaviours.emplace(by_id.asString(), it->second);
  1482. }
  1483. ++it;
  1484. }
  1485. // And then clear the old UUID
  1486. clear(src_id, "");
  1487. HBFloaterRLV::setDirty();
  1488. }
  1489. bool RLInterface::garbageCollector(bool all)
  1490. {
  1491. bool res = false;
  1492. LLUUID id;
  1493. rl_map_it_t it = mSpecialObjectBehaviours.begin();
  1494. while (it != mSpecialObjectBehaviours.end())
  1495. {
  1496. id.set(it->first);
  1497. #if LL_LINUX
  1498. bool is_lua = id == gAgentID ||
  1499. (id == HBViewerAutomation::sLuaDBusFakeObjectId &&
  1500. id.notNull());
  1501. #else
  1502. bool is_lua = id == gAgentID;
  1503. #endif
  1504. if (!is_lua && (all || id.notNull()))
  1505. {
  1506. LLViewerObject* objp = gObjectList.findObject(id);
  1507. if (!objp)
  1508. {
  1509. LL_DEBUGS("RestrainedLove") << it->first
  1510. << " not found => cleaning... "
  1511. << LL_ENDL;
  1512. clear(id);
  1513. res = true;
  1514. it = mSpecialObjectBehaviours.begin();
  1515. HBFloaterRLV::setDirty();
  1516. }
  1517. else
  1518. {
  1519. ++it;
  1520. }
  1521. }
  1522. else
  1523. {
  1524. LL_DEBUGS("RestrainedLove") << "Ignoring " << it->second
  1525. << LL_ENDL;
  1526. ++it;
  1527. }
  1528. }
  1529. return res;
  1530. }
  1531. std::deque<std::string> RLInterface::parse(std::string str, std::string sep)
  1532. {
  1533. size_t ind;
  1534. size_t length = sep.length();
  1535. std::string token;
  1536. std::deque<std::string> res;
  1537. do
  1538. {
  1539. ind = str.find(sep);
  1540. if (ind != std::string::npos)
  1541. {
  1542. token = str.substr(0, ind);
  1543. if (!token.empty())
  1544. {
  1545. res.emplace_back(token);
  1546. }
  1547. str = str.substr(ind + length);
  1548. }
  1549. else if (!str.empty())
  1550. {
  1551. res.emplace_back(str);
  1552. }
  1553. }
  1554. while (ind != std::string::npos);
  1555. return res;
  1556. }
  1557. void RLInterface::notify(const std::string& action, const std::string& suffix)
  1558. {
  1559. size_t length = 7; // size of "notify:"
  1560. std::deque<std::string> tokens;
  1561. std::string rule;
  1562. LLUUID obj_id;
  1563. for (rl_map_it_t it = mSpecialObjectBehaviours.begin(),
  1564. end = mSpecialObjectBehaviours.end();
  1565. it != end; ++it)
  1566. {
  1567. // We are looking for rules like "notify:2222;tp", if action contains
  1568. // "tp" then notify the scripts on channel 2222
  1569. rule = it->second;
  1570. if (rule.compare(0, 7, "notify:") == 0)
  1571. {
  1572. // Found a possible notification to send
  1573. rule = rule.substr(length); // keep right part only(here "2222;tp")
  1574. tokens = parse(rule, ";");
  1575. S32 size = tokens.size();
  1576. if (size == 1 ||
  1577. (size > 1 && action.find(tokens[1]) != std::string::npos))
  1578. {
  1579. obj_id.set(it->first);
  1580. // suffix can be "=n", "=y" or whatever else we want, "/" is
  1581. // needed to avoid some clever griefing
  1582. answerOnChat(obj_id, tokens[0], "/" + action + suffix);
  1583. }
  1584. }
  1585. }
  1586. }
  1587. bool RLInterface::parseCommand(const std::string& command,
  1588. std::string& behaviour, std::string& option,
  1589. std::string& param)
  1590. {
  1591. size_t i = command.find('=');
  1592. if (i == std::string::npos)
  1593. {
  1594. behaviour = command;
  1595. param.clear();
  1596. option.clear();
  1597. return false;
  1598. }
  1599. behaviour = command.substr(0, i);
  1600. param = command.substr(i + 1);
  1601. i = behaviour.find(':');
  1602. if (i != std::string::npos)
  1603. {
  1604. option = behaviour.substr(i + 1);
  1605. // Keep in this order(option first, then behav) or crash
  1606. behaviour = behaviour.substr(0, i);
  1607. }
  1608. else
  1609. {
  1610. option.clear();
  1611. }
  1612. return true;
  1613. }
  1614. bool RLInterface::handleCommand(const LLUUID& id, std::string command)
  1615. {
  1616. mHandleNoRelay = mRelays.count(id) != 0;
  1617. // Parse the command, which is of one of these forms:
  1618. // behav=param
  1619. // behav:option=param
  1620. std::string behav, option, param;
  1621. LLStringUtil::toLower(command);
  1622. // detach=n, recvchat=n, recvim=n, unsit=n, recvim:<uuid>=add,
  1623. // clear=tplure:
  1624. if (parseCommand(command, behav, option, param))
  1625. {
  1626. LL_DEBUGS("RestrainedLove") << "[" << id << "] [" << behav << "] ["
  1627. << option << "] [" << param << "]"
  1628. << LL_ENDL;
  1629. if (gAutomationp)
  1630. {
  1631. gAutomationp->onRLVHandleCommand(id, behav, option, param);
  1632. }
  1633. if (behav == "version")
  1634. {
  1635. return answerOnChat(id, param, getVersion());
  1636. }
  1637. else if (behav == "versionnew")
  1638. {
  1639. return answerOnChat(id, param, getVersion2());
  1640. }
  1641. else if (behav == "versionnum")
  1642. {
  1643. return answerOnChat(id, param, RL_VERSION_NUM);
  1644. }
  1645. else if (behav == "versionnumbl")
  1646. {
  1647. return answerOnChat(id, param, getVersionNum());
  1648. }
  1649. else if (behav == "getblacklist")
  1650. {
  1651. return answerOnChat(id, param,
  1652. dumpList2String(getBlacklist(option), ","));
  1653. }
  1654. else if (behav == "getoutfit")
  1655. {
  1656. return answerOnChat(id, param, getOutfit(option));
  1657. }
  1658. else if (behav == "getattach")
  1659. {
  1660. return answerOnChat(id, param, getAttachments(option));
  1661. }
  1662. else if (behav == "getstatus")
  1663. {
  1664. return answerOnChat(id, param, getStatus(id, option));
  1665. }
  1666. else if (behav == "getstatusall")
  1667. {
  1668. return answerOnChat(id, param, getStatus(LLUUID::null, option));
  1669. }
  1670. else if (behav == "getcommand")
  1671. {
  1672. return answerOnChat(id, param, getCommand(option));
  1673. }
  1674. else if (behav == "getinv")
  1675. {
  1676. return answerOnChat(id, param, getInventoryList(option));
  1677. }
  1678. else if (behav == "getinvworn")
  1679. {
  1680. return answerOnChat(id, param, getInventoryList(option, true));
  1681. }
  1682. else if (behav == "getsitid")
  1683. {
  1684. return answerOnChat(id, param, mSitTargetId.asString());
  1685. }
  1686. else if (behav == "getpath")
  1687. {
  1688. // Option can be empty (=> find path to object) or the name of an
  1689. // attach pt or the name of a clothing layer
  1690. return answerOnChat(id, param,
  1691. getFullPath(getItem(id), option, false));
  1692. }
  1693. else if (behav == "getpathnew")
  1694. {
  1695. // Option can be empty (=> find path to object) or the name of an
  1696. // attach pt or the name of a clothing layer
  1697. return answerOnChat(id, param, getFullPath(getItem(id), option));
  1698. }
  1699. else if (behav == "findfolder")
  1700. {
  1701. return answerOnChat(id, param,
  1702. getFullPath(findCategoryUnderRlvShare(option)));
  1703. }
  1704. else if (behav == "findfolders")
  1705. {
  1706. std::string response;
  1707. std::deque<std::string> options = parse(option, ";");
  1708. S32 opt_count = options.size();
  1709. if (opt_count)
  1710. {
  1711. const std::string& folder_to_find = options[0];
  1712. const std::string& separator = opt_count > 1 ? options[1] : ",";
  1713. std::deque<LLInventoryCategory*> cats =
  1714. findCategoriesUnderRlvShare(folder_to_find);
  1715. for (S32 i = 0, count = cats.size(); i < count; ++i)
  1716. {
  1717. if (i > 0)
  1718. {
  1719. response += separator;
  1720. }
  1721. response += getFullPath(cats[i]);
  1722. }
  1723. }
  1724. return answerOnChat(id, param, response);
  1725. }
  1726. else if (behav.compare(0, 7, "getenv_") == 0)
  1727. {
  1728. return answerOnChat(id, param, getEnvironment(behav));
  1729. }
  1730. else if (behav.compare(0, 9, "getdebug_") == 0)
  1731. {
  1732. return answerOnChat(id, param, getDebugSetting(behav));
  1733. }
  1734. else if (behav == "getgroup")
  1735. {
  1736. LLUUID group_id = gAgent.getGroupID();
  1737. std::string group_name = "none";
  1738. if (group_id.notNull() && gCacheNamep)
  1739. {
  1740. gCacheNamep->getGroupName(group_id, group_name);
  1741. }
  1742. return answerOnChat(id, param, group_name);
  1743. }
  1744. else if (behav == "getcam_avdistmin")
  1745. {
  1746. std::stringstream str;
  1747. str << std::fixed << mCamDistMin;
  1748. return answerOnChat(id, param, str.str());
  1749. }
  1750. else if (behav == "getcam_avdistmax")
  1751. {
  1752. std::stringstream str;
  1753. str << std::fixed << mCamDistMax;
  1754. return answerOnChat(id, param, str.str());
  1755. }
  1756. else if (behav == "getcam_zoommin")
  1757. {
  1758. std::stringstream str;
  1759. str << std::fixed << mCamZoomMin;
  1760. return answerOnChat(id, param, str.str());
  1761. }
  1762. else if (behav == "getcam_zoommax")
  1763. {
  1764. std::stringstream str;
  1765. str << std::fixed << mCamZoomMax;
  1766. return answerOnChat(id, param, str.str());
  1767. }
  1768. else if (behav == "getcam_fovmin")
  1769. {
  1770. std::stringstream str;
  1771. str << std::fixed << DEFAULT_FIELD_OF_VIEW / mCamZoomMax;
  1772. return answerOnChat(id, param, str.str());
  1773. }
  1774. else if (behav == "getcam_fovmax")
  1775. {
  1776. std::stringstream str;
  1777. str << std::fixed << DEFAULT_FIELD_OF_VIEW / mCamZoomMin;
  1778. return answerOnChat(id, param, str.str());
  1779. }
  1780. else if (behav == "getcam_fov")
  1781. {
  1782. std::stringstream str;
  1783. str << std::fixed << gViewerCamera.getView();
  1784. return answerOnChat(id, param, str.str());
  1785. }
  1786. else if (behav == "getcam_textures")
  1787. {
  1788. LLUUID tex_id;
  1789. if (mCamTexturesCustom)
  1790. {
  1791. tex_id = mCamTexturesCustom->getID();
  1792. }
  1793. return answerOnChat(id, param, tex_id.asString());
  1794. }
  1795. else if (param == "n" || param == "add")
  1796. {
  1797. if (behav == "unsit" && (mGotSit || mGotUnsit))
  1798. {
  1799. mSkipAll = true;
  1800. LL_DEBUGS("RestrainedLove") << "Detected @unsit=n command right after @"
  1801. << (mGotSit ? "sit" : "unsit")
  1802. << "=force. Delaying." << LL_ENDL;
  1803. return true;
  1804. }
  1805. add(id, behav, option);
  1806. }
  1807. else if (param == "y" || param == "rem")
  1808. {
  1809. remove(id, behav, option);
  1810. }
  1811. else if (behav == "clear")
  1812. {
  1813. clear(id, param);
  1814. }
  1815. else if (param == "force")
  1816. {
  1817. if ((mGotUnsit && (behav == "sit" || behav == "sitground")) ||
  1818. (mGotSit && behav == "unsit"))
  1819. {
  1820. // When we just executed an (un)sit=force command in the queue,
  1821. // skip any opposite (un)sit=force command and everything
  1822. // following it, so to let some time for the viewer and server
  1823. // to agree on the sitting status...
  1824. mSkipAll = true;
  1825. LL_DEBUGS("RestrainedLove") << "Detected @" << behav
  1826. << "=force command right after @"
  1827. << (mGotSit ? "sit*" : "unsit")
  1828. << "=force. Delaying." << LL_ENDL;
  1829. return true;
  1830. }
  1831. return force(id, behav, option);
  1832. }
  1833. else
  1834. {
  1835. return false;
  1836. }
  1837. }
  1838. else
  1839. {
  1840. LL_DEBUGS("RestrainedLove") << id << ": "
  1841. << (behav == " " ? "Cancelling @relayed"
  1842. : behav)
  1843. << LL_ENDL;
  1844. if (behav == "clear")
  1845. {
  1846. clear(id);
  1847. }
  1848. else if (behav == "relayed")
  1849. {
  1850. mRelays.emplace(id);
  1851. }
  1852. else if (behav == " ") // A single space means "end relayed"
  1853. {
  1854. mRelays.erase(id);
  1855. }
  1856. else
  1857. {
  1858. return false;
  1859. }
  1860. }
  1861. return true;
  1862. }
  1863. void RLInterface::fireCommands()
  1864. {
  1865. // Do not execute queued commands if the avatar is not yet fully baked !
  1866. if (!LLStartUp::isLoggedIn() || !isAgentAvatarValid() ||
  1867. (!mAssetsToReattach.empty() && !mReattachTimeout) ||
  1868. !gAppearanceMgr.isAvatarFullyBaked())
  1869. {
  1870. return;
  1871. }
  1872. // Check if the last @sit=force or @unsit=force has been executed
  1873. bool is_sitting = gAgentAvatarp->mIsSitting;
  1874. if (mGotSit && is_sitting)
  1875. {
  1876. mSkipAll = mGotSit = false;
  1877. }
  1878. if (mGotUnsit && !is_sitting)
  1879. {
  1880. mSkipAll = mGotUnsit = false;
  1881. }
  1882. if (mSkipAll && mSitUnsitDelayTimer.getElapsedTimeF32() > 1.f)
  1883. {
  1884. llwarns << "Timeout waiting for " << (mGotSit ? "sit" : "unsit")
  1885. << " event. Resuming command queue processing." << llendl;
  1886. mSkipAll = mGotSit = mGotUnsit = false;
  1887. }
  1888. if (mQueuedCommands.empty())
  1889. {
  1890. return;
  1891. }
  1892. LL_DEBUGS("RestrainedLove") << "Number of currently queued commands: "
  1893. << mQueuedCommands.size() << LL_ENDL;
  1894. while (!mQueuedCommands.empty() && !mSkipAll)
  1895. {
  1896. S32 result = HBFloaterRLV::EXECUTED;
  1897. const RLCommand& cmd = mQueuedCommands[0];
  1898. mLastCmdBlacklisted = false;
  1899. if (handleCommand(cmd.mId, cmd.mCommand))
  1900. {
  1901. // "Success" executing this command (which could as well have been
  1902. // black-listed and thus ignored).
  1903. if (mLastCmdBlacklisted)
  1904. {
  1905. mLastCmdBlacklisted = false;
  1906. result = HBFloaterRLV::BLACKLISTED;
  1907. }
  1908. }
  1909. else
  1910. {
  1911. // Failure executing this command
  1912. result = HBFloaterRLV::FAILED;
  1913. }
  1914. HBFloaterRLV::logCommand(cmd.mId, cmd.mName, cmd.mCommand, result);
  1915. mQueuedCommands.pop_front();
  1916. }
  1917. LL_DEBUGS("RestrainedLove") << "Number of remaining queued commands: "
  1918. << mQueuedCommands.size() << LL_ENDL;
  1919. }
  1920. void RLInterface::queueCommand(const LLUUID& id, const std::string& name,
  1921. const std::string& command)
  1922. {
  1923. // Never queue any of the @version* and @getcommand commands: answer them
  1924. // immediately. These commands are likely to be sent as soon as a scripted
  1925. // RLV attachment rezzes as a form of "ping" to discover whether the viewer
  1926. // supports RestrainedLove or not, and with what features; since we delay
  1927. // other commands processing after full rezzing and baking of the agent
  1928. // (which may take an indeterminate amount of time, especially if the
  1929. // inventory cache got emptied before login), we cannot risk having the
  1930. // attachment timing out on us...
  1931. if (command.compare(0, 7, "version") == 0 ||
  1932. command.compare(0, 10, "getcommand") == 0)
  1933. {
  1934. if (handleCommand(id, command))
  1935. {
  1936. // Success executing this command. Note: "version" and "getcommand"
  1937. // cannot be black-listed, so we do not check for it.
  1938. HBFloaterRLV::logCommand(id, name, command);
  1939. }
  1940. else
  1941. {
  1942. // Failure executing this command
  1943. HBFloaterRLV::logCommand(id, name, command, HBFloaterRLV::FAILED);
  1944. }
  1945. }
  1946. else
  1947. {
  1948. // A single space means "end relayed": do not log it.
  1949. if (command != " ")
  1950. {
  1951. HBFloaterRLV::logCommand(id, name, command, HBFloaterRLV::QUEUED);
  1952. }
  1953. mQueuedCommands.emplace_back(id, name.empty() ? id.asString() : name,
  1954. command);
  1955. }
  1956. }
  1957. void RLInterface::queueCommands(const LLUUID& id, const std::string& name,
  1958. const std::string& cmd_line)
  1959. {
  1960. // Check whether the command is a single one or instead a coma-separated
  1961. // list of commands, and act accordingly.
  1962. if (cmd_line.find(',') != std::string::npos)
  1963. {
  1964. bool has_relayed = false;
  1965. std::deque<std::string> list_of_commands = parse(cmd_line, ",");
  1966. for (U32 i = 0; i < list_of_commands.size(); ++i)
  1967. {
  1968. const std::string& command = list_of_commands[i];
  1969. if (command.length() > 1 && command[0] != ' ')
  1970. {
  1971. queueCommand(id, name, command);
  1972. }
  1973. if (command == "relayed")
  1974. {
  1975. has_relayed = true;
  1976. }
  1977. }
  1978. if (has_relayed)
  1979. {
  1980. // A single space means "end relayed"
  1981. queueCommand(id, name, " ");
  1982. }
  1983. }
  1984. else if (cmd_line != "relayed") // a single @relayed command is a NOP
  1985. {
  1986. queueCommand(id, name, cmd_line);
  1987. }
  1988. }
  1989. void RLInterface::storeLastStandingLoc(bool force)
  1990. {
  1991. if (force || (isAgentAvatarValid() && !gAgentAvatarp->mIsSitting))
  1992. {
  1993. // We are now standing, and we want to sit down => store our current
  1994. // location so that we can snap back here when we stand up, if under
  1995. // @standtp
  1996. LLVector3d pos = LLVector3d(gAgent.getPositionGlobal());
  1997. mLastStandingLocation = pos;
  1998. gSavedPerAccountSettings.setVector3d("RestrainedLoveLastStandingLocation",
  1999. pos);
  2000. mHandleBackToLastStanding = false;
  2001. }
  2002. }
  2003. void RLInterface::validateLastStandingLoc()
  2004. {
  2005. if (!gRLenabled || (!mContainsStandtp && !mHandleBackToLastStanding))
  2006. {
  2007. // Reset this position to zero if not restricted with @standtp
  2008. gSavedPerAccountSettings.setVector3d("RestrainedLoveLastStandingLocation",
  2009. LLVector3d(0.0, 0.0, 0.0));
  2010. }
  2011. }
  2012. void RLInterface::restoreLastStandingLoc()
  2013. {
  2014. mLastStandingLocation =
  2015. gSavedPerAccountSettings.getVector3d("RestrainedLoveLastStandingLocation");
  2016. mHandleBackToLastStanding = !mLastStandingLocation.isExactlyZero();
  2017. }
  2018. static void force_sit(const LLUUID& object_id)
  2019. {
  2020. LL_DEBUGS("RestrainedLove") << "Attempting to force-sit agent on object: "
  2021. << object_id << LL_ENDL;
  2022. LLViewerObject* objectp = gObjectList.findObject(object_id);
  2023. if (!objectp)
  2024. {
  2025. LL_DEBUGS("RestrainedLove") << "Object not found !" << LL_ENDL;
  2026. return;
  2027. }
  2028. LLViewerRegion* regionp = objectp->getRegion();
  2029. if (!regionp)
  2030. {
  2031. LL_DEBUGS("RestrainedLove") << "Region not found for object."
  2032. << LL_ENDL;
  2033. return;
  2034. }
  2035. if (isAgentAvatarValid() && gAgentAvatarp->mIsSitting)
  2036. {
  2037. if (gRLInterface.mContainsUnsit)
  2038. {
  2039. // Do not allow a script to force the avatar to sit somewhere
  2040. // if already forced to stay sitting here
  2041. LL_DEBUGS("RestrainedLove") << "@unsit=n in force. Aborting."
  2042. << LL_ENDL;
  2043. return;
  2044. }
  2045. LLViewerObject* parent = (LLViewerObject*)gAgentAvatarp->getParent();
  2046. if (parent && parent->getID() == object_id)
  2047. {
  2048. // Already sitting there !
  2049. LL_DEBUGS("RestrainedLove") << "Already sitting on that object."
  2050. << LL_ENDL;
  2051. return;
  2052. }
  2053. }
  2054. if (gRLInterface.mContainsInteract || gRLInterface.contains("sit"))
  2055. {
  2056. LL_DEBUGS("RestrainedLove") << "Not permitted to force-sit."
  2057. << LL_ENDL;
  2058. return;
  2059. }
  2060. // Store our current standing location if adequate and possible
  2061. gRLInterface.storeLastStandingLoc();
  2062. LL_DEBUGS("RestrainedLove") << "Sending the sit request to the server."
  2063. << LL_ENDL;
  2064. LL_DEBUGS("AgentSit") << "RestrainedLove sending agent sit on object request"
  2065. << LL_ENDL;
  2066. LLMessageSystem* msg = gMessageSystemp;
  2067. msg->newMessageFast(_PREHASH_AgentRequestSit);
  2068. msg->nextBlockFast(_PREHASH_AgentData);
  2069. msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
  2070. msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
  2071. msg->nextBlockFast(_PREHASH_TargetObject);
  2072. msg->addUUIDFast(_PREHASH_TargetID, objectp->mID);
  2073. #if 0 // Note: for seats without a sit target, transmitting the offset
  2074. // results in a sit failure with "There is no suitable surface to sit
  2075. // on" message, while transmitting a 0 offset seems to work, as long as
  2076. // the seat is close to the avatar (8 meters away at most)...
  2077. msg->addVector3Fast(_PREHASH_Offset,
  2078. gAgent.calcFocusOffset(objectp,
  2079. gAgent.getPositionAgent(),
  2080. 0, 0));
  2081. #else
  2082. msg->addVector3Fast(_PREHASH_Offset, LLVector3::zero);
  2083. #endif
  2084. regionp->sendReliableMessage();
  2085. }
  2086. void RLInterface::backToLastStandingLoc()
  2087. {
  2088. if (!mLastStandingLocation.isExactlyZero() && !LLApp::isExiting())
  2089. {
  2090. // Verify that a TP on the agent parcel would not cause the said agent
  2091. // to either fail to TP (blocked TPs) or be TPed to a landing point.
  2092. LLParcel* parcel = gViewerParcelMgr.getAgentParcel();
  2093. if (parcel)
  2094. {
  2095. S32 type = parcel->getLandingType();
  2096. if (type == LLParcel::L_NONE ||
  2097. (type == LLParcel::L_LANDING_POINT &&
  2098. !parcel->getUserLocation().isExactlyZero()))
  2099. {
  2100. static uuid_list_t warned_parcels;
  2101. const LLUUID& parcel_id = parcel->getID();
  2102. if (warned_parcels.count(parcel_id) == 0 &&
  2103. LLViewerParcelMgr::isParcelModifiableByAgent(parcel,
  2104. GP_LAND_SET_LANDING_POINT))
  2105. {
  2106. warned_parcels.emplace(parcel_id);
  2107. gNotifications.add("RLVStandtpFailsOnRoutedParcel");
  2108. }
  2109. else
  2110. {
  2111. llwarns << "Cannot enforce @standtp on a parcel with teleport routing..."
  2112. << llendl;
  2113. }
  2114. return;
  2115. }
  2116. }
  2117. mSnappingBackToLastStandingLocation = true;
  2118. gAgent.teleportViaLocationLookAt(mLastStandingLocation);
  2119. mSnappingBackToLastStandingLocation = false;
  2120. mHandleBackToLastStanding = false;
  2121. }
  2122. }
  2123. static void force_tp_callback(U64 handle, const LLVector3& pos_region,
  2124. bool keep_lookat)
  2125. {
  2126. if (handle)
  2127. {
  2128. LLVector3d pos_global = from_region_handle(handle) +
  2129. LLVector3d(pos_region);
  2130. if (keep_lookat)
  2131. {
  2132. gAgent.teleportViaLocationLookAt(pos_global);
  2133. }
  2134. else
  2135. {
  2136. gAgent.teleportViaLocation(pos_global);
  2137. }
  2138. }
  2139. }
  2140. // Note: "location" must be X/Y/Z where X, Y and Z are ABSOLUTE coordinates =>
  2141. // use a script in-world to translate from local to global.
  2142. bool RLInterface::forceTeleport(const std::string& location, bool keep_lookat)
  2143. {
  2144. std::string region_name;
  2145. S32 x = 128;
  2146. S32 y = 128;
  2147. S32 z = 0;
  2148. std::deque<std::string> tokens = parse(location, "/");
  2149. if (tokens.size() == 3)
  2150. {
  2151. x = atoi(tokens[0].c_str());
  2152. y = atoi(tokens[1].c_str());
  2153. z = atoi(tokens[2].c_str());
  2154. }
  2155. else if (tokens.size() == 4)
  2156. {
  2157. region_name = tokens[0];
  2158. x = atoi(tokens[1].c_str());
  2159. y = atoi(tokens[2].c_str());
  2160. z = atoi(tokens[3].c_str());
  2161. }
  2162. else
  2163. {
  2164. return false;
  2165. }
  2166. LL_DEBUGS("RestrainedLove") << "Location = '" << location
  2167. << "' decoded as: " << x << "," << y << ","
  2168. << z << " - Region name: " << region_name
  2169. << LL_ENDL;
  2170. // Will be checked once receiving the tp order from the sim, then set to
  2171. // true again:
  2172. mAllowCancelTp = false;
  2173. if (region_name.empty())
  2174. {
  2175. LLVector3d pos_global((F32)x, (F32)y, (F32)z);
  2176. if (keep_lookat)
  2177. {
  2178. gAgent.teleportViaLocationLookAt(pos_global);
  2179. }
  2180. else
  2181. {
  2182. gAgent.teleportViaLocation(pos_global);
  2183. }
  2184. }
  2185. else
  2186. {
  2187. const LLVector3 pos_local((F32)x, (F32)y, (F32)z);
  2188. LLWorldMap::url_callback_t cb = boost::bind(&force_tp_callback, _1,
  2189. pos_local, keep_lookat);
  2190. gWorldMap.sendNamedRegionRequest(region_name, cb, "", true);
  2191. }
  2192. return true;
  2193. }
  2194. bool RLInterface::force(const LLUUID& obj_id, std::string command,
  2195. std::string option)
  2196. {
  2197. LL_DEBUGS("RestrainedLove") << command << " / " << option << LL_ENDL;
  2198. mLastCmdBlacklisted = false;
  2199. // Check the command against the blacklist
  2200. if (isBlacklisted(obj_id, command, option, true))
  2201. {
  2202. mLastCmdBlacklisted = true;
  2203. if (!option.empty())
  2204. {
  2205. command += ":" + option;
  2206. }
  2207. llinfos << "Blacklisted RestrainedLove command: " << command
  2208. << "=force for object " << obj_id << llendl;
  2209. return true;
  2210. }
  2211. // RLVa allows #RLV/ to be used at the start of the path in an option, so
  2212. // support it too for compatibility.
  2213. if (option.compare(0, RL_HRLVS_LENGTH, RL_RLV_REDIR_FOLDER_PREFIX) == 0)
  2214. {
  2215. // Remove #RLV/, keep the tilde.
  2216. option.erase(0, RL_HRLVS_LENGTH);
  2217. }
  2218. bool res = true;
  2219. mHandleNoStrip = true;
  2220. if (command == "sit")
  2221. { // sit:UUID
  2222. bool allowed_to_sittp = true;
  2223. if (!isAllowed(obj_id, "sittp"))
  2224. {
  2225. allowed_to_sittp = false;
  2226. remove(obj_id, "sittp", "");
  2227. }
  2228. LLUUID id(option);
  2229. force_sit(id);
  2230. mGotSit = true;
  2231. mSitUnsitDelayTimer.reset();
  2232. if (!allowed_to_sittp)
  2233. {
  2234. add(obj_id, "sittp", "");
  2235. }
  2236. }
  2237. else if (command == "sitground")
  2238. {
  2239. if (isAgentAvatarValid() &&
  2240. // Verify we are not already sat on ground...
  2241. !(gAgentAvatarp->mIsSitting && mSitTargetId.isNull()))
  2242. {
  2243. mGotSit = true;
  2244. if (gAgentAvatarp->mIsSitting)
  2245. {
  2246. mSitGroundOnStandUp = true;
  2247. gAgent.setControlFlags(AGENT_CONTROL_STAND_UP);
  2248. }
  2249. else
  2250. {
  2251. gAgent.setFlying(false);
  2252. gAgent.clearControlFlags(AGENT_CONTROL_STAND_UP);
  2253. gAgent.setControlFlags(AGENT_CONTROL_SIT_ON_GROUND);
  2254. storeLastStandingLoc(true);
  2255. }
  2256. }
  2257. }
  2258. else if (command == "unsit")
  2259. { // unsit
  2260. LL_DEBUGS("RestrainedLove") << "trying to unsit" << LL_ENDL;
  2261. if (isAgentAvatarValid() && gAgentAvatarp->mIsSitting)
  2262. {
  2263. LL_DEBUGS("RestrainedLove") << "Found sitting avatar object"
  2264. << LL_ENDL;
  2265. if (mContainsUnsit)
  2266. {
  2267. LL_DEBUGS("RestrainedLove") << "prevented from unsitting" << LL_ENDL;
  2268. }
  2269. else
  2270. {
  2271. LL_DEBUGS("RestrainedLove") << "unsitting agent" << LL_ENDL;
  2272. mGotUnsit = true;
  2273. mSitUnsitDelayTimer.reset();
  2274. LL_DEBUGS("AgentSit") << "Sending agent unsit request"
  2275. << LL_ENDL;
  2276. gAgent.setControlFlags(AGENT_CONTROL_STAND_UP);
  2277. send_agent_update(true, true);
  2278. if (mContainsStandtp)
  2279. {
  2280. backToLastStandingLoc();
  2281. }
  2282. }
  2283. }
  2284. }
  2285. else if (command == "remoutfit")
  2286. { // remoutfit or remoutfit:shoes
  2287. if (option.empty())
  2288. {
  2289. gAgentWearables.removeWearable(LLWearableType::WT_GLOVES, true, 0);
  2290. gAgentWearables.removeWearable(LLWearableType::WT_JACKET, true, 0);
  2291. gAgentWearables.removeWearable(LLWearableType::WT_PANTS, true, 0);
  2292. gAgentWearables.removeWearable(LLWearableType::WT_SHIRT, true, 0);
  2293. gAgentWearables.removeWearable(LLWearableType::WT_SHOES, true, 0);
  2294. gAgentWearables.removeWearable(LLWearableType::WT_SKIRT, true, 0);
  2295. gAgentWearables.removeWearable(LLWearableType::WT_SOCKS, true, 0);
  2296. gAgentWearables.removeWearable(LLWearableType::WT_UNDERPANTS, true,
  2297. 0);
  2298. gAgentWearables.removeWearable(LLWearableType::WT_UNDERSHIRT, true,
  2299. 0);
  2300. gAgentWearables.removeWearable(LLWearableType::WT_ALPHA, true, 0);
  2301. gAgentWearables.removeWearable(LLWearableType::WT_TATTOO, true, 0);
  2302. gAgentWearables.removeWearable(LLWearableType::WT_UNIVERSAL, true,
  2303. 0);
  2304. gAgentWearables.removeWearable(LLWearableType::WT_PHYSICS, true,
  2305. 0);
  2306. }
  2307. else
  2308. {
  2309. LLWearableType::EType type = getOutfitLayerAsType(option);
  2310. if (type != LLWearableType::WT_INVALID)
  2311. {
  2312. // clothes only, not skin, eyes, hair or shape
  2313. if (LLWearableType::getAssetType(type) ==
  2314. LLAssetType::AT_CLOTHING)
  2315. {
  2316. // Remove by layer
  2317. gAgentWearables.removeWearable(type, true, 0);
  2318. }
  2319. }
  2320. else
  2321. {
  2322. // Remove by category (in RLV share)
  2323. forceDetachByName(option, false);
  2324. }
  2325. }
  2326. }
  2327. else if (command == "detach" || command == "remattach")
  2328. {
  2329. // detach:chest=force OR detach:restraints/cuffs=force (@remattach is a
  2330. // synonym). If option is an UUID, detach the corresponding object.
  2331. if (LLUUID::validate(option))
  2332. {
  2333. res = forceDetachByUuid(option);
  2334. }
  2335. else
  2336. {
  2337. LLViewerJointAttachment* attachpt =
  2338. findAttachmentPointFromName(option, true); // Exact name
  2339. if (attachpt || option.empty())
  2340. {
  2341. res = forceDetach(option); // Remove by attach pt
  2342. }
  2343. else
  2344. {
  2345. res = forceDetachByName(option, false);
  2346. }
  2347. }
  2348. }
  2349. else if (command == "detachme")
  2350. {
  2351. // detachme=force to detach this object specifically
  2352. res = forceDetachByUuid(obj_id.asString()); // Remove by uuid
  2353. }
  2354. else if (command == "detachthis")
  2355. {
  2356. // detachthis=force to detach the folder containing this object. If
  2357. // option is an UUID, we do not detach the folder containing the
  2358. // calling object, but the referenced object instead.
  2359. std::string pathes_str;
  2360. if (LLUUID::validate(option))
  2361. {
  2362. pathes_str = getFullPath(getItem(LLUUID(option)));
  2363. }
  2364. else
  2365. {
  2366. pathes_str = getFullPath(getItem(obj_id), option);
  2367. }
  2368. std::deque<std::string> pathes = parse(pathes_str, ",");
  2369. for (U32 i = 0; i < pathes.size(); ++i)
  2370. {
  2371. res &= forceDetachByName(pathes[i], false);
  2372. }
  2373. }
  2374. else if (command == "detachall")
  2375. {
  2376. // detachall:cuffs=force to detach a folder and its subfolders
  2377. res = forceDetachByName(option, true);
  2378. }
  2379. else if (command == "detachallthis")
  2380. {
  2381. // detachallthis=force to detach the folder containing this object and
  2382. // also its subfolders. If option is an UUID, we do not detach the
  2383. // folder containing the calling object, but the referenced object
  2384. // instead.
  2385. std::string pathes_str;
  2386. if (LLUUID::validate(option))
  2387. {
  2388. pathes_str = getFullPath(getItem(LLUUID(option)));
  2389. }
  2390. else
  2391. {
  2392. pathes_str = getFullPath(getItem(obj_id), option);
  2393. }
  2394. std::deque<std::string> pathes = parse(pathes_str, ",");
  2395. for (U32 i = 0; i < pathes.size(); ++i)
  2396. {
  2397. res &= forceDetachByName(pathes[i], true);
  2398. }
  2399. }
  2400. else if (command == "tpto")
  2401. {
  2402. bool keep_lookat = false;
  2403. // tpto:[region/]X/Y/Z=force(X, Y, Z are local or global coordinates,
  2404. // depending on the presence of the region name or not)
  2405. size_t i = option.find(";");
  2406. if (i != std::string::npos && i + 1 < option.length())
  2407. {
  2408. // Strip off the "lookat" vector: we do not support it.
  2409. option = option.substr(0, i);
  2410. // Instead, pass a flag telling there was a lookat vector, and use
  2411. // that in the teleport function to keep facing in the same
  2412. // direction after TP as before it.
  2413. keep_lookat = true;
  2414. }
  2415. bool allowed_to_tploc = true;
  2416. bool allowed_to_local = true;
  2417. bool allowed_to_unsit = true;
  2418. bool allowed_to_sittp = true;
  2419. if (!isAllowed(obj_id, "tploc"))
  2420. {
  2421. allowed_to_tploc = false;
  2422. remove(obj_id, "tploc", "");
  2423. }
  2424. if (!isAllowed(obj_id, "tplocal"))
  2425. {
  2426. allowed_to_local = false;
  2427. remove(obj_id, "tplocal", "");
  2428. }
  2429. if (!isAllowed(obj_id, "unsit"))
  2430. {
  2431. allowed_to_unsit = false;
  2432. remove(obj_id, "unsit", "");
  2433. }
  2434. if (!isAllowed(obj_id, "sittp"))
  2435. {
  2436. allowed_to_sittp = false;
  2437. remove(obj_id, "sittp", "");
  2438. }
  2439. res = forceTeleport(option, keep_lookat);
  2440. if (!allowed_to_tploc)
  2441. {
  2442. add(obj_id, "tploc", "");
  2443. }
  2444. if (!allowed_to_local)
  2445. {
  2446. add(obj_id, "tplocal", "");
  2447. }
  2448. if (!allowed_to_unsit)
  2449. {
  2450. add(obj_id, "unsit", "");
  2451. }
  2452. if (!allowed_to_sittp)
  2453. {
  2454. add(obj_id, "sittp", "");
  2455. }
  2456. }
  2457. else if (command == "attach" || command == "addoutfit")
  2458. {
  2459. // attach:cuffs=force
  2460. // Will have to be changed back to AttachReplace eventually, but not
  2461. // before a clear and early communication
  2462. forceAttach(option, false, AttachOverOrReplace);
  2463. }
  2464. else if (command == "attachover" || command == "addoutfitover")
  2465. {
  2466. // attachover:cuffs=force
  2467. forceAttach(option, false, AttachOver);
  2468. }
  2469. else if (command == "attachoverorreplace" ||
  2470. command == "addoutfitoverorreplace")
  2471. {
  2472. // attachoverorreplace:cuffs=force
  2473. forceAttach(option, false, AttachOverOrReplace);
  2474. }
  2475. else if (command == "attachthis" || command == "addoutfitthis")
  2476. {
  2477. // attachthis=force to attach the folder containing this object
  2478. std::string pathes_str = getFullPath(getItem(obj_id), option);
  2479. if (!pathes_str.empty())
  2480. {
  2481. std::deque<std::string> pathes = parse(pathes_str, ",");
  2482. for (U32 i = 0; i < pathes.size(); ++i)
  2483. {
  2484. // Will have to be changed back to AttachReplace eventually,
  2485. // but not before a clear and early communication
  2486. forceAttach(pathes[i], false, AttachOverOrReplace);
  2487. }
  2488. }
  2489. }
  2490. else if (command == "attachthisover" || command == "addoutfitthisover")
  2491. {
  2492. // attachthisover=force to attach the folder containing this object
  2493. std::string pathes_str = getFullPath(getItem(obj_id), option);
  2494. if (!pathes_str.empty())
  2495. {
  2496. std::deque<std::string> pathes = parse(pathes_str, ",");
  2497. for (U32 i = 0; i < pathes.size(); ++i)
  2498. {
  2499. forceAttach(pathes[i], false, AttachOver);
  2500. }
  2501. }
  2502. }
  2503. else if (command == "attachthisoverorreplace" ||
  2504. command == "addoutfitthisoverorreplace")
  2505. {
  2506. // attachthisoverorreplace=force to attach the folder containing this
  2507. // object
  2508. std::string pathes_str = getFullPath(getItem(obj_id), option);
  2509. if (!pathes_str.empty())
  2510. {
  2511. std::deque<std::string> pathes = parse(pathes_str, ",");
  2512. for (U32 i = 0; i < pathes.size(); ++i)
  2513. {
  2514. forceAttach(pathes[i], false, AttachOverOrReplace);
  2515. }
  2516. }
  2517. }
  2518. else if (command == "attachall" || command == "addoutfitall")
  2519. {
  2520. // attachall:cuffs=force to attach a folder and its subfolders. Will
  2521. // have to be changed back to AttachReplace eventually, but not before
  2522. // a clear and early communication.
  2523. forceAttach(option, true, AttachOverOrReplace);
  2524. }
  2525. else if (command == "attachallover" || command == "addoutfitallover")
  2526. {
  2527. // attachallover:cuffs=force to attach a folder and its subfolders
  2528. forceAttach(option, true, AttachOver);
  2529. }
  2530. else if (command == "attachalloverorreplace" ||
  2531. command == "addoutfitalloverorreplace")
  2532. {
  2533. // attachalloverorreplace:cuffs=force to attach a folder and its
  2534. // subfolders
  2535. forceAttach(option, true, AttachOverOrReplace);
  2536. }
  2537. else if (command == "attachallthis" || command == "addoutfitallthis")
  2538. {
  2539. // attachallthis=force to attach the folder containing this object and
  2540. // its subfolders
  2541. std::string pathes_str = getFullPath(getItem(obj_id), option);
  2542. if (!pathes_str.empty())
  2543. {
  2544. std::deque<std::string> pathes = parse(pathes_str, ",");
  2545. for (U32 i = 0; i < pathes.size(); ++i)
  2546. {
  2547. // Will have to be changed back to AttachReplace eventually,
  2548. // but not before a clear and early communication
  2549. forceAttach(pathes[i], true, AttachOverOrReplace);
  2550. }
  2551. }
  2552. }
  2553. else if (command == "attachallthisover" ||
  2554. command == "addoutfitallthisover")
  2555. {
  2556. // attachallthisover=force to attach the folder containing this object
  2557. // and its subfolders
  2558. std::string pathes_str = getFullPath(getItem(obj_id), option);
  2559. if (!pathes_str.empty())
  2560. {
  2561. std::deque<std::string> pathes = parse(pathes_str, ",");
  2562. for (U32 i = 0; i < pathes.size(); ++i)
  2563. {
  2564. forceAttach(pathes[i], true, AttachOver);
  2565. }
  2566. }
  2567. }
  2568. else if (command == "attachallthisoverorreplace" ||
  2569. command == "addoutfitallthisoverorreplace")
  2570. {
  2571. // attachallthisoverorreplace=force to attach the folder containing
  2572. // this object and its subfolders
  2573. std::string pathes_str = getFullPath(getItem(obj_id), option);
  2574. if (!pathes_str.empty())
  2575. {
  2576. std::deque<std::string> pathes = parse(pathes_str, ",");
  2577. for (U32 i = 0; i < pathes.size(); ++i)
  2578. {
  2579. forceAttach(pathes[i], true, AttachOverOrReplace);
  2580. }
  2581. }
  2582. }
  2583. else if (command.compare(0, 7, "setenv_") == 0)
  2584. {
  2585. bool allowed = true;
  2586. if (!isAllowed(obj_id, "setenv"))
  2587. {
  2588. allowed = false;
  2589. remove(obj_id, "setenv", "");
  2590. }
  2591. if (!mContainsSetenv)
  2592. {
  2593. res = forceEnvironment(command, option);
  2594. }
  2595. if (!allowed)
  2596. {
  2597. add(obj_id, "setenv", "");
  2598. }
  2599. }
  2600. else if (command.compare(0, 9, "setdebug_") == 0)
  2601. {
  2602. bool allowed = true;
  2603. if (!isAllowed(obj_id, "setdebug"))
  2604. {
  2605. allowed = false;
  2606. remove(obj_id, "setdebug", "");
  2607. }
  2608. if (!contains("setdebug"))
  2609. {
  2610. res = forceDebugSetting(command, option);
  2611. }
  2612. if (!allowed)
  2613. {
  2614. add(obj_id, "setdebug", "");
  2615. }
  2616. }
  2617. else if (command == "setrot")
  2618. {
  2619. // setrot:angle_radians=force
  2620. F32 val = atof(option.c_str());
  2621. gAgent.startCameraAnimation();
  2622. LLVector3 rot(0.f, 1.f, 0.f);
  2623. rot = rot.rotVec(-val, LLVector3::z_axis);
  2624. rot.normalize();
  2625. gAgent.resetAxes(rot);
  2626. }
  2627. else if (command == "adjustheight")
  2628. {
  2629. // adjustheight:adjustment_centimeters=force or
  2630. // adjustheight:ref_pelvis_to_foot;scalar[;delta]=force
  2631. if (isAgentAvatarValid())
  2632. {
  2633. F32 val = (F32)atoi(option.c_str()) / 100.f;
  2634. size_t i = option.find(';');
  2635. if (i != std::string::npos && i + 1 < option.length())
  2636. {
  2637. F32 scalar = (F32)atof(option.substr(i + 1).c_str());
  2638. if (scalar != 0.f)
  2639. {
  2640. LL_DEBUGS("RestrainedLove") << "Pelvis to foot = "
  2641. << gAgentAvatarp->getPelvisToFoot()
  2642. << "m" << LL_ENDL;
  2643. val = (atof(option.c_str()) -
  2644. gAgentAvatarp->getPelvisToFoot()) * scalar;
  2645. option = option.substr(i + 1);
  2646. i = option.find(';');
  2647. if (i != std::string::npos && i + 1 < option.length())
  2648. {
  2649. val += (F32)atof(option.substr(i + 1).c_str());
  2650. }
  2651. }
  2652. }
  2653. if (!LLVOAvatarSelf::canUseServerBaking() ||
  2654. LLVOAvatarSelf::useAvatarHoverHeight())
  2655. {
  2656. gSavedSettings.setF32("AvatarOffsetZ", val);
  2657. }
  2658. }
  2659. }
  2660. else if (command == "setgroup")
  2661. {
  2662. std::string target_group_name = option;
  2663. LLStringUtil::toLower(target_group_name);
  2664. // Note: "none" is not localized here because a script should not have
  2665. // to bother about viewer language
  2666. if (target_group_name == "none")
  2667. {
  2668. gAgent.setGroup(LLUUID::null);
  2669. }
  2670. else
  2671. {
  2672. std::string name;
  2673. for (S32 i = 0, count = gAgent.mGroups.size(); i < count; ++i)
  2674. {
  2675. const LLGroupData& gdatap = gAgent.mGroups[i];
  2676. name = gdatap.mName;
  2677. LLStringUtil::toLower(name);
  2678. if (name == target_group_name)
  2679. {
  2680. gAgent.setGroup(gdatap.mID);
  2681. break;
  2682. }
  2683. }
  2684. }
  2685. }
  2686. else if (command == "setcam_fov")
  2687. {
  2688. F32 new_fov_rad = atof(option.c_str());
  2689. gViewerCamera.setDefaultFOV(new_fov_rad);
  2690. // setView() may have clamped it:
  2691. gSavedSettings.setF32("CameraAngle", gViewerCamera.getView());
  2692. }
  2693. else
  2694. {
  2695. // Unknown command
  2696. res = false;
  2697. }
  2698. mHandleNoStrip = false;
  2699. return res;
  2700. }
  2701. void RLInterface::removeWearableItemFromAvatar(LLViewerInventoryItem* item_or_link)
  2702. {
  2703. if (!item_or_link)
  2704. {
  2705. return;
  2706. }
  2707. LLViewerInventoryItem* item = item_or_link;
  2708. if (LLViewerInventoryItem* linked_item = item_or_link->getLinkedItem())
  2709. {
  2710. item = linked_item;
  2711. }
  2712. if (item->getInventoryType() != LLInventoryType::IT_WEARABLE ||
  2713. !canUnwear(item))
  2714. {
  2715. return;
  2716. }
  2717. LLViewerWearable* wearable;
  2718. wearable = gAgentWearables.getWearableFromItemID(item->getUUID());
  2719. if (!wearable)
  2720. {
  2721. return;
  2722. }
  2723. LLWearableType::EType type = wearable->getType();
  2724. U32 index;
  2725. if (gAgentWearables.getWearableIndex(wearable, index))
  2726. {
  2727. gAgentWearables.removeWearable(type, false, index);
  2728. }
  2729. }
  2730. bool RLInterface::answerOnChat(const LLUUID& obj_id,
  2731. const std::string& channel, std::string msg)
  2732. {
  2733. S32 chan = (S32)atoi(channel.c_str());
  2734. if (chan == 0)
  2735. {
  2736. // Protection against abusive "@getstatus=0" commands, or against a
  2737. // non-numerical channel
  2738. return false;
  2739. }
  2740. if (msg.length() > (size_t)(chan > 0 ? 1023 : 254))
  2741. {
  2742. llwarns << "Too large an answer: maximum is "
  2743. << (chan > 0 ? "1023 characters"
  2744. : "254 characters for a negative channel")
  2745. << ". Truncated reply." << llendl;
  2746. msg = msg.substr(0, (size_t)(chan > 0 ? 1022 : 254));
  2747. }
  2748. LLMessageSystem* msgsys = gMessageSystemp;
  2749. if (chan > 0)
  2750. {
  2751. msgsys->newMessageFast(_PREHASH_ChatFromViewer);
  2752. msgsys->nextBlockFast(_PREHASH_AgentData);
  2753. msgsys->addUUIDFast(_PREHASH_AgentID, gAgentID);
  2754. msgsys->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
  2755. msgsys->nextBlockFast(_PREHASH_ChatData);
  2756. msgsys->addStringFast(_PREHASH_Message, msg);
  2757. msgsys->addU8Fast(_PREHASH_Type, CHAT_TYPE_SHOUT);
  2758. msgsys->addS32(_PREHASH_Channel, chan);
  2759. }
  2760. else
  2761. {
  2762. msgsys->newMessage(_PREHASH_ScriptDialogReply);
  2763. msgsys->nextBlock(_PREHASH_AgentData);
  2764. msgsys->addUUID(_PREHASH_AgentID, gAgentID);
  2765. msgsys->addUUID(_PREHASH_SessionID, gAgentSessionID);
  2766. msgsys->nextBlock(_PREHASH_Data);
  2767. msgsys->addUUID(_PREHASH_ObjectID, gAgentID);
  2768. msgsys->addS32(_PREHASH_ChatChannel, chan);
  2769. msgsys->addS32(_PREHASH_ButtonIndex, 1);
  2770. msgsys->addString(_PREHASH_ButtonLabel, msg);
  2771. }
  2772. gAgent.sendReliableMessage();
  2773. if (gAutomationp)
  2774. {
  2775. gAutomationp->onRLVAnswerOnChat(obj_id, chan, msg);
  2776. }
  2777. LL_DEBUGS("RestrainedLove") << "/" << chan << " " << msg << LL_ENDL;
  2778. return true;
  2779. }
  2780. std::string RLInterface::crunchEmote(const std::string& msg, U32 truncate_to)
  2781. {
  2782. if (msg.empty())
  2783. {
  2784. return LLStringUtil::null;
  2785. }
  2786. std::string crunched = msg;
  2787. if (msg.compare(0, 4, "/me ") == 0 || msg.compare(0, 4, "/me'") == 0)
  2788. {
  2789. // Only allow emotes without "spoken" text.
  2790. // Forbid text containing any symbol which could be used as quotes.
  2791. if (msg.find('"') != std::string::npos ||
  2792. msg.find("''") != std::string::npos ||
  2793. msg.find('(') != std::string::npos ||
  2794. msg.find(')') != std::string::npos ||
  2795. msg.find(" -") != std::string::npos ||
  2796. msg.find("- ") != std::string::npos ||
  2797. msg.find('*') != std::string::npos ||
  2798. msg.find('=') != std::string::npos ||
  2799. msg.find('^') != std::string::npos ||
  2800. msg.find('_') != std::string::npos ||
  2801. msg.find('~') != std::string::npos)
  2802. {
  2803. crunched = "...";
  2804. }
  2805. else if (truncate_to > 0 && !sUntruncatedEmotes && !contains("emote"))
  2806. {
  2807. // Only allow short emotes.
  2808. size_t i = msg.find('.');
  2809. if (i != std::string::npos)
  2810. {
  2811. crunched = msg.substr(0, ++i);
  2812. }
  2813. if (crunched.length() > truncate_to)
  2814. {
  2815. crunched = crunched.substr(0, truncate_to);
  2816. }
  2817. }
  2818. }
  2819. else if (msg[0] == '/')
  2820. {
  2821. // Only allow short gesture names(to avoid cheats).
  2822. if (msg.length() > 7)
  2823. { // allows things like "/ao off", "/hug X"
  2824. crunched = "...";
  2825. }
  2826. }
  2827. else if (!sCanOoc || msg.compare(0, 2, "((") != 0 ||
  2828. msg.find("))") != msg.length() - 2)
  2829. {
  2830. // Only allow OOC chat, starting with "((" and ending with "))".
  2831. crunched = "...";
  2832. }
  2833. return crunched;
  2834. }
  2835. std::string RLInterface::getOutfitLayerAsString(LLWearableType::EType layer)
  2836. {
  2837. switch (layer)
  2838. {
  2839. case LLWearableType::WT_SKIN:
  2840. return WS_SKIN;
  2841. case LLWearableType::WT_GLOVES:
  2842. return WS_GLOVES;
  2843. case LLWearableType::WT_JACKET:
  2844. return WS_JACKET;
  2845. case LLWearableType::WT_PANTS:
  2846. return WS_PANTS;
  2847. case LLWearableType::WT_SHIRT:
  2848. return WS_SHIRT;
  2849. case LLWearableType::WT_SHOES:
  2850. return WS_SHOES;
  2851. case LLWearableType::WT_SKIRT:
  2852. return WS_SKIRT;
  2853. case LLWearableType::WT_SOCKS:
  2854. return WS_SOCKS;
  2855. case LLWearableType::WT_UNDERPANTS:
  2856. return WS_UNDERPANTS;
  2857. case LLWearableType::WT_UNDERSHIRT:
  2858. return WS_UNDERSHIRT;
  2859. case LLWearableType::WT_ALPHA:
  2860. return WS_ALPHA;
  2861. case LLWearableType::WT_TATTOO:
  2862. return WS_TATTOO;
  2863. case LLWearableType::WT_UNIVERSAL:
  2864. return WS_UNIVERSAL;
  2865. case LLWearableType::WT_PHYSICS:
  2866. return WS_PHYSICS;
  2867. case LLWearableType::WT_EYES:
  2868. return WS_EYES;
  2869. case LLWearableType::WT_HAIR:
  2870. return WS_HAIR;
  2871. case LLWearableType::WT_SHAPE:
  2872. return WS_SHAPE;
  2873. default:
  2874. return "";
  2875. }
  2876. }
  2877. LLWearableType::EType RLInterface::getOutfitLayerAsType(const std::string& layer)
  2878. {
  2879. if (layer == WS_SKIN) return LLWearableType::WT_SKIN;
  2880. if (layer == WS_GLOVES) return LLWearableType::WT_GLOVES;
  2881. if (layer == WS_JACKET) return LLWearableType::WT_JACKET;
  2882. if (layer == WS_PANTS) return LLWearableType::WT_PANTS;
  2883. if (layer == WS_SHIRT) return LLWearableType::WT_SHIRT;
  2884. if (layer == WS_SHOES) return LLWearableType::WT_SHOES;
  2885. if (layer == WS_SKIRT) return LLWearableType::WT_SKIRT;
  2886. if (layer == WS_SOCKS) return LLWearableType::WT_SOCKS;
  2887. if (layer == WS_UNDERPANTS) return LLWearableType::WT_UNDERPANTS;
  2888. if (layer == WS_UNDERSHIRT) return LLWearableType::WT_UNDERSHIRT;
  2889. if (layer == WS_ALPHA) return LLWearableType::WT_ALPHA;
  2890. if (layer == WS_TATTOO) return LLWearableType::WT_TATTOO;
  2891. if (layer == WS_UNIVERSAL) return LLWearableType::WT_UNIVERSAL;
  2892. if (layer == WS_PHYSICS) return LLWearableType::WT_PHYSICS;
  2893. if (layer == WS_EYES) return LLWearableType::WT_EYES;
  2894. if (layer == WS_HAIR) return LLWearableType::WT_HAIR;
  2895. if (layer == WS_SHAPE) return LLWearableType::WT_SHAPE;
  2896. return LLWearableType::WT_INVALID;
  2897. }
  2898. std::string RLInterface::getOutfit(const std::string& layer)
  2899. {
  2900. if (layer == WS_SKIN) return (gAgentWearables.getWearable(LLWearableType::WT_SKIN, 0) ? "1" : "0");
  2901. if (layer == WS_GLOVES) return (gAgentWearables.getWearable(LLWearableType::WT_GLOVES, 0) ? "1" : "0");
  2902. if (layer == WS_JACKET) return (gAgentWearables.getWearable(LLWearableType::WT_JACKET, 0) ? "1" : "0");
  2903. if (layer == WS_PANTS) return (gAgentWearables.getWearable(LLWearableType::WT_PANTS, 0) ? "1" : "0");
  2904. if (layer == WS_SHIRT) return (gAgentWearables.getWearable(LLWearableType::WT_SHIRT, 0) ? "1" : "0");
  2905. if (layer == WS_SHOES) return (gAgentWearables.getWearable(LLWearableType::WT_SHOES, 0) ? "1" : "0");
  2906. if (layer == WS_SKIRT) return (gAgentWearables.getWearable(LLWearableType::WT_SKIRT, 0) ? "1" : "0");
  2907. if (layer == WS_SOCKS) return (gAgentWearables.getWearable(LLWearableType::WT_SOCKS, 0) ? "1" : "0");
  2908. if (layer == WS_UNDERPANTS) return (gAgentWearables.getWearable(LLWearableType::WT_UNDERPANTS, 0) ? "1" : "0");
  2909. if (layer == WS_UNDERSHIRT) return (gAgentWearables.getWearable(LLWearableType::WT_UNDERSHIRT, 0) ? "1" : "0");
  2910. if (layer == WS_ALPHA) return (gAgentWearables.getWearable(LLWearableType::WT_ALPHA, 0) ? "1" : "0");
  2911. if (layer == WS_TATTOO) return (gAgentWearables.getWearable(LLWearableType::WT_TATTOO, 0) ? "1" : "0");
  2912. if (layer == WS_UNIVERSAL) return (gAgentWearables.getWearable(LLWearableType::WT_UNIVERSAL, 0) ? "1" : "0");
  2913. if (layer == WS_PHYSICS) return (gAgentWearables.getWearable(LLWearableType::WT_PHYSICS, 0) ? "1" : "0");
  2914. if (layer == WS_EYES) return (gAgentWearables.getWearable(LLWearableType::WT_EYES, 0) ? "1" : "0");
  2915. if (layer == WS_HAIR) return (gAgentWearables.getWearable(LLWearableType::WT_HAIR, 0) ? "1" : "0");
  2916. if (layer == WS_SHAPE) return (gAgentWearables.getWearable(LLWearableType::WT_SHAPE, 0) ? "1" : "0");
  2917. return getOutfit(WS_GLOVES) + getOutfit(WS_JACKET) + getOutfit(WS_PANTS) +
  2918. getOutfit(WS_SHIRT) + getOutfit(WS_SHOES) + getOutfit(WS_SKIRT) +
  2919. getOutfit(WS_SOCKS) + getOutfit(WS_UNDERPANTS) + getOutfit(WS_UNDERSHIRT) +
  2920. getOutfit(WS_SKIN) + getOutfit(WS_EYES) + getOutfit(WS_HAIR) +
  2921. getOutfit(WS_SHAPE) + getOutfit(WS_ALPHA) + getOutfit(WS_TATTOO) +
  2922. getOutfit(WS_PHYSICS) + getOutfit(WS_UNIVERSAL);
  2923. }
  2924. std::string RLInterface::getAttachments(const std::string& attachpt)
  2925. {
  2926. std::string res, name;
  2927. if (!isAgentAvatarValid())
  2928. {
  2929. llwarns << "NULL avatar pointer. Aborting." << llendl;
  2930. return res;
  2931. }
  2932. if (attachpt.empty())
  2933. {
  2934. res += "0"; // to match the LSL macros
  2935. }
  2936. for (LLVOAvatar::attachment_map_t::iterator
  2937. iter = gAgentAvatarp->mAttachmentPoints.begin(),
  2938. end = gAgentAvatarp->mAttachmentPoints.end();
  2939. iter != end; ++iter)
  2940. {
  2941. LLViewerJointAttachment* attachment = iter->second;
  2942. name = attachment->getName();
  2943. if (name == "Avatar Center")
  2944. {
  2945. name = "Root";
  2946. }
  2947. LLStringUtil::toLower(name);
  2948. LL_DEBUGS("RestrainedLove") << "trying <" << name << ">" << LL_ENDL;
  2949. if (attachpt.empty() || attachpt == name)
  2950. {
  2951. if (attachment->getNumObjects() > 0)
  2952. {
  2953. res += "1"; // attachment->getName();
  2954. }
  2955. else
  2956. {
  2957. res += "0";
  2958. }
  2959. }
  2960. }
  2961. return res;
  2962. }
  2963. std::string RLInterface::getStatus(const LLUUID& obj_id, std::string rule)
  2964. {
  2965. std::string res, name;
  2966. std::string separator = "/";
  2967. // If rule contains a specification of the separator, extract it
  2968. size_t ind = rule.find(";");
  2969. if (ind != std::string::npos)
  2970. {
  2971. separator = rule.substr(ind + 1);
  2972. rule = rule.substr(0, ind);
  2973. }
  2974. if (separator.empty())
  2975. {
  2976. // Prevent a hack to force the avatar to say something
  2977. separator = "/";
  2978. }
  2979. rl_map_it_t it;
  2980. if (obj_id.isNull())
  2981. {
  2982. it = mSpecialObjectBehaviours.begin();
  2983. }
  2984. else
  2985. {
  2986. it = mSpecialObjectBehaviours.find(obj_id.asString());
  2987. }
  2988. while (it != mSpecialObjectBehaviours.end() &&
  2989. (obj_id.isNull() ||
  2990. it != mSpecialObjectBehaviours.upper_bound(obj_id.asString())))
  2991. {
  2992. if (rule.empty() || it->second.find(rule) != std::string::npos)
  2993. {
  2994. res += separator;
  2995. res += it->second;
  2996. }
  2997. ++it;
  2998. }
  2999. return res;
  3000. }
  3001. std::string RLInterface::getCommand(std::string match, bool blacklist)
  3002. {
  3003. std::string res, command, name, temp;
  3004. LLStringUtil::toLower(match);
  3005. for (rl_command_map_it_t it = sCommandsMap.begin(),
  3006. end = sCommandsMap.end();
  3007. it != end; ++it)
  3008. {
  3009. command = it->first;
  3010. size_t i = command.find("%f");
  3011. bool force = i != std::string::npos;
  3012. name = force ? command.substr(0, i) : command;
  3013. temp = res + "/";
  3014. if (match.empty() || command.find(match) != std::string::npos)
  3015. {
  3016. if (temp.find("/" + command + "/") == std::string::npos &&
  3017. (blacklist || !isBlacklisted(LLUUID::null, name, "", force)))
  3018. {
  3019. res += "/" + command;
  3020. }
  3021. }
  3022. }
  3023. return res;
  3024. }
  3025. std::string RLInterface::getCommandsByType(S32 type, bool blacklist)
  3026. {
  3027. std::string res, command, name, temp;
  3028. for (rl_command_map_it_t it = sCommandsMap.begin(),
  3029. end = sCommandsMap.end();
  3030. it != end; ++it)
  3031. {
  3032. S32 cmdtype = (S32)it->second;
  3033. if (cmdtype == type)
  3034. {
  3035. command = it->first;
  3036. size_t i = command.find("%f");
  3037. bool force = i != std::string::npos;
  3038. name = force ? command.substr(0, i) : command;
  3039. temp = res + "/";
  3040. if (temp.find("/" + command + "/") == std::string::npos &&
  3041. (blacklist || !isBlacklisted(LLUUID::null, name, "", force)))
  3042. {
  3043. res += "/" + command;
  3044. }
  3045. }
  3046. }
  3047. return res;
  3048. }
  3049. std::deque<std::string> RLInterface::getBlacklist(std::string filter)
  3050. {
  3051. std::deque<std::string> list, res;
  3052. list = parse(sBlackList, ",");
  3053. res.clear();
  3054. size_t size = list.size();
  3055. for (size_t i = 0; i < size; ++i)
  3056. {
  3057. if (filter.empty() || list[i].find(filter) != std::string::npos)
  3058. {
  3059. res.emplace_back(list[i]);
  3060. }
  3061. }
  3062. return res;
  3063. }
  3064. std::string RLInterface::getRlvRestrictions(const std::string& filter)
  3065. {
  3066. LLUUID id;
  3067. std::string res = "\n################ RLV RESTRICTIONS ################";
  3068. std::string object_name, old_object_name;
  3069. for (rl_map_it_t it = mSpecialObjectBehaviours.begin(),
  3070. end = mSpecialObjectBehaviours.end();
  3071. it != end; ++it)
  3072. {
  3073. id.set(it->first);
  3074. LLInventoryItem* item = getItem(id);
  3075. if (item)
  3076. {
  3077. object_name = item->getName();
  3078. }
  3079. if (filter.empty() || object_name.find(filter) != std::string::npos)
  3080. {
  3081. if (object_name.empty())
  3082. {
  3083. object_name = id.asString();
  3084. }
  3085. // print the name of the object
  3086. if (object_name != old_object_name)
  3087. {
  3088. res += "\nObject: " + object_name;
  3089. }
  3090. res += "\n - " + it->second;
  3091. }
  3092. old_object_name = object_name;
  3093. object_name.clear();
  3094. }
  3095. return res + "\n##################################################";
  3096. }
  3097. bool RLInterface::forceDetach(const std::string& attachpt)
  3098. {
  3099. bool res = false;
  3100. if (!isAgentAvatarValid()) return res;
  3101. std::string name;
  3102. for (LLVOAvatar::attachment_map_t::iterator
  3103. iter = gAgentAvatarp->mAttachmentPoints.begin(),
  3104. end = gAgentAvatarp->mAttachmentPoints.end();
  3105. iter != end; ++iter)
  3106. {
  3107. LLViewerJointAttachment* attachment = iter->second;
  3108. if (!attachment) continue; // Paranoia
  3109. name = attachment->getName();
  3110. if (name == "Avatar Center")
  3111. {
  3112. name = "Root";
  3113. }
  3114. LLStringUtil::toLower(name);
  3115. LL_DEBUGS("RestrainedLove") << "trying <" << name << ">" << LL_ENDL;
  3116. if (attachpt.empty() || attachpt == name)
  3117. {
  3118. LL_DEBUGS("RestrainedLove") << "found => detaching" << LL_ENDL;
  3119. detachAllObjectsFromAttachment(attachment);
  3120. res = true;
  3121. }
  3122. }
  3123. return res;
  3124. }
  3125. bool RLInterface::forceDetachByUuid(const std::string& object_id)
  3126. {
  3127. bool res = false;
  3128. if (!isAgentAvatarValid()) return res;
  3129. LLViewerObject* object = gObjectList.findObject(LLUUID(object_id));
  3130. if (object)
  3131. {
  3132. object = object->getRootEdit();
  3133. for (LLVOAvatar::attachment_map_t::iterator
  3134. iter = gAgentAvatarp->mAttachmentPoints.begin(),
  3135. end = gAgentAvatarp->mAttachmentPoints.end();
  3136. iter != end; ++iter)
  3137. {
  3138. LLViewerJointAttachment* attachment = iter->second;
  3139. if (attachment && attachment->isObjectAttached(object))
  3140. {
  3141. detachObject(object);
  3142. res = true;
  3143. }
  3144. }
  3145. }
  3146. return res;
  3147. }
  3148. bool RLInterface::hasLockedHuds()
  3149. {
  3150. if (!isAgentAvatarValid()) return false;
  3151. for (S32 i = 0, count = gAgentAvatarp->mAttachedObjectsVector.size();
  3152. i < count; ++i)
  3153. {
  3154. LLViewerObject* objp = gAgentAvatarp->mAttachedObjectsVector[i].first;
  3155. if (objp && objp->isHUDAttachment() && !canDetach(objp))
  3156. {
  3157. return true;
  3158. }
  3159. }
  3160. return false;
  3161. }
  3162. std::deque<LLInventoryItem*> RLInterface::getListOfLockedItems(LLInventoryCategory* root)
  3163. {
  3164. std::deque<LLInventoryItem*> res;
  3165. std::deque<LLInventoryItem*> tmp;
  3166. if (root && isAgentAvatarValid())
  3167. {
  3168. LLInventoryModel::cat_array_t* cats;
  3169. LLInventoryModel::item_array_t* items;
  3170. gInventory.getDirectDescendentsOf(root->getUUID(), cats, items);
  3171. // Try to find locked items in the current category
  3172. std::string attach_point_name;
  3173. for (S32 i = 0, count = items->size(); i < count; ++i)
  3174. {
  3175. LLInventoryItem* item = (*items)[i];
  3176. // If this is an object, add it if it is worn and locked, or worn
  3177. // and its attach point is locked
  3178. if (item && item->getType() == LLAssetType::AT_OBJECT)
  3179. {
  3180. LLViewerObject* attached_object;
  3181. attached_object = gAgentAvatarp->getWornAttachment(item->getUUID());
  3182. if (attached_object)
  3183. {
  3184. attach_point_name = gAgentAvatarp->getAttachedPointName(item->getLinkedUUID());
  3185. if (!canDetach(attached_object))
  3186. {
  3187. LL_DEBUGS("RestrainedLove") << "Found a locked object: "
  3188. << item->getName()
  3189. << " on "
  3190. << attach_point_name
  3191. << LL_ENDL;
  3192. res.push_back(item);
  3193. }
  3194. }
  3195. }
  3196. // If this is a piece of clothing, add it if the avatar cannot
  3197. // unwear clothes, or if this layer itself cannot be unworn
  3198. else if (item && item->getType() == LLAssetType::AT_CLOTHING)
  3199. {
  3200. if (contains("remoutfit") || containsSubstr("remoutfit:"))
  3201. {
  3202. LL_DEBUGS("RestrainedLove") << "Found a locked clothing: "
  3203. << item->getName() << LL_ENDL;
  3204. res.push_back(item);
  3205. }
  3206. }
  3207. }
  3208. // We have all the locked objects contained directly in this folder,
  3209. // now add all the ones contained in children folders recursively
  3210. for (S32 i = 0, count = cats->size(); i < count; ++i)
  3211. {
  3212. LLInventoryCategory* cat = (*cats)[i];
  3213. tmp = getListOfLockedItems(cat);
  3214. for (S32 j = 0, count2 = tmp.size(); j < count2; ++j)
  3215. {
  3216. LLInventoryItem* item = tmp[j];
  3217. if (item)
  3218. {
  3219. res.push_back(item);
  3220. }
  3221. }
  3222. }
  3223. LL_DEBUGS("RestrainedLove") << "Number of locked objects under "
  3224. << root->getName() << " = " << res.size()
  3225. << LL_ENDL;
  3226. }
  3227. return res;
  3228. }
  3229. std::deque<std::string> RLInterface::getListOfRestrictions(const LLUUID& obj_id,
  3230. const std::string& rule)
  3231. {
  3232. std::deque<std::string> res;
  3233. std::string name;
  3234. rl_map_it_t it;
  3235. if (obj_id.isNull())
  3236. {
  3237. it = mSpecialObjectBehaviours.begin();
  3238. }
  3239. else
  3240. {
  3241. it = mSpecialObjectBehaviours.find(obj_id.asString());
  3242. }
  3243. while (it != mSpecialObjectBehaviours.end() &&
  3244. (obj_id.isNull() ||
  3245. it != mSpecialObjectBehaviours.upper_bound(obj_id.asString())))
  3246. {
  3247. if (rule.empty() || it->second.find(rule) != std::string::npos)
  3248. {
  3249. res.emplace_back(it->second);
  3250. }
  3251. ++it;
  3252. }
  3253. return res;
  3254. }
  3255. std::string RLInterface::getInventoryList(const std::string& path,
  3256. bool with_worn_info)
  3257. {
  3258. std::string res;
  3259. LLInventoryModel::cat_array_t* cats;
  3260. LLInventoryModel::item_array_t* items;
  3261. LLInventoryCategory* root = NULL;
  3262. if (path.empty())
  3263. {
  3264. root = getRlvShare();
  3265. }
  3266. else
  3267. {
  3268. root = getCategoryUnderRlvShare(path);
  3269. }
  3270. if (root)
  3271. {
  3272. gInventory.getDirectDescendentsOf(root->getUUID(), cats, items);
  3273. if (cats)
  3274. {
  3275. bool found_one = false;
  3276. if (with_worn_info)
  3277. {
  3278. std::string worn_items = getWornItems(root);
  3279. res += "|";
  3280. found_one = true;
  3281. if (worn_items == "n")
  3282. {
  3283. res += "10";
  3284. }
  3285. else if (worn_items == "N")
  3286. {
  3287. res += "30";
  3288. }
  3289. else
  3290. {
  3291. res += worn_items;
  3292. }
  3293. }
  3294. for (S32 i = 0, count = cats->size(); i < count; ++i)
  3295. {
  3296. LLInventoryCategory* cat = (*cats)[i];
  3297. const std::string& name = cat->getName();
  3298. if (!name.empty() && name[0] != '.' &&
  3299. (!mHandleNoRelay ||
  3300. name.find(RL_NORELAY_FOLDER_TAG) == std::string::npos))
  3301. { // hidden folders => invisible to the list
  3302. if (found_one)
  3303. {
  3304. res += ",";
  3305. }
  3306. res += name.c_str();
  3307. if (with_worn_info)
  3308. {
  3309. std::string worn_items = getWornItems(cat);
  3310. res += "|";
  3311. found_one = true;
  3312. if (worn_items == "n")
  3313. {
  3314. res += "10";
  3315. }
  3316. else if (worn_items == "N")
  3317. {
  3318. res += "30";
  3319. }
  3320. else
  3321. {
  3322. res += worn_items;
  3323. }
  3324. }
  3325. found_one = true;
  3326. }
  3327. }
  3328. }
  3329. }
  3330. return res;
  3331. }
  3332. std::string RLInterface::getWornItems(LLInventoryCategory* cat)
  3333. {
  3334. // Returns a string of 2 digits according to the proportion of worn items
  3335. // in this folder and its children:
  3336. // First digit is this folder, second digit is children folders
  3337. // 0 : No item contained in the folder
  3338. // 1 : Some items contained but none is worn
  3339. // 2 : Some items contained and some of them are worn
  3340. // 3 : Some items contained and all of them are worn
  3341. S32 res = 0;
  3342. S32 sub_res = 0;
  3343. S32 prev_sub_res = 0;
  3344. S32 nb_items = 0;
  3345. S32 nb_worn = 0;
  3346. bool no_mod = false;
  3347. bool is_rlv_root = getRlvShare() == cat;
  3348. // if cat exists, scan all the items inside it
  3349. if (cat)
  3350. {
  3351. LLInventoryModel::cat_array_t* cats;
  3352. LLInventoryModel::item_array_t* items;
  3353. // Retrieve all the objects contained in this folder
  3354. gInventory.getDirectDescendentsOf(cat->getUUID(), cats, items);
  3355. if (!is_rlv_root && items) // Do not scan the shared root
  3356. {
  3357. // Scan them one by one
  3358. LLViewerInventoryItem* item;
  3359. for (S32 i = 0, count = items->size(); i < count; ++i)
  3360. {
  3361. item = (LLViewerInventoryItem*)(*items)[i];
  3362. if (item)
  3363. {
  3364. if (item->getType() == LLAssetType::AT_OBJECT ||
  3365. item->getType() == LLAssetType::AT_CLOTHING ||
  3366. item->getType() == LLAssetType::AT_BODYPART)
  3367. {
  3368. ++nb_items;
  3369. }
  3370. if (gAgentWearables.isWearingItem(item->getUUID()) ||
  3371. (isAgentAvatarValid() &&
  3372. gAgentAvatarp->isWearingAttachment(item->getUUID())))
  3373. {
  3374. ++nb_worn;
  3375. }
  3376. // Special case: this item is no-mod, hence we need to check
  3377. // its parent folder is correctly named, and that the item
  3378. // is alone in its folder. If so, then the calling method
  3379. // will have to deal with a special character instead of a
  3380. // number
  3381. if (count == 1 && item->getType() == LLAssetType::AT_OBJECT &&
  3382. !item->getPermissions().allowModifyBy(gAgentID))
  3383. {
  3384. if (findAttachmentPointFromName(cat->getName()))
  3385. {
  3386. no_mod = true;
  3387. }
  3388. }
  3389. }
  3390. }
  3391. }
  3392. // Scan every subfolder of the folder we are scanning, recursively.
  3393. // Note: in the case of no-mod items we should not have sub-folders,
  3394. // so there is no need to check.
  3395. if (cats && !no_mod)
  3396. {
  3397. for (S32 i = 0, count = cats->size(); i < count; ++i)
  3398. {
  3399. LLViewerInventoryCategory* childp =
  3400. (LLViewerInventoryCategory*)(*cats)[i];
  3401. if (childp)
  3402. {
  3403. std::string tmp = getWornItems(childp);
  3404. // Translate the result for no-mod items into something the
  3405. // upper levels can understand
  3406. if (tmp == "N")
  3407. {
  3408. if (!is_rlv_root)
  3409. {
  3410. ++nb_worn;
  3411. ++nb_items;
  3412. sub_res = 3;
  3413. }
  3414. }
  3415. else if (tmp == "n")
  3416. {
  3417. if (!is_rlv_root)
  3418. {
  3419. ++nb_items;
  3420. sub_res = 1;
  3421. }
  3422. }
  3423. else if (!childp->getName().empty() &&
  3424. // We do not want to include invisible folders,
  3425. // except the ones containing a no-mod item
  3426. childp->getName()[0] != '.')
  3427. {
  3428. // This is an actual sub-folder with several items and
  3429. // sub-folders inside, so retain its score to include
  3430. // it into the current one. As it is a sub-folder, to
  3431. // include it we need to reduce its score first
  3432. // (consider "0" as "ignore")
  3433. // "00" = 0, "01" = 1, "10" = 1, "30" = 3, "03" = 3,
  3434. // "33" = 3, all the rest gives 2 (some worn, some not
  3435. // worn)
  3436. if (tmp == "00")
  3437. {
  3438. sub_res = 0;
  3439. }
  3440. else if (tmp == "11" || tmp == "01" || tmp == "10")
  3441. {
  3442. sub_res = 1;
  3443. }
  3444. else if (tmp == "33" || tmp == "03" || tmp == "30")
  3445. {
  3446. sub_res = 3;
  3447. }
  3448. else
  3449. {
  3450. sub_res = 2;
  3451. }
  3452. // Then we must combine with the previous sibling
  3453. // sub-folders./ Same rule as above, set to 2 in all
  3454. // cases except when prev_sub_res == sub_res or when
  3455. // either == 0 (nothing present, ignore)
  3456. if (prev_sub_res == 0 && sub_res == 0)
  3457. {
  3458. sub_res = 0;
  3459. }
  3460. else if (prev_sub_res == 0 && sub_res == 1)
  3461. {
  3462. sub_res = 1;
  3463. }
  3464. else if (prev_sub_res == 1 && sub_res == 0)
  3465. {
  3466. sub_res = 1;
  3467. }
  3468. else if (prev_sub_res == 1 && sub_res == 1)
  3469. {
  3470. sub_res = 1;
  3471. }
  3472. else if (prev_sub_res == 0 && sub_res == 3)
  3473. {
  3474. sub_res = 3;
  3475. }
  3476. else if (prev_sub_res == 3 && sub_res == 0)
  3477. {
  3478. sub_res = 3;
  3479. }
  3480. else if (prev_sub_res == 3 && sub_res == 3)
  3481. {
  3482. sub_res = 3;
  3483. }
  3484. else
  3485. {
  3486. sub_res = 2;
  3487. }
  3488. prev_sub_res = sub_res;
  3489. }
  3490. }
  3491. }
  3492. }
  3493. }
  3494. if (no_mod)
  3495. {
  3496. // The folder contains one no-mod object and is named from an
  3497. // attachment point => return a special character that will be handled
  3498. // by the calling method
  3499. if (nb_worn > 0)
  3500. {
  3501. return "N";
  3502. }
  3503. else
  3504. {
  3505. return "n";
  3506. }
  3507. }
  3508. else
  3509. {
  3510. if (is_rlv_root || nb_items == 0)
  3511. {
  3512. // Forcibly hide all items contained directly under #RLV
  3513. res = 0;
  3514. }
  3515. else if (nb_worn >= nb_items)
  3516. {
  3517. res = 3;
  3518. }
  3519. else if (nb_worn > 0)
  3520. {
  3521. res = 2;
  3522. }
  3523. else
  3524. {
  3525. res = 1;
  3526. }
  3527. }
  3528. std::stringstream str;
  3529. str << res;
  3530. str << sub_res;
  3531. return str.str();
  3532. }
  3533. LLInventoryCategory* RLInterface::getRlvShare()
  3534. {
  3535. LLInventoryModel::cat_array_t* cats;
  3536. LLInventoryModel::item_array_t* items;
  3537. gInventory.getDirectDescendentsOf(gInventory.getRootFolderID(), cats,
  3538. items);
  3539. if (cats)
  3540. {
  3541. for (S32 i = 0, count = cats->size(); i < count; ++i)
  3542. {
  3543. LLInventoryCategory* cat = (*cats)[i];
  3544. const std::string& name = cat->getName();
  3545. if (name == RL_SHARED_FOLDER)
  3546. {
  3547. // LL_DEBUGS("RestrainedLove") << "found " << name << LL_ENDL;
  3548. return cat;
  3549. }
  3550. }
  3551. }
  3552. return NULL;
  3553. }
  3554. bool RLInterface::isUnderRlvShare(LLInventoryItem* item)
  3555. {
  3556. if (!item) return false;
  3557. const LLUUID& cat_id = item->getParentUUID();
  3558. return isUnderFolder(getRlvShare(), gInventory.getCategory(cat_id));
  3559. }
  3560. bool RLInterface::isUnderRlvShare(LLInventoryCategory* cat)
  3561. {
  3562. return isUnderFolder(getRlvShare(), cat);
  3563. }
  3564. bool RLInterface::isUnderFolder(LLInventoryCategory* parentp,
  3565. LLInventoryCategory* childp)
  3566. {
  3567. if (!parentp || !childp)
  3568. {
  3569. return false;
  3570. }
  3571. if (childp == parentp)
  3572. {
  3573. return true;
  3574. }
  3575. const LLUUID& root_id = gInventory.getRootFolderID();
  3576. const LLUUID& cat_id = childp->getParentUUID();
  3577. LLInventoryCategory* res = gInventory.getCategory(cat_id);
  3578. while (res && res->getUUID() != root_id)
  3579. {
  3580. if (res == parentp)
  3581. {
  3582. return true;
  3583. }
  3584. const LLUUID& parent_id = res->getParentUUID();
  3585. res = gInventory.getCategory(parent_id);
  3586. }
  3587. return false;
  3588. }
  3589. LLInventoryCategory* RLInterface::getCategoryUnderRlvShare(std::string cat_name,
  3590. LLInventoryCategory* root)
  3591. {
  3592. if (!root)
  3593. {
  3594. root = getRlvShare();
  3595. if (!root)
  3596. {
  3597. LL_DEBUGS("RestrainedLove") << "No " << RL_SHARED_FOLDER
  3598. << " folder !" << LL_ENDL;
  3599. return NULL;
  3600. }
  3601. }
  3602. if (cat_name.empty())
  3603. {
  3604. return root;
  3605. }
  3606. LLStringUtil::toLower(cat_name);
  3607. std::deque<std::string> tokens = parse(cat_name, "/");
  3608. // Preliminary action: remove everything after pipes("|"), including pipes
  3609. // themselves. This way we can feed the result of a @getinvworn command
  3610. // directly into this method without having to clean up what is after the
  3611. // pipes.
  3612. for (S32 i = 0, count = tokens.size(); i < count; ++i)
  3613. {
  3614. std::string tok = tokens[i];
  3615. size_t ind = tok.find('|');
  3616. if (ind != std::string::npos)
  3617. {
  3618. tok = tok.substr(0, ind);
  3619. tokens[i] = tok;
  3620. }
  3621. }
  3622. LLInventoryModel::cat_array_t* cats;
  3623. LLInventoryModel::item_array_t* items;
  3624. gInventory.getDirectDescendentsOf(root->getUUID(), cats, items);
  3625. if (!cats)
  3626. {
  3627. LL_DEBUGS("RestrainedLove") << "No sub-folder in "
  3628. << RL_SHARED_FOLDER << LL_ENDL;
  3629. return NULL;
  3630. }
  3631. // We first need to scan the folder tree and retain the best match
  3632. bool exact_match = false;
  3633. S32 max_size_index = -1;
  3634. S32 max_size = 0;
  3635. for (S32 i = 0, count = cats->size(); i < count; ++i)
  3636. {
  3637. LLInventoryCategory* cat = (*cats)[i];
  3638. std::string name = cat->getName();
  3639. if (!name.empty() && name[0] != '.') // Ignore invisible cats
  3640. {
  3641. LLStringUtil::toLower(name);
  3642. S32 size = match(tokens, name, exact_match);
  3643. if (size > max_size || (exact_match && size == max_size))
  3644. {
  3645. max_size = size;
  3646. max_size_index = i;
  3647. }
  3648. }
  3649. }
  3650. if (max_size <= 0)
  3651. {
  3652. LL_DEBUGS("RestrainedLove") << "No matching category name found for "
  3653. << cat_name << LL_ENDL;
  3654. return NULL;
  3655. }
  3656. // Only now we can grab the best match and either continue deeper or return
  3657. // it
  3658. LLInventoryCategory* cat = (*cats)[max_size_index];
  3659. if (max_size == (S32)tokens.size())
  3660. {
  3661. return cat;
  3662. }
  3663. // Recurse...
  3664. std::string subcat = dumpList2String(getSubList(tokens, max_size), "/");
  3665. return getCategoryUnderRlvShare(subcat, cat);
  3666. }
  3667. LLInventoryCategory* RLInterface::findCategoryUnderRlvShare(std::string cat_name,
  3668. LLInventoryCategory* root)
  3669. {
  3670. if (!root)
  3671. {
  3672. root = getRlvShare();
  3673. if (!root)
  3674. {
  3675. LL_DEBUGS("RestrainedLove") << "No " << RL_SHARED_FOLDER
  3676. << " folder !" << LL_ENDL;
  3677. return NULL;
  3678. }
  3679. }
  3680. LLStringUtil::toLower(cat_name);
  3681. std::deque<std::string> tokens = parse(cat_name, "&&");
  3682. LLInventoryModel::cat_array_t* cats;
  3683. LLInventoryModel::item_array_t* items;
  3684. gInventory.getDirectDescendentsOf(root->getUUID(), cats, items);
  3685. if (cats)
  3686. {
  3687. LLInventoryCategory* found;
  3688. for (S32 i = 0, count = cats->size(); i < count; ++i)
  3689. {
  3690. LLInventoryCategory* cat = (*cats)[i];
  3691. const std::string& name = cat->getName();
  3692. // We cannot find invisible folders('.') and given folders('~')
  3693. if (!name.empty() && name[0] != '.' && name[0] != '~')
  3694. {
  3695. // Search recursively deeper
  3696. found = findCategoryUnderRlvShare(cat_name, cat);
  3697. if (found)
  3698. {
  3699. return found;
  3700. }
  3701. }
  3702. }
  3703. }
  3704. // Return this category if it matches
  3705. std::string name = root->getName();
  3706. LLStringUtil::toLower(name);
  3707. // We cannot find invisible folders('.') and given folders('~')
  3708. if (!name.empty() && name[0] != '.' && name[0] != '~' &&
  3709. findMultiple(tokens, name))
  3710. {
  3711. return root;
  3712. }
  3713. return NULL; // We did not find anything
  3714. }
  3715. std::deque<LLInventoryCategory*> RLInterface::findCategoriesUnderRlvShare(std::string cat_name,
  3716. LLInventoryCategory* root)
  3717. {
  3718. std::deque<LLInventoryCategory*> res;
  3719. if (!root)
  3720. {
  3721. root = getRlvShare();
  3722. if (!root)
  3723. {
  3724. LL_DEBUGS("RestrainedLove") << "No " << RL_SHARED_FOLDER
  3725. << " folder !" << LL_ENDL;
  3726. return res;
  3727. }
  3728. }
  3729. LLStringUtil::toLower(cat_name);
  3730. std::deque<std::string> tokens = parse(cat_name, "&&");
  3731. LLInventoryModel::cat_array_t* cats;
  3732. LLInventoryModel::item_array_t* items;
  3733. gInventory.getDirectDescendentsOf(root->getUUID(), cats, items);
  3734. if (cats)
  3735. {
  3736. std::deque<LLInventoryCategory*> found;
  3737. for (S32 i = 0, count = cats->size(); i < count; ++i)
  3738. {
  3739. LLInventoryCategory* cat = (*cats)[i];
  3740. const std::string& name = cat->getName();
  3741. // We cannot find invisible folders('.') and given folders('~')
  3742. if (!name.empty() && name[0] != '.' && name[0] != '~')
  3743. {
  3744. // Search recursively deeper
  3745. found = findCategoriesUnderRlvShare(cat_name, cat);
  3746. for (S32 i = 0, count2 = found.size(); i < count2; ++i)
  3747. {
  3748. res.push_back(found[i]);
  3749. }
  3750. }
  3751. }
  3752. }
  3753. // Return this category if it matches
  3754. std::string name = root->getName();
  3755. LLStringUtil::toLower(name);
  3756. // We cannot find invisible folders('.') and given folders('~')
  3757. if (!name.empty() && name[0] != '.' && name[0] != '~' &&
  3758. findMultiple(tokens, name))
  3759. {
  3760. res.push_back(root);
  3761. }
  3762. return res;
  3763. }
  3764. bool RLInterface::shouldMoveToSharedSubFolder(LLViewerInventoryCategory* catp)
  3765. {
  3766. // Note: we do not test for getRlvShare(), since it is time consuming; the
  3767. // caller should test for it once and for all before doing repetitive calls
  3768. // to this method.
  3769. return catp->getName().compare(0, RL_HRLVST_LENGTH,
  3770. RL_RLV_REDIR_FOLDER_PREFIX) == 0;
  3771. }
  3772. void RLInterface::moveToSharedSubFolder(LLViewerInventoryCategory* catp)
  3773. {
  3774. LLInventoryCategory* rlv_root_catp = getRlvShare();
  3775. if (!rlv_root_catp)
  3776. {
  3777. return;
  3778. }
  3779. std::string folder_name = catp->getName();
  3780. if (folder_name.compare(0, RL_HRLVST_LENGTH,
  3781. RL_RLV_REDIR_FOLDER_PREFIX) != 0)
  3782. {
  3783. return;
  3784. }
  3785. // Remove #RLV/
  3786. folder_name.erase(0, RL_HRLVS_LENGTH);
  3787. // Sanitize the name
  3788. LLInventoryObject::correctInventoryName(folder_name);
  3789. // By default, we will put this folder under #RLV directly
  3790. LLInventoryCategory* target_catp = rlv_root_catp;
  3791. // We have received a "#RLV/~A/B/C" folder so we want to move it under our
  3792. // #RLV/ root folder.
  3793. // To avoid cluttering the #RLV folder with many sub-folders of the same
  3794. // name, we try to unify the hierarchy like so:
  3795. // - The last folder in the string must be created even if it already
  3796. // exists so we do not pollute an existing folder with new items.
  3797. // - All its parents must be unified with existing folders if possible,
  3798. // created if not possible.
  3799. std::deque<std::string> hierarchy = parse(folder_name, "/");
  3800. S32 sub_folders = hierarchy.size();
  3801. // For each parent folder in the name from left to right (if any, meaning
  3802. // if there is at least one "/" in the name of the folder we have
  3803. // received), unify or create that folder and make it the parent of the
  3804. // folder on its right.
  3805. for (S32 i = 0; i < sub_folders - 1; ++i)
  3806. {
  3807. const std::string& name = hierarchy[i];
  3808. LLInventoryModel::cat_array_t* cats;
  3809. LLInventoryModel::item_array_t* items;
  3810. gInventory.getDirectDescendentsOf(target_catp->getUUID(), cats, items);
  3811. // Try to find the first folder among the descendents which name
  3812. // matches the one we are examining.
  3813. LLInventoryCategory* found_catp = NULL;
  3814. for (S32 j = 0, count = cats->size(); j < count; ++j)
  3815. {
  3816. LLInventoryCategory* old_catp = (*cats)[j];
  3817. if (!LLStringUtil::compareInsensitive(old_catp->getName(), name))
  3818. {
  3819. // Found an existing folder with that name
  3820. found_catp = old_catp;
  3821. break;
  3822. }
  3823. }
  3824. if (found_catp)
  3825. {
  3826. target_catp = found_catp;
  3827. }
  3828. else
  3829. {
  3830. LLUUID id = gInventory.createCategoryUDP(target_catp->getUUID(),
  3831. LLFolderType::FT_NONE,
  3832. name);
  3833. gInventory.notifyObservers();
  3834. if (id.notNull())
  3835. {
  3836. target_catp = gInventory.getCategory(id);
  3837. }
  3838. }
  3839. }
  3840. // Now, move the folder we have received (the one with all the items in
  3841. // it) to our last created (deepest) folder.
  3842. gInventory.changeCategoryParent(catp, target_catp->getUUID(), false);
  3843. gInventory.notifyObservers();
  3844. // And rename it using the last folder name in the path.
  3845. rename_category(&gInventory, catp->getUUID(), hierarchy[sub_folders - 1]);
  3846. }
  3847. // This struct is meant to be used in RLInterface::findAttachmentPointFromName
  3848. // below
  3849. typedef struct
  3850. {
  3851. LLViewerJointAttachment* attachment;
  3852. S32 length;
  3853. S32 index;
  3854. } Candidate;
  3855. LLViewerJointAttachment* RLInterface::findAttachmentPointFromName(std::string obj_name,
  3856. bool exact_name)
  3857. {
  3858. // For each possible attachment point, check whether its name appears in
  3859. // the name of the item.
  3860. // We are going to scan the whole list of attachments, but we would not
  3861. // decide which one to take right away.
  3862. // Instead, for each matching point, we will store in lists the following
  3863. // results:
  3864. // - length of its name
  3865. // - right-most index where it is found in the name
  3866. // - a pointer to that attachment point
  3867. // When we have that list, choose the highest index, and in case of
  3868. // ex-aequo choose the longest length.
  3869. if (obj_name.length() < 3)
  3870. {
  3871. // No need to bother: the shorter attachment name is "Top" with 3
  3872. // characters...
  3873. return NULL;
  3874. }
  3875. if (!isAgentAvatarValid())
  3876. {
  3877. llwarns << "NULL avatar pointer. Aborting." << llendl;
  3878. return NULL;
  3879. }
  3880. LL_DEBUGS("RestrainedLove") << "Searching attachment name with "
  3881. << (exact_name ? "exact match"
  3882. : "partial matches") << " in: "
  3883. << obj_name << LL_ENDL;
  3884. LLStringUtil::toLower(obj_name);
  3885. std::string attach_name;
  3886. bool found_one = false;
  3887. std::vector<Candidate> candidates;
  3888. for (LLVOAvatar::attachment_map_t::iterator
  3889. iter = gAgentAvatarp->mAttachmentPoints.begin(),
  3890. end = gAgentAvatarp->mAttachmentPoints.end();
  3891. iter != end; ++iter)
  3892. {
  3893. LLViewerJointAttachment* attachment = iter->second;
  3894. if (attachment)
  3895. {
  3896. attach_name = attachment->getName();
  3897. if (attach_name == "Avatar Center")
  3898. {
  3899. attach_name = "Root";
  3900. }
  3901. LLStringUtil::toLower(attach_name);
  3902. #if 0
  3903. LL_DEBUGS("RestrainedLove") << "Trying attachment: " << attach_name
  3904. << LL_ENDL;
  3905. #endif
  3906. if (exact_name)
  3907. {
  3908. if (obj_name == attach_name)
  3909. {
  3910. return attachment;
  3911. }
  3912. }
  3913. else
  3914. {
  3915. size_t ind = obj_name.rfind(attach_name);
  3916. if (ind != std::string::npos &&
  3917. obj_name.substr(0, ind).find('(') != std::string::npos &&
  3918. obj_name.substr(ind).find(')') != std::string::npos)
  3919. {
  3920. Candidate new_candidate;
  3921. new_candidate.index = ind;
  3922. new_candidate.length = attach_name.length();
  3923. new_candidate.attachment = attachment;
  3924. candidates.emplace_back(new_candidate);
  3925. found_one = true;
  3926. LL_DEBUGS("RestrainedLove") << "New candidate: '"
  3927. << attach_name << "', index="
  3928. << new_candidate.index
  3929. << ", length="
  3930. << new_candidate.length
  3931. << LL_ENDL;
  3932. }
  3933. }
  3934. }
  3935. }
  3936. if (!found_one)
  3937. {
  3938. LL_DEBUGS("RestrainedLove") << "No attachment found." << LL_ENDL;
  3939. return NULL;
  3940. }
  3941. // Now that we have at least one candidate, we have to decide which one to
  3942. // return
  3943. LLViewerJointAttachment* res = NULL;
  3944. Candidate candidate;
  3945. S32 ind_res = -1;
  3946. S32 max_index = -1;
  3947. S32 max_length = -1;
  3948. S32 count = candidates.size();
  3949. // Find the highest index
  3950. for (S32 i = 0; i < count; ++i)
  3951. {
  3952. candidate = candidates[i];
  3953. if (candidate.index > max_index)
  3954. {
  3955. max_index = candidate.index;
  3956. }
  3957. }
  3958. // Find the longest match among the ones found at that index
  3959. for (S32 i = 0; i < count; ++i)
  3960. {
  3961. candidate = candidates[i];
  3962. if (candidate.index == max_index)
  3963. {
  3964. if (candidate.length > max_length)
  3965. {
  3966. max_length = candidate.length;
  3967. ind_res = i;
  3968. }
  3969. }
  3970. }
  3971. // Return this attachment point
  3972. if (ind_res > -1)
  3973. {
  3974. candidate = candidates[ind_res];
  3975. res = candidate.attachment;
  3976. if (res)
  3977. {
  3978. LL_DEBUGS("RestrainedLove") << "Returning: '" << res->getName()
  3979. << "'" << LL_ENDL;
  3980. }
  3981. }
  3982. return res;
  3983. }
  3984. LLViewerJointAttachment* RLInterface::findAttachmentPointFromParentName(LLInventoryItem* item)
  3985. {
  3986. if (item)
  3987. {
  3988. // Look in parent folder(this could be a no-mod item), use its name to
  3989. // find the target attach point
  3990. const LLUUID& parent_id = item->getParentUUID();
  3991. LLViewerInventoryCategory* cat = gInventory.getCategory(parent_id);
  3992. if (cat)
  3993. {
  3994. return findAttachmentPointFromName(cat->getName());
  3995. }
  3996. }
  3997. return NULL;
  3998. }
  3999. S32 RLInterface::findAttachmentPointNumber(LLViewerJointAttachment* attachment)
  4000. {
  4001. if (isAgentAvatarValid())
  4002. {
  4003. for (LLVOAvatar::attachment_map_t::iterator
  4004. iter = gAgentAvatarp->mAttachmentPoints.begin(),
  4005. end = gAgentAvatarp->mAttachmentPoints.end();
  4006. iter != end; ++iter)
  4007. {
  4008. if (iter->second == attachment)
  4009. {
  4010. return iter->first;
  4011. }
  4012. }
  4013. }
  4014. return -1;
  4015. }
  4016. // When an inventory item in #RLV gets attached and does not contain any
  4017. // attachment info in its name, rename it for later (truncate the name first if
  4018. // needed). Mod-ok items are renamed, else their parent folder, when two level
  4019. // deep or more in the tree and named "New Folder", gets renamed, else a new
  4020. // folder bearing the joint name is created and the item moved inside it.
  4021. // This is called only by LLVOAvatarSelf::attachObject() and must be followed
  4022. // with a 'gInventory.notifyObservers()' call as soon as appropriate. HB
  4023. void RLInterface::addAttachmentPointName(LLViewerObject* vobj)
  4024. {
  4025. static LLCachedControl<bool> rename(gSavedSettings,
  4026. "RestrainedLoveAutomaticRenameItems");
  4027. if (!isAgentAvatarValid() || !rename) return;
  4028. LLViewerInventoryItem* item =
  4029. gInventory.getItem(vobj->getAttachmentItemID());
  4030. if (!item || !item->isFinished() || !isUnderRlvShare(item) ||
  4031. findAttachmentPointFromName(item->getName()))
  4032. {
  4033. // Nothing to do.
  4034. return;
  4035. }
  4036. const LLUUID& item_id = item->getUUID();
  4037. std::string attach_name = gAgentAvatarp->getAttachedPointName(item_id);
  4038. LLStringUtil::toLower(attach_name);
  4039. if (item->getPermissions().allowModifyBy(gAgentID))
  4040. {
  4041. // Truncate the original inventory item name if too long
  4042. size_t max_name_length = DB_INV_ITEM_NAME_STR_LEN - 3 -
  4043. attach_name.size();
  4044. std::string item_name = item->getName();
  4045. if (item_name.length() >= max_name_length)
  4046. {
  4047. item_name = item_name.substr(0, max_name_length);
  4048. }
  4049. // Add the name of the attach point at the end of the name of the item.
  4050. // Note: this code uses AIS whenever enabled/possible. HB
  4051. LLSD updates;
  4052. updates["name"] = item_name + " (" + attach_name + ")";
  4053. update_inventory_item(item_id, updates);
  4054. return;
  4055. }
  4056. // This is a no-mod item, so we have to rename its parent category instead,
  4057. // provided it is at least 2 levels deep in the #RLV tree, or to move it
  4058. // inside a newly created sub-folder bearing the proper joint name.
  4059. LLInventoryCategory* rlv_share = getRlvShare();
  4060. const LLUUID& parent_id = item->getParentUUID();
  4061. LLViewerInventoryCategory* parentp = gInventory.getCategory(parent_id);
  4062. if (!parentp || (LLInventoryCategory*)parentp == rlv_share)
  4063. {
  4064. // No parent (!) or just under #RLV/: do not rename the #RLV/ folder !
  4065. return;
  4066. }
  4067. // Check to see the folder is already bearing the right attachment name.
  4068. if (findAttachmentPointFromName(parentp->getName()))
  4069. {
  4070. // Yes, so nothing to do...
  4071. return;
  4072. }
  4073. std::string new_name = ".(" + attach_name + ")";
  4074. // Do not rename the folder if it is only 1 level under #RLV/ (i.e. it is
  4075. // an outfit sub-folder) and do not rename it either if the user renamed it
  4076. // themselves, or if another call to this method already renamed it for
  4077. // another no-mod attachment. I.e. only allow to rename a freshly created
  4078. // "New Folder". HB
  4079. LLInventoryCategory* gparentp =
  4080. (LLInventoryCategory*)gInventory.getCategory(parentp->getParentUUID());
  4081. const std::string& default_name =
  4082. LLViewerFolderType::lookupNewCategoryName(LLFolderType::FT_NONE);
  4083. if (gparentp != rlv_share && parentp->getName() == default_name)
  4084. {
  4085. // Rename the category as ".(attachment name)".
  4086. // Note: this code uses AIS whenever enabled/possible. HB
  4087. LLSD updates;
  4088. updates["name"] = new_name;
  4089. update_inventory_category(parent_id, updates, NULL);
  4090. }
  4091. // Else, create a new category with the appropriate name, and move the
  4092. // no-mod item inside it. HB
  4093. else
  4094. {
  4095. LLUUID cat_id = gInventory.createCategoryUDP(parent_id,
  4096. LLFolderType::FT_NONE,
  4097. new_name);
  4098. move_inventory_item(item_id, cat_id, item->getName());
  4099. }
  4100. }
  4101. // Handles the detach message to the sim here, after a check
  4102. void RLInterface::detachObject(LLViewerObject* object)
  4103. {
  4104. if (object && (!gRLenabled || canDetach(object)))
  4105. {
  4106. LLMessageSystem* msg = gMessageSystemp;
  4107. msg->newMessage("ObjectDetach");
  4108. msg->nextBlockFast(_PREHASH_AgentData);
  4109. msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
  4110. msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
  4111. msg->nextBlockFast(_PREHASH_ObjectData);
  4112. msg->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID());
  4113. msg->sendReliable(gAgent.getRegionHost());
  4114. }
  4115. }
  4116. void RLInterface::detachAllObjectsFromAttachment(LLViewerJointAttachment* attachment)
  4117. {
  4118. if (!attachment) return;
  4119. // We need to remove all the objects from attachment->mAttachedObjects, one
  4120. // by one. To do this, and in order to avoid any race condition, we are
  4121. // going to copy the list and iterate on the copy instead of the original
  4122. // which changes everytime something is attached and detached, asynchronously.
  4123. LLViewerJointAttachment::attachedobjs_vec_t attached_objects =
  4124. attachment->mAttachedObjects;
  4125. for (S32 i = 0, count = attached_objects.size(); i < count; ++i)
  4126. {
  4127. LLViewerObject* object = attached_objects[i];
  4128. detachObject(object);
  4129. }
  4130. }
  4131. bool RLInterface::canDetachAllObjectsFromAttachment(LLViewerJointAttachment* attachment)
  4132. {
  4133. if (!attachment) return false;
  4134. for (U32 i = 0; i < attachment->mAttachedObjects.size(); ++i)
  4135. {
  4136. LLViewerObject* object = attachment->mAttachedObjects[i];
  4137. if (!canDetach(object))
  4138. {
  4139. return false;
  4140. }
  4141. }
  4142. return true;
  4143. }
  4144. void RLInterface::fetchInventory(LLInventoryCategory* root)
  4145. {
  4146. // do this only once on login
  4147. if (mInventoryFetched) return;
  4148. bool last_step = false;
  4149. if (!root)
  4150. {
  4151. root = getRlvShare();
  4152. last_step = true;
  4153. }
  4154. if (root)
  4155. {
  4156. LLViewerInventoryCategory* viewer_root = (LLViewerInventoryCategory*)root;
  4157. viewer_root->fetch();
  4158. LLInventoryModel::cat_array_t* cats;
  4159. LLInventoryModel::item_array_t* items;
  4160. // Retrieve all the shared folders
  4161. gInventory.getDirectDescendentsOf(viewer_root->getUUID(), cats, items);
  4162. if (cats)
  4163. {
  4164. for (S32 i = 0, count = cats->size(); i < count; ++i)
  4165. {
  4166. LLInventoryCategory* cat = (LLInventoryCategory*)(*cats)[i];
  4167. fetchInventory(cat);
  4168. }
  4169. }
  4170. }
  4171. if (last_step)
  4172. {
  4173. mInventoryFetched = true;
  4174. }
  4175. }
  4176. // Note: 'recursive' is true in the case of an attachall command
  4177. void RLInterface::forceAttach(const std::string& category, bool recursive,
  4178. EAttachMethod how)
  4179. {
  4180. if (category.empty())
  4181. {
  4182. return;
  4183. }
  4184. // Find the category under RLV shared folder
  4185. LLInventoryCategory* cat = getCategoryUnderRlvShare(category);
  4186. if (!cat)
  4187. {
  4188. // No such category. Skip.
  4189. return;
  4190. }
  4191. // We are replacing for now, but the name of the category could decide
  4192. // otherwise
  4193. bool replacing = how == AttachReplace || how == AttachOverOrReplace;
  4194. // If the name of the category begins with a "+", then we force to stack
  4195. // instead of replacing
  4196. if (how == AttachOverOrReplace)
  4197. {
  4198. const std::string& name = cat->getName();
  4199. if (!name.empty() && name[0] == '+')
  4200. {
  4201. replacing = false;
  4202. }
  4203. }
  4204. // Retrieve all the objects contained in this folder
  4205. LLInventoryModel::cat_array_t* cats;
  4206. LLInventoryModel::item_array_t* items;
  4207. gInventory.getDirectDescendentsOf(cat->getUUID(), cats, items);
  4208. bool is_rlv_root = getRlvShare() == cat;
  4209. if (!is_rlv_root && items)
  4210. {
  4211. // Wear them one by one
  4212. for (S32 i = 0, count = items->size(); i < count; ++i)
  4213. {
  4214. LLViewerInventoryItem* item = (LLViewerInventoryItem*)(*items)[i];
  4215. LL_DEBUGS("RestrainedLove") << "Trying to attach "
  4216. << item->getName() << LL_ENDL;
  4217. // This is an object to attach somewhere
  4218. if (item && item->getType() == LLAssetType::AT_OBJECT)
  4219. {
  4220. LLViewerJointAttachment* attachpt =
  4221. findAttachmentPointFromName(item->getName());
  4222. if (attachpt)
  4223. {
  4224. LL_DEBUGS("RestrainedLove") << "Attaching item to "
  4225. << attachpt->getName()
  4226. << LL_ENDL;
  4227. if (replacing)
  4228. {
  4229. // We are replacing => mimick rezAttachment without
  4230. // confirmation dialog
  4231. S32 number = findAttachmentPointNumber(attachpt);
  4232. if (canDetach(attachpt->getName()) && canAttach(item))
  4233. {
  4234. attachObjectByUUID(item->getLinkedUUID(), number,
  4235. true);
  4236. }
  4237. }
  4238. else
  4239. {
  4240. // We are stacking => call rezAttachment directly
  4241. gAppearanceMgr.rezAttachment(item, attachpt, false);
  4242. }
  4243. }
  4244. else
  4245. {
  4246. // Attachment point is not in the name => stack
  4247. gAppearanceMgr.rezAttachment(item, attachpt, false);
  4248. }
  4249. }
  4250. // This is a piece of clothing
  4251. else if (item->getType() == LLAssetType::AT_CLOTHING ||
  4252. item->getType() == LLAssetType::AT_BODYPART)
  4253. {
  4254. gAppearanceMgr.wearInventoryItemOnAvatar(item, replacing);
  4255. }
  4256. // This is a gesture: activate
  4257. else if (item->getType() == LLAssetType::AT_GESTURE)
  4258. {
  4259. if (!gGestureManager.isGestureActive(item->getLinkedUUID()))
  4260. {
  4261. gGestureManager.activateGesture(item->getLinkedUUID());
  4262. }
  4263. }
  4264. // This is an environment setting: activate
  4265. else if (item->getType() == LLAssetType::AT_SETTINGS)
  4266. {
  4267. if (!mContainsSetenv && !sRLNoSetEnv)
  4268. {
  4269. gEnvironment.setEnvironment(LLEnvironment::ENV_LOCAL,
  4270. item->getAssetUUID());
  4271. gEnvironment.setSelectedEnvironment(LLEnvironment::ENV_LOCAL,
  4272. LLEnvironment::TRANSITION_INSTANT);
  4273. }
  4274. }
  4275. }
  4276. }
  4277. if (!cats)
  4278. {
  4279. // No sub-folder, we are done !
  4280. return;
  4281. }
  4282. // Not taken into account, we (possibly) recurse instead:
  4283. LLInventoryModel::cat_array_t* subcats;
  4284. // Actual no-mod item(s):
  4285. LLInventoryModel::item_array_t* subcatitems;
  4286. // Scan every sub-folder of the folder we are attaching, in order to attach
  4287. // no-mod items. For each subfolder, attach the first item it contains
  4288. // according to its name
  4289. for (S32 i = 0, count = cats->size(); i < count; ++i)
  4290. {
  4291. LLViewerInventoryCategory* childp =
  4292. (LLViewerInventoryCategory*)(*cats)[i];
  4293. LLViewerJointAttachment* attachpt =
  4294. findAttachmentPointFromName(childp->getName());
  4295. if (!is_rlv_root && attachpt)
  4296. {
  4297. // This subfolder is properly named => attach the first item it
  4298. // contains.
  4299. gInventory.getDirectDescendentsOf(childp->getUUID(), subcats,
  4300. subcatitems);
  4301. if (subcatitems && subcatitems->size() == 1)
  4302. {
  4303. LLViewerInventoryItem* subcatitem =
  4304. (LLViewerInventoryItem*)(*subcatitems)[0];
  4305. if (subcatitem &&
  4306. subcatitem->getType() == LLAssetType::AT_OBJECT &&
  4307. !subcatitem->getPermissions().allowModifyBy(gAgentID) &&
  4308. findAttachmentPointFromParentName(subcatitem))
  4309. {
  4310. // It is no-mod and its parent is named correctly: we use
  4311. // the attach point from the name of the folder, not the
  4312. // no-mod item
  4313. if (replacing)
  4314. {
  4315. // Mimick rezAttachment without a confirmation dialog
  4316. S32 number = findAttachmentPointNumber(attachpt);
  4317. if (canDetach(attachpt->getName()) &&
  4318. canAttach(subcatitem))
  4319. {
  4320. attachObjectByUUID(subcatitem->getLinkedUUID(),
  4321. number, true);
  4322. }
  4323. }
  4324. else
  4325. {
  4326. // We are stacking => call rezAttachment directly
  4327. gAppearanceMgr.rezAttachment(subcatitem, attachpt,
  4328. false);
  4329. }
  4330. }
  4331. }
  4332. }
  4333. if (recursive)
  4334. {
  4335. const std::string& name = childp->getName();
  4336. if (name.empty() || name[0] != '.')
  4337. {
  4338. // attachall and not invisible
  4339. forceAttach(getFullPath(childp), recursive, how);
  4340. }
  4341. }
  4342. }
  4343. }
  4344. bool RLInterface::forceDetachByName(const std::string& category,
  4345. bool recursive)
  4346. {
  4347. if (!isAgentAvatarValid())
  4348. {
  4349. return false;
  4350. }
  4351. if (category.empty())
  4352. {
  4353. return true; // Nothing to do = success
  4354. }
  4355. // Find the category under RLV shared folder
  4356. LLInventoryCategory* cat = getCategoryUnderRlvShare(category);
  4357. if (!cat)
  4358. {
  4359. return true; // Nothing to do = success
  4360. }
  4361. bool is_rlv_root = getRlvShare() == cat;
  4362. if (mHandleNoStrip)
  4363. {
  4364. std::string name = cat->getName();
  4365. LLStringUtil::toLower(name);
  4366. if (name.find(RL_PROTECTED_FOLDER_TAG) != std::string::npos)
  4367. {
  4368. return false; // Protected folder !
  4369. }
  4370. }
  4371. // Retrieve all the objects contained in this folder
  4372. LLInventoryModel::cat_array_t* cats;
  4373. LLInventoryModel::item_array_t* items;
  4374. gInventory.getDirectDescendentsOf(cat->getUUID(), cats, items);
  4375. if (!is_rlv_root && items)
  4376. {
  4377. // Un-wear them one by one
  4378. for (S32 i = 0, count = items->size(); i < count; ++i)
  4379. {
  4380. LLViewerInventoryItem* item = (LLViewerInventoryItem*)(*items)[i];
  4381. LL_DEBUGS("RestrainedLove") << "Trying to detach "
  4382. << item->getName() << LL_ENDL;
  4383. if (item->getType() == LLAssetType::AT_OBJECT)
  4384. {
  4385. // This is an attached object, find the attachpoint from which
  4386. // to detach
  4387. for (LLVOAvatar::attachment_map_t::iterator
  4388. iter = gAgentAvatarp->mAttachmentPoints.begin(),
  4389. end = gAgentAvatarp->mAttachmentPoints.end();
  4390. iter != end; ++iter)
  4391. {
  4392. LLViewerJointAttachment* attachment = iter->second;
  4393. LLViewerObject* object =
  4394. gAgentAvatarp->getWornAttachment(item->getUUID());
  4395. if (object && attachment &&
  4396. attachment->isObjectAttached(object))
  4397. {
  4398. detachObject(object);
  4399. break;
  4400. }
  4401. }
  4402. }
  4403. else if (item->getType() == LLAssetType::AT_CLOTHING)
  4404. {
  4405. // This is a piece of clothing: remove
  4406. if (canDetach(item))
  4407. {
  4408. removeWearableItemFromAvatar(item);
  4409. }
  4410. }
  4411. else if (item->getType() == LLAssetType::AT_GESTURE)
  4412. {
  4413. // This is a gesture: deactivate
  4414. if (gGestureManager.isGestureActive(item->getLinkedUUID()))
  4415. {
  4416. gGestureManager.deactivateGesture(item->getLinkedUUID());
  4417. }
  4418. }
  4419. #if 0 // Do nothing because we do not know what to replace it with... HB
  4420. // This is an environment setting: deactivate
  4421. else if (item->getType() == LLAssetType::AT_SETTINGS)
  4422. {
  4423. if (!mContainsSetenv && !sRLNoSetEnv)
  4424. {
  4425. gEnvironment.clearEnvironment(LLEnvironment::ENV_LOCAL);
  4426. gEnvironment.setSelectedEnvironment(LLEnvironment::ENV_LOCAL,
  4427. LLEnvironment::TRANSITION_INSTANT);
  4428. }
  4429. }
  4430. #endif
  4431. }
  4432. }
  4433. if (!cats)
  4434. {
  4435. // No sub-folder, we are done !
  4436. return true;
  4437. }
  4438. // Not taken into account, we (possibly) recurse instead:
  4439. LLInventoryModel::cat_array_t* subcats;
  4440. // Actual no-mod item(s):
  4441. LLInventoryModel::item_array_t* subcatitems;
  4442. // For each subfolder, detach the first item it contains (only for single
  4443. // no-mod items contained in appropriately named folders)
  4444. for (S32 i = 0, count = cats->size(); i < count; ++i)
  4445. {
  4446. LLViewerInventoryCategory* childp =
  4447. (LLViewerInventoryCategory*)(*cats)[i];
  4448. if (mHandleNoStrip)
  4449. {
  4450. std::string name = childp->getName();
  4451. LLStringUtil::toLower(name);
  4452. if (name.find(RL_PROTECTED_FOLDER_TAG) != std::string::npos)
  4453. {
  4454. continue; // Protected folder...
  4455. }
  4456. }
  4457. gInventory.getDirectDescendentsOf(childp->getUUID(), subcats,
  4458. subcatitems);
  4459. if (!is_rlv_root && subcatitems && subcatitems->size() == 1)
  4460. {
  4461. // Only one item...
  4462. LLViewerInventoryItem* subcatitem =
  4463. (LLViewerInventoryItem*)(*subcatitems)[0];
  4464. if (subcatitem &&
  4465. subcatitem->getType() == LLAssetType::AT_OBJECT &&
  4466. !subcatitem->getPermissions().allowModifyBy(gAgentID) &&
  4467. findAttachmentPointFromParentName(subcatitem))
  4468. {
  4469. // ... and it is no-mod and its parent is named correctly
  4470. // detach this object. Find the attachpoint from which to
  4471. // detach.
  4472. for (LLVOAvatar::attachment_map_t::iterator
  4473. iter = gAgentAvatarp->mAttachmentPoints.begin(),
  4474. end = gAgentAvatarp->mAttachmentPoints.end();
  4475. iter != end; ++iter)
  4476. {
  4477. LLViewerJointAttachment* attachment = iter->second;
  4478. LLViewerObject* object =
  4479. gAgentAvatarp->getWornAttachment(subcatitem->getUUID());
  4480. if (object && attachment &&
  4481. attachment->isObjectAttached(object))
  4482. {
  4483. detachObject(object);
  4484. break;
  4485. }
  4486. }
  4487. }
  4488. }
  4489. if (recursive)
  4490. {
  4491. const std::string& name = childp->getName();
  4492. if (name.empty() || name[0] != '.')
  4493. {
  4494. // detachall and not invisible
  4495. forceDetachByName(getFullPath(childp), recursive);
  4496. }
  4497. }
  4498. }
  4499. return true;
  4500. }
  4501. #if LL_CLANG
  4502. // Ignore the '°' encoding in separators below
  4503. # pragma clang diagnostic ignored "-Winvalid-source-encoding"
  4504. #endif
  4505. std::string RLInterface::stringReplace(std::string s, std::string what_str,
  4506. const std::string& by_str,
  4507. bool case_sensitive)
  4508. {
  4509. if (what_str.empty() || what_str == " ")
  4510. {
  4511. return s; // Avoid an infinite loop
  4512. }
  4513. size_t len_by_str = by_str.length();
  4514. if (len_by_str == 0)
  4515. {
  4516. len_by_str = 1; // Avoid an infinite loop
  4517. }
  4518. size_t len_what_str = what_str.length();
  4519. size_t ind;
  4520. while ((ind = s.find("%20")) != std::string::npos) // Unescape
  4521. {
  4522. s = s.replace(ind, 3, " ");
  4523. }
  4524. std::string lower = s;
  4525. if (!case_sensitive)
  4526. {
  4527. LLStringUtil::toLower(lower);
  4528. LLStringUtil::toLower(what_str);
  4529. }
  4530. static std::string separators = " .,:;!?'\"_()[]{}*/+-=°~&|@#%$`<>\\\t\n";
  4531. size_t len_s = s.length();
  4532. size_t old_ind = 0;
  4533. while ((ind = lower.find(what_str, old_ind)) != std::string::npos)
  4534. {
  4535. char prec = ' ';
  4536. if (ind > 0)
  4537. {
  4538. prec = s[ind - 1];
  4539. }
  4540. char succ = ' ';
  4541. if (ind < len_s - len_what_str - 1)
  4542. {
  4543. succ = s[ind + len_what_str];
  4544. }
  4545. if (separators.find(prec) != std::string::npos &&
  4546. separators.find(succ) != std::string::npos)
  4547. {
  4548. s = s.replace(ind, len_what_str, by_str);
  4549. lower = s;
  4550. if (!case_sensitive)
  4551. {
  4552. LLStringUtil::toLower(lower);
  4553. }
  4554. }
  4555. old_ind = ind + len_by_str;
  4556. }
  4557. return s;
  4558. }
  4559. std::string RLInterface::getDummyName(std::string name,
  4560. EChatAudible audible)
  4561. {
  4562. std::string res;
  4563. size_t len = name.length();
  4564. if (len == 0) return res;
  4565. // We use mLaunchTimestamp in order to modify the scrambling when the
  4566. // session restarts (it stays consistent during the session though). But in
  4567. // crashy situations, let's not make it change at EVERY session, more like
  4568. // once a day or so. A day is 86400 seconds, the closest power of two is
  4569. // 65536, that is a 16 bits shift. Very lame hash function I know... but it
  4570. // should be linear enough (the old length method was way too gaussian with
  4571. // a peak at 11 to 16 characters)
  4572. unsigned char hash = name[0] + name[len - 1] + len +
  4573. (mLaunchTimestamp >> 16);
  4574. unsigned char mod = hash % 28;
  4575. switch (mod)
  4576. {
  4577. case 0:
  4578. res = "A resident";
  4579. break;
  4580. case 1:
  4581. res = "This resident";
  4582. break;
  4583. case 2:
  4584. res = "That resident";
  4585. break;
  4586. case 3:
  4587. res = "An individual";
  4588. break;
  4589. case 4:
  4590. res = "This individual";
  4591. break;
  4592. case 5:
  4593. res = "That individual";
  4594. break;
  4595. case 6:
  4596. res = "A person";
  4597. break;
  4598. case 7:
  4599. res = "This person";
  4600. break;
  4601. case 8:
  4602. res = "That person";
  4603. break;
  4604. case 9:
  4605. res = "A stranger";
  4606. break;
  4607. case 10:
  4608. res = "This stranger";
  4609. break;
  4610. case 11:
  4611. res = "That stranger";
  4612. break;
  4613. case 12:
  4614. res = "A human being";
  4615. break;
  4616. case 13:
  4617. res = "This human being";
  4618. break;
  4619. case 14:
  4620. res = "That human being";
  4621. break;
  4622. case 15:
  4623. res = "An agent";
  4624. break;
  4625. case 16:
  4626. res = "This agent";
  4627. break;
  4628. case 17:
  4629. res = "That agent";
  4630. break;
  4631. case 18:
  4632. res = "A soul";
  4633. break;
  4634. case 19:
  4635. res = "This soul";
  4636. break;
  4637. case 20:
  4638. res = "That soul";
  4639. break;
  4640. case 21:
  4641. res = "Somebody";
  4642. break;
  4643. case 22:
  4644. res = "Anonymous one";
  4645. break;
  4646. case 23:
  4647. res = "Someone";
  4648. break;
  4649. case 24:
  4650. res = "Mysterious one";
  4651. break;
  4652. case 25:
  4653. res = "An unknown being";
  4654. break;
  4655. case 26:
  4656. res = "Unidentified one";
  4657. break;
  4658. default:
  4659. res = "An unknown person";
  4660. }
  4661. if (audible == CHAT_AUDIBLE_BARELY)
  4662. {
  4663. res += " afar";
  4664. }
  4665. return res;
  4666. }
  4667. // Hides every occurrence of the name of anybody around (found in cache, so not
  4668. // completely accurate neither completely immediate).
  4669. std::string RLInterface::getCensoredMessage(std::string str)
  4670. {
  4671. uuid_vec_t avatar_ids;
  4672. gWorld.getAvatars(avatar_ids);
  4673. LLUUID avatar_id;
  4674. std::string name, dummy_name;
  4675. LLAvatarName avatar_name;
  4676. for (U32 i = 0, count = avatar_ids.size(); i < count; ++i)
  4677. {
  4678. avatar_id = avatar_ids[i];
  4679. // If listed in exceptions, skip this avatar
  4680. if (mExceptions.count(avatar_id)) continue;
  4681. if (gCacheNamep && gCacheNamep->getFullName(avatar_id, name))
  4682. {
  4683. dummy_name = getDummyName(name);
  4684. str = stringReplace(str, name, dummy_name); // Legacy name
  4685. size_t j = name.find(" Resident");
  4686. if (j > 0)
  4687. {
  4688. name = name.substr(0, j);
  4689. // legacy name, without " Resident"
  4690. str = stringReplace(str, name, dummy_name);
  4691. }
  4692. }
  4693. if (LLAvatarNameCache::get(avatar_id, &avatar_name))
  4694. {
  4695. if (!avatar_name.mIsDisplayNameDefault)
  4696. {
  4697. name = avatar_name.mDisplayName;
  4698. dummy_name = getDummyName(name);
  4699. str = stringReplace(str, name, dummy_name); // Display name
  4700. }
  4701. }
  4702. }
  4703. return str;
  4704. }
  4705. std::string RLInterface::getCensoredLocation(std::string str)
  4706. {
  4707. if (gAgent.getRegion())
  4708. {
  4709. // Hide every occurrence of the Parcel name
  4710. str = stringReplace(str, mParcelName, "(Parcel hidden)");
  4711. // Hide every occurrence of the Region name
  4712. str = stringReplace(str, gAgent.getRegion()->getName(),
  4713. "(Region hidden)");
  4714. }
  4715. return str;
  4716. }
  4717. bool RLInterface::forceEnvironment(std::string command, std::string option)
  4718. {
  4719. // Compatibility with RLVa
  4720. LLStringUtil::replaceChar(option, '/', ';');
  4721. // Reset this since we are going to change any loaded preset...
  4722. mLastLoadedPreset.clear();
  4723. // 'command' is "setenv_<something>"
  4724. F32 val = (F32)atof(option.c_str());
  4725. constexpr size_t length = 7; // Size of "setenv_"
  4726. command = command.substr(length);
  4727. LLSettingsSky::ptr_t skyp;
  4728. if (gEnvironment.hasEnvironment(LLEnvironment::ENV_LOCAL))
  4729. {
  4730. if (gEnvironment.getEnvironmentDay(LLEnvironment::ENV_LOCAL))
  4731. {
  4732. // We have a full day cycle in the local environment: freeze
  4733. // the sky.
  4734. skyp = gEnvironment.getEnvironmentFixedSky(LLEnvironment::ENV_LOCAL)->buildClone();
  4735. gEnvironment.setEnvironment(LLEnvironment::ENV_LOCAL, skyp, 0);
  4736. }
  4737. else
  4738. {
  4739. // Otherwise we can just use the local sky.
  4740. skyp = gEnvironment.getEnvironmentFixedSky(LLEnvironment::ENV_LOCAL);
  4741. }
  4742. }
  4743. else
  4744. {
  4745. // Use a copy of the parcel environment sky instead.
  4746. skyp = gEnvironment.getEnvironmentFixedSky(LLEnvironment::ENV_PARCEL,
  4747. true)->buildClone();
  4748. gEnvironment.setEnvironment(LLEnvironment::ENV_LOCAL, skyp, 0);
  4749. }
  4750. gEnvironment.setSelectedEnvironment(LLEnvironment::ENV_LOCAL,
  4751. LLEnvironment::TRANSITION_INSTANT);
  4752. if (command == "daytime")
  4753. {
  4754. if (val > 1.f)
  4755. {
  4756. val = 1.f;
  4757. }
  4758. if (val >= 0.f)
  4759. {
  4760. gEnvironment.setFixedTimeOfDay(val);
  4761. }
  4762. else
  4763. {
  4764. gSavedSettings.setBool("UseParcelEnvironment", true);
  4765. }
  4766. }
  4767. else if (command == "reset") // Synonym for "daytime:-1"
  4768. {
  4769. gEnvironment.clearEnvironment(LLEnvironment::ENV_LOCAL);
  4770. gEnvironment.setSelectedEnvironment(LLEnvironment::ENV_LOCAL,
  4771. LLEnvironment::TRANSITION_INSTANT);
  4772. }
  4773. else if (command == "bluehorizonr")
  4774. {
  4775. LLColor3 bluehorizon = skyp->getBlueHorizon();
  4776. bluehorizon.mV[0] = val * 2.f;
  4777. skyp->setBlueHorizon(bluehorizon);
  4778. skyp->update();
  4779. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  4780. }
  4781. else if (command == "bluehorizong")
  4782. {
  4783. LLColor3 bluehorizon = skyp->getBlueHorizon();
  4784. bluehorizon.mV[1] = val * 2.f;
  4785. skyp->setBlueHorizon(bluehorizon);
  4786. skyp->update();
  4787. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  4788. }
  4789. else if (command == "bluehorizonb")
  4790. {
  4791. LLColor3 bluehorizon = skyp->getBlueHorizon();
  4792. bluehorizon.mV[2] = val * 2.f;
  4793. skyp->setBlueHorizon(bluehorizon);
  4794. skyp->update();
  4795. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  4796. }
  4797. else if (command == "bluehorizoni")
  4798. {
  4799. LLColor3 bluehorizon = skyp->getBlueHorizon();
  4800. F32 old_intensity = llmax(bluehorizon.mV[0], bluehorizon.mV[1],
  4801. bluehorizon.mV[2]);
  4802. if (val == 0.f || old_intensity == 0.f)
  4803. {
  4804. bluehorizon.mV[0] = bluehorizon.mV[1] =
  4805. bluehorizon.mV[2] = val * 2.f;
  4806. }
  4807. else
  4808. {
  4809. F32 factor = val * 2.f / old_intensity;
  4810. bluehorizon.mV[0] *= factor;
  4811. bluehorizon.mV[1] *= factor;
  4812. bluehorizon.mV[2] *= factor;
  4813. }
  4814. skyp->setBlueHorizon(bluehorizon);
  4815. skyp->update();
  4816. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  4817. }
  4818. else if (command == "bluehorizon")
  4819. {
  4820. std::deque<std::string> tokens = parse(option, ";");
  4821. F32 r = atof(tokens[0].c_str()) * 2.f;
  4822. F32 g = atof(tokens[1].c_str()) * 2.f;
  4823. F32 b = atof(tokens[2].c_str()) * 2.f;
  4824. LLColor3 bluehorizon = skyp->getBlueHorizon();
  4825. bluehorizon.mV[0] = r;
  4826. bluehorizon.mV[1] = g;
  4827. bluehorizon.mV[2] = b;
  4828. skyp->setBlueHorizon(bluehorizon);
  4829. skyp->update();
  4830. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  4831. }
  4832. else if (command == "bluedensityr")
  4833. {
  4834. LLColor3 bluedensity = skyp->getBlueDensity();
  4835. bluedensity.mV[0] = val * 2.f;
  4836. skyp->setBlueDensity(bluedensity);
  4837. skyp->update();
  4838. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  4839. }
  4840. else if (command == "bluedensityg")
  4841. {
  4842. LLColor3 bluedensity = skyp->getBlueDensity();
  4843. bluedensity.mV[1] = val * 2.f;
  4844. skyp->setBlueDensity(bluedensity);
  4845. skyp->update();
  4846. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  4847. }
  4848. else if (command == "bluedensityb")
  4849. {
  4850. LLColor3 bluedensity = skyp->getBlueDensity();
  4851. bluedensity.mV[2] = val * 2.f;
  4852. skyp->setBlueDensity(bluedensity);
  4853. skyp->update();
  4854. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  4855. }
  4856. else if (command == "bluedensityi")
  4857. {
  4858. LLColor3 bluedensity = skyp->getBlueDensity();
  4859. F32 old_intensity = llmax(bluedensity.mV[0], bluedensity.mV[1],
  4860. bluedensity.mV[2]);
  4861. if (val == 0.f || old_intensity == 0.f)
  4862. {
  4863. bluedensity.mV[0] = bluedensity.mV[1] =
  4864. bluedensity.mV[2] = val * 2.f;
  4865. }
  4866. else
  4867. {
  4868. F32 factor = val * 2.f / old_intensity;
  4869. bluedensity.mV[0] *= factor;
  4870. bluedensity.mV[1] *= factor;
  4871. bluedensity.mV[2] *= factor;
  4872. }
  4873. skyp->setBlueDensity(bluedensity);
  4874. skyp->update();
  4875. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  4876. }
  4877. else if (command == "bluedensity")
  4878. {
  4879. std::deque<std::string> tokens = parse(option, ";");
  4880. F32 r = atof(tokens[0].c_str()) * 2.f;
  4881. F32 g = atof(tokens[1].c_str()) * 2.f;
  4882. F32 b = atof(tokens[2].c_str()) * 2.f;
  4883. LLColor3 bluedensity = skyp->getBlueDensity();
  4884. bluedensity.mV[0] = r;
  4885. bluedensity.mV[1] = g;
  4886. bluedensity.mV[2] = b;
  4887. skyp->setBlueDensity(bluedensity);
  4888. skyp->update();
  4889. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  4890. }
  4891. else if (command == "hazehorizon")
  4892. {
  4893. skyp->setHazeHorizon(val);
  4894. skyp->update();
  4895. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  4896. }
  4897. else if (command == "hazedensity")
  4898. {
  4899. skyp->setHazeDensity(val * 4.f);
  4900. skyp->update();
  4901. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  4902. }
  4903. else if (command == "densitymultiplier")
  4904. {
  4905. skyp->setDensityMultiplier(val * 0.001f);
  4906. skyp->update();
  4907. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  4908. }
  4909. else if (command == "distancemultiplier")
  4910. {
  4911. skyp->setDistanceMultiplier(val);
  4912. skyp->update();
  4913. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  4914. }
  4915. else if (command == "maxaltitude")
  4916. {
  4917. skyp->setMaxY(val);
  4918. skyp->update();
  4919. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  4920. }
  4921. else if (command == "sunmooncolorr" || command == "sunlightcolorr")
  4922. {
  4923. LLColor3 suncolour= skyp->getSunlightColor();
  4924. suncolour.mV[0] = val * 3.f;
  4925. skyp->setSunlightColor(suncolour);
  4926. skyp->update();
  4927. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  4928. }
  4929. else if (command == "sunmooncolorg" || command == "sunlightcolorg")
  4930. {
  4931. LLColor3 suncolour= skyp->getSunlightColor();
  4932. suncolour.mV[1] = val * 3.f;
  4933. skyp->setSunlightColor(suncolour);
  4934. skyp->update();
  4935. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  4936. }
  4937. else if (command == "sunmooncolorb" || command == "sunlightcolorb")
  4938. {
  4939. LLColor3 suncolour= skyp->getSunlightColor();
  4940. suncolour.mV[2] = val * 3.f;
  4941. skyp->setSunlightColor(suncolour);
  4942. skyp->update();
  4943. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  4944. }
  4945. else if (command == "sunmooncolori" || command == "sunlightcolori")
  4946. {
  4947. LLColor3 suncolour= skyp->getSunlightColor();
  4948. F32 old_intensity = llmax(suncolour.mV[0], suncolour.mV[1],
  4949. suncolour.mV[2]);
  4950. if (val == 0.f || old_intensity == 0.f)
  4951. {
  4952. suncolour.mV[0] = suncolour.mV[1] = suncolour.mV[2] = val * 3.f;
  4953. }
  4954. else
  4955. {
  4956. F32 factor = val * 3.f / old_intensity;
  4957. suncolour.mV[0] *= factor;
  4958. suncolour.mV[1] *= factor;
  4959. suncolour.mV[2] *= factor;
  4960. }
  4961. skyp->setSunlightColor(suncolour);
  4962. skyp->update();
  4963. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  4964. }
  4965. else if (command == "sunmooncolor" || command == "sunlightcolor")
  4966. {
  4967. std::deque<std::string> tokens = parse(option, ";");
  4968. F32 r = atof(tokens[0].c_str()) * 3.f;
  4969. F32 g = atof(tokens[1].c_str()) * 3.f;
  4970. F32 b = atof(tokens[2].c_str()) * 3.f;
  4971. LLColor3 suncolour = skyp->getSunlightColor();
  4972. suncolour.mV[0] = r;
  4973. suncolour.mV[1] = g;
  4974. suncolour.mV[2] = b;
  4975. skyp->setSunlightColor(suncolour);
  4976. skyp->update();
  4977. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  4978. }
  4979. else if (command == "ambientr")
  4980. {
  4981. LLColor3 ambientcolor = skyp->getAmbientColor();
  4982. ambientcolor.mV[0] = val * 3.f;
  4983. skyp->setAmbientColor(ambientcolor);
  4984. skyp->update();
  4985. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  4986. }
  4987. else if (command == "ambientg")
  4988. {
  4989. LLColor3 ambientcolor = skyp->getAmbientColor();
  4990. ambientcolor.mV[1] = val * 3.f;
  4991. skyp->setAmbientColor(ambientcolor);
  4992. skyp->update();
  4993. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  4994. }
  4995. else if (command == "ambientb")
  4996. {
  4997. LLColor3 ambientcolor = skyp->getAmbientColor();
  4998. ambientcolor.mV[2] = val * 3.f;
  4999. skyp->setAmbientColor(ambientcolor);
  5000. skyp->update();
  5001. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5002. }
  5003. else if (command == "ambienti")
  5004. {
  5005. LLColor3 ambientcolor = skyp->getAmbientColor();
  5006. F32 old_intensity = llmax(ambientcolor.mV[0], ambientcolor.mV[1],
  5007. ambientcolor.mV[2]);
  5008. if (val == 0.f || old_intensity == 0.f)
  5009. {
  5010. ambientcolor.mV[0] = ambientcolor.mV[1] = ambientcolor.mV[2] =
  5011. val * 3.f;
  5012. }
  5013. else
  5014. {
  5015. F32 factor = val * 3.f / old_intensity;
  5016. ambientcolor.mV[0] *= factor;
  5017. ambientcolor.mV[1] *= factor;
  5018. ambientcolor.mV[2] *= factor;
  5019. }
  5020. skyp->setAmbientColor(ambientcolor);
  5021. skyp->update();
  5022. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5023. }
  5024. else if (command == "ambient")
  5025. {
  5026. std::deque<std::string> tokens = parse(option, ";");
  5027. F32 r = atof(tokens[0].c_str()) * 3.f;
  5028. F32 g = atof(tokens[1].c_str()) * 3.f;
  5029. F32 b = atof(tokens[2].c_str()) * 3.f;
  5030. LLColor3 ambientcolor = skyp->getAmbientColor();
  5031. ambientcolor.mV[0] = r;
  5032. ambientcolor.mV[1] = g;
  5033. ambientcolor.mV[2] = b;
  5034. skyp->setAmbientColor(ambientcolor);
  5035. skyp->update();
  5036. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5037. }
  5038. else if (command == "sunglowfocus")
  5039. {
  5040. LLColor3 glow = skyp->getGlow();
  5041. glow.mV[2] = val * -5.f;
  5042. skyp->setGlow(glow);
  5043. skyp->update();
  5044. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5045. }
  5046. else if (command == "sunglowsize")
  5047. {
  5048. LLColor3 glow = skyp->getGlow();
  5049. glow.mV[0] = val * 20.f;
  5050. skyp->setGlow(glow);
  5051. skyp->update();
  5052. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5053. }
  5054. else if (command == "scenegamma")
  5055. {
  5056. skyp->setGamma(val);
  5057. skyp->update();
  5058. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5059. }
  5060. else if (command == "sunazim" || command == "sunazimuth")
  5061. {
  5062. val -= F_TWO_PI * floorf((val + F_PI) / F_TWO_PI);
  5063. LLQuaternion orig_quat = skyp->getSunRotation();
  5064. F32 roll, pitch, yaw;
  5065. orig_quat.getEulerAngles(&roll, &pitch, &yaw);
  5066. LLQuaternion rotation_world;
  5067. rotation_world.setEulerAngles(0.f, 0.f, val - yaw);
  5068. rotation_world.normalize();
  5069. LLQuaternion new_quat = orig_quat * rotation_world;
  5070. skyp->setSunRotation(new_quat);
  5071. skyp->update();
  5072. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5073. }
  5074. else if (command == "sunelev" || command == "sunelevation")
  5075. {
  5076. val = -llclamp(val, -F_PI_BY_TWO, F_PI_BY_TWO);
  5077. LLQuaternion orig_quat = skyp->getSunRotation();
  5078. F32 roll, pitch, yaw;
  5079. orig_quat.getEulerAngles(&roll, &pitch, &yaw);
  5080. LLQuaternion pitch_quat;
  5081. pitch_quat.setAngleAxis(val, 0.f, 1.f, 0.f);
  5082. LLQuaternion yaw_quat;
  5083. yaw_quat.setAngleAxis(yaw, 0.f, 0.f, 1.f);
  5084. LLQuaternion new_quat = pitch_quat * yaw_quat;
  5085. skyp->setSunRotation(new_quat);
  5086. skyp->update();
  5087. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5088. }
  5089. else if (command == "moonazim" || command == "moonazimuth")
  5090. {
  5091. val -= F_TWO_PI * floorf((val + F_PI) / F_TWO_PI);
  5092. LLQuaternion orig_quat = skyp->getMoonRotation();
  5093. F32 roll, pitch, yaw;
  5094. orig_quat.getEulerAngles(&roll, &pitch, &yaw);
  5095. LLQuaternion rotation_world;
  5096. rotation_world.setEulerAngles(0.f, 0.f, val - yaw);
  5097. rotation_world.normalize();
  5098. LLQuaternion new_quat = orig_quat * rotation_world;
  5099. skyp->setMoonRotation(new_quat);
  5100. skyp->update();
  5101. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5102. }
  5103. else if (command == "moonelev" || command == "moonelevation")
  5104. {
  5105. val = -llclamp(val, -F_PI_BY_TWO, F_PI_BY_TWO);
  5106. LLQuaternion orig_quat = skyp->getMoonRotation();
  5107. F32 roll, pitch, yaw;
  5108. orig_quat.getEulerAngles(&roll, &pitch, &yaw);
  5109. LLQuaternion pitch_quat;
  5110. pitch_quat.setAngleAxis(val, 0.f, 1.f, 0.f);
  5111. LLQuaternion yaw_quat;
  5112. yaw_quat.setAngleAxis(yaw, 0.f, 0.f, 1.f);
  5113. LLQuaternion new_quat = pitch_quat * yaw_quat;
  5114. skyp->setMoonRotation(new_quat);
  5115. skyp->update();
  5116. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5117. }
  5118. #if 0 // *TODO: implement the EE approximation
  5119. else if (command == "sunmoonposition")
  5120. {
  5121. }
  5122. else if (command == "eastangle")
  5123. {
  5124. }
  5125. #endif
  5126. else if (command == "starbrightness")
  5127. {
  5128. skyp->setStarBrightness(val);
  5129. skyp->update();
  5130. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5131. }
  5132. else if (command == "cloudcolorr")
  5133. {
  5134. LLColor3 cloudcolor = skyp->getCloudColor();
  5135. cloudcolor.mV[0] = val;
  5136. skyp->setCloudColor(cloudcolor);
  5137. skyp->update();
  5138. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5139. }
  5140. else if (command == "cloudcolorg")
  5141. {
  5142. LLColor3 cloudcolor = skyp->getCloudColor();
  5143. cloudcolor.mV[1] = val;
  5144. skyp->setCloudColor(cloudcolor);
  5145. skyp->update();
  5146. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5147. }
  5148. else if (command == "cloudcolorb")
  5149. {
  5150. LLColor3 cloudcolor = skyp->getCloudColor();
  5151. cloudcolor.mV[2] = val;
  5152. skyp->setCloudColor(cloudcolor);
  5153. skyp->update();
  5154. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5155. }
  5156. else if (command == "cloudcolori")
  5157. {
  5158. LLColor3 cloudcolor = skyp->getCloudColor();
  5159. F32 old_intensity = llmax(cloudcolor.mV[0], cloudcolor.mV[1],
  5160. cloudcolor.mV[2]);
  5161. if (val == 0.f || old_intensity == 0.f)
  5162. {
  5163. cloudcolor.mV[0] = cloudcolor.mV[1] = cloudcolor.mV[2] = val;
  5164. }
  5165. else
  5166. {
  5167. F32 factor = val / old_intensity;
  5168. cloudcolor.mV[0] *= factor;
  5169. cloudcolor.mV[1] *= factor;
  5170. cloudcolor.mV[2] *= factor;
  5171. }
  5172. skyp->setCloudColor(cloudcolor);
  5173. skyp->update();
  5174. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5175. }
  5176. else if (command == "cloudcolor")
  5177. {
  5178. std::deque<std::string> tokens = parse(option, ";");
  5179. F32 r = atof(tokens[0].c_str());
  5180. F32 g = atof(tokens[1].c_str());
  5181. F32 b = atof(tokens[2].c_str());
  5182. LLColor3 cloudcolor = skyp->getCloudColor();
  5183. cloudcolor.mV[0] = r;
  5184. cloudcolor.mV[1] = g;
  5185. cloudcolor.mV[2] = b;
  5186. skyp->setCloudColor(cloudcolor);
  5187. skyp->update();
  5188. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5189. }
  5190. else if (command == "cloudx" || command == "clouddensityx")
  5191. {
  5192. LLColor3 clouddetail = skyp->getCloudPosDensity1();
  5193. clouddetail.mV[0] = val;
  5194. skyp->setCloudPosDensity1(clouddetail);
  5195. skyp->update();
  5196. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5197. }
  5198. else if (command == "cloudy" || command == "clouddensityy")
  5199. {
  5200. LLColor3 clouddetail = skyp->getCloudPosDensity1();
  5201. clouddetail.mV[1] = val;
  5202. skyp->setCloudPosDensity1(clouddetail);
  5203. skyp->update();
  5204. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5205. }
  5206. else if (command == "cloudd" || command == "clouddensityd")
  5207. {
  5208. LLColor3 clouddetail = skyp->getCloudPosDensity1();
  5209. clouddetail.mV[2] = val;
  5210. skyp->setCloudPosDensity1(clouddetail);
  5211. skyp->update();
  5212. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5213. }
  5214. else if (command == "cloud" || command == "clouddensity")
  5215. {
  5216. std::deque<std::string> tokens = parse(option, ";");
  5217. F32 r = atof(tokens[0].c_str());
  5218. F32 g = atof(tokens[1].c_str());
  5219. F32 b = atof(tokens[2].c_str());
  5220. LLColor3 clouddetail = skyp->getCloudPosDensity1();
  5221. clouddetail.mV[0] = r;
  5222. clouddetail.mV[1] = g;
  5223. clouddetail.mV[2] = b;
  5224. skyp->setCloudPosDensity1(clouddetail);
  5225. skyp->update();
  5226. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5227. }
  5228. else if (command == "clouddetailx")
  5229. {
  5230. LLColor3 clouddetail = skyp->getCloudPosDensity2();
  5231. clouddetail.mV[0] = val;
  5232. skyp->setCloudPosDensity2(clouddetail);
  5233. skyp->update();
  5234. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5235. }
  5236. else if (command == "clouddetaily")
  5237. {
  5238. LLColor3 clouddetail = skyp->getCloudPosDensity2();
  5239. clouddetail.mV[1] = val;
  5240. skyp->setCloudPosDensity2(clouddetail);
  5241. skyp->update();
  5242. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5243. }
  5244. else if (command == "clouddetaild")
  5245. {
  5246. LLColor3 clouddetail = skyp->getCloudPosDensity2();
  5247. clouddetail.mV[2] = val;
  5248. skyp->setCloudPosDensity2(clouddetail);
  5249. skyp->update();
  5250. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5251. }
  5252. else if (command == "clouddetail")
  5253. {
  5254. std::deque<std::string> tokens = parse(option, ";");
  5255. F32 r = atof(tokens[0].c_str());
  5256. F32 g = atof(tokens[1].c_str());
  5257. F32 b = atof(tokens[2].c_str());
  5258. LLColor3 clouddetail = skyp->getCloudPosDensity2();
  5259. clouddetail.mV[0] = r;
  5260. clouddetail.mV[1] = g;
  5261. clouddetail.mV[2] = b;
  5262. skyp->setCloudPosDensity2(clouddetail);
  5263. skyp->update();
  5264. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5265. }
  5266. else if (command == "cloudcoverage")
  5267. {
  5268. skyp->setCloudShadow(val);
  5269. skyp->update();
  5270. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5271. }
  5272. else if (command == "cloudscale")
  5273. {
  5274. skyp->setCloudScale(val);
  5275. skyp->update();
  5276. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5277. }
  5278. else if (command == "cloudvariance")
  5279. {
  5280. skyp->setCloudVariance(val);
  5281. skyp->update();
  5282. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5283. }
  5284. else if (command == "cloudscrollx")
  5285. {
  5286. skyp->setCloudScrollRateX(val + 10.f);
  5287. skyp->update();
  5288. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5289. }
  5290. else if (command == "cloudscrolly")
  5291. {
  5292. skyp->setCloudScrollRateY(val + 10.f);
  5293. skyp->update();
  5294. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5295. }
  5296. else if (command == "cloudscroll")
  5297. {
  5298. std::deque<std::string> tokens = parse(option, ";");
  5299. F32 x = atof(tokens[0].c_str()) + 10.f;
  5300. F32 y = atof(tokens[1].c_str()) + 10.f;
  5301. skyp->setCloudScrollRateX(x + 10.f);
  5302. skyp->setCloudScrollRateY(y + 10.f);
  5303. skyp->update();
  5304. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5305. }
  5306. else if (command == "moisturelevel")
  5307. {
  5308. skyp->setSkyMoistureLevel(val);
  5309. skyp->update();
  5310. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5311. }
  5312. else if (command == "dropletradius")
  5313. {
  5314. skyp->setSkyDropletRadius(val);
  5315. skyp->update();
  5316. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5317. }
  5318. else if (command == "icelevel")
  5319. {
  5320. skyp->setSkyDropletRadius(val);
  5321. skyp->update();
  5322. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5323. }
  5324. else if (command == "sunscale")
  5325. {
  5326. skyp->setSunScale(val);
  5327. skyp->update();
  5328. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5329. }
  5330. else if (command == "moonscale")
  5331. {
  5332. skyp->setMoonScale(val);
  5333. skyp->update();
  5334. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5335. }
  5336. else if (command == "moonbrightness")
  5337. {
  5338. skyp->setMoonBrightness(val);
  5339. skyp->update();
  5340. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5341. }
  5342. else if (command == "sunimage" || command == "suntexture")
  5343. {
  5344. LLUUID id;
  5345. id.set(option, false);
  5346. skyp->setSunTextureId(id);
  5347. skyp->update();
  5348. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5349. }
  5350. else if (command == "moonimage" || command == "moontexture")
  5351. {
  5352. LLUUID id;
  5353. id.set(option, false);
  5354. skyp->setMoonTextureId(id);
  5355. skyp->update();
  5356. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5357. }
  5358. else if (command == "cloudimage" || command == "cloudtexture")
  5359. {
  5360. LLUUID id;
  5361. id.set(option, false);
  5362. skyp->setCloudNoiseTextureId(id);
  5363. skyp->update();
  5364. gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
  5365. }
  5366. else if (command == "preset" || command == "asset")
  5367. {
  5368. // This is an extension to RLV's API, allowing to choose what type of
  5369. // setting to search for: e.g. @setenv_preset:sky|blizzard=force will
  5370. // search for "blizzard" in sky settings only. An especially useful
  5371. // case is when a setting name is shared by all types, like "Default",
  5372. // e.g. @setenv_preset:day|default=force will load the default day
  5373. // setting.
  5374. // The pipe ('|') was chosen as a separator, because it is an illegal
  5375. // character for inventory assets names and file names.
  5376. bool skies = true;
  5377. bool days = true;
  5378. bool waters = true;
  5379. size_t i = option.find('|');
  5380. if (i != std::string::npos && i < option.size() - 1)
  5381. {
  5382. std::string category = option.substr(0, i);
  5383. option.erase(0, i);
  5384. skies = category == "sky";
  5385. days = category == "day";
  5386. waters = category == "water";
  5387. }
  5388. // Apply any preset matching the name in 'option' (ignoring case), be
  5389. // it an inventory setting, a Windlight setting, sky, day or water
  5390. // setting (in this order of preferences). When successfully loaded,
  5391. // the preset will be converted to EE settings and Windlight overriding
  5392. // is enabled if it was not in force already.
  5393. if ((skies && LLEnvSettingsSky::applyPresetByName(option, true)) ||
  5394. (days && LLEnvSettingsDay::applyPresetByName(option, true)) ||
  5395. (waters && LLEnvSettingsWater::applyPresetByName(option, true)))
  5396. {
  5397. mLastLoadedPreset = option;
  5398. }
  5399. }
  5400. return true;
  5401. }
  5402. std::string RLInterface::getEnvironment(std::string command)
  5403. {
  5404. F32 res = 0.f;
  5405. constexpr size_t length = 7; // Size of "getenv_"
  5406. command = command.substr(length);
  5407. const LLSettingsSky::ptr_t& skyp = gEnvironment.getCurrentSky();
  5408. if (command == "daytime")
  5409. {
  5410. static LLCachedControl<bool> estate(gSavedSettings, "UseWLEstateTime");
  5411. if (gSavedSettings.getBool("UseParcelEnvironment"))
  5412. {
  5413. res = -1.f;
  5414. }
  5415. else if (skyp->getIsSunUp())
  5416. {
  5417. res = 1.f;
  5418. }
  5419. }
  5420. else if (command == "bluehorizonr")
  5421. {
  5422. res = skyp->getBlueHorizon().mV[0] * 0.5f;
  5423. }
  5424. else if (command == "bluehorizong")
  5425. {
  5426. res = skyp->getBlueHorizon().mV[1] * 0.5f;
  5427. }
  5428. else if (command == "bluehorizonb")
  5429. {
  5430. res = skyp->getBlueHorizon().mV[2] * 0.5f;
  5431. }
  5432. else if (command == "bluehorizoni")
  5433. {
  5434. LLColor3 bluehorizon = skyp->getBlueHorizon();
  5435. res = llmax(bluehorizon.mV[0], bluehorizon.mV[1], bluehorizon.mV[2]) *
  5436. 0.5f;
  5437. }
  5438. else if (command == "bluehorizon")
  5439. {
  5440. std::stringstream str;
  5441. str << skyp->getBlueHorizon().mV[0] * 0.5f << ";";
  5442. str << skyp->getBlueHorizon().mV[1] * 0.5f << ";";
  5443. str << skyp->getBlueHorizon().mV[2] * 0.5f;
  5444. return str.str();
  5445. }
  5446. else if (command == "bluedensityr")
  5447. {
  5448. res = skyp->getBlueDensity().mV[0] * 0.5f;
  5449. }
  5450. else if (command == "bluedensityg")
  5451. {
  5452. res = skyp->getBlueDensity().mV[1] * 0.5f;
  5453. }
  5454. else if (command == "bluedensityb")
  5455. {
  5456. res = skyp->getBlueDensity().mV[2] * 0.5f;
  5457. }
  5458. else if (command == "bluedensityi")
  5459. {
  5460. LLColor3 bluedensity = skyp->getBlueDensity();
  5461. res = llmax(bluedensity.mV[0], bluedensity.mV[1], bluedensity.mV[2]) *
  5462. 0.5f;
  5463. }
  5464. else if (command == "bluedensity")
  5465. {
  5466. std::stringstream str;
  5467. str << skyp->getBlueDensity().mV[0] * 0.5f << ";";
  5468. str << skyp->getBlueDensity().mV[1] * 0.5f << ";";
  5469. str << skyp->getBlueDensity().mV[2] * 0.5f;
  5470. return str.str();
  5471. }
  5472. else if (command == "hazehorizon")
  5473. {
  5474. res = skyp->getHazeHorizon();
  5475. }
  5476. else if (command == "hazedensity")
  5477. {
  5478. res = skyp->getHazeDensity() * 0.25f;
  5479. }
  5480. else if (command == "densitymultiplier")
  5481. {
  5482. res = skyp->getDensityMultiplier() * 1000.f;
  5483. }
  5484. else if (command == "distancemultiplier")
  5485. {
  5486. res = skyp->getDistanceMultiplier();
  5487. }
  5488. else if (command == "maxaltitude")
  5489. {
  5490. res = skyp->getMaxY();
  5491. }
  5492. else if (command == "sunmooncolorr")
  5493. {
  5494. res = skyp->getSunlightColor().mV[0] / 3.f;
  5495. }
  5496. else if (command == "sunmooncolorg")
  5497. {
  5498. res = skyp->getSunlightColor().mV[1] / 3.f;
  5499. }
  5500. else if (command == "sunmooncolorb")
  5501. {
  5502. res = skyp->getSunlightColor().mV[2] / 3.f;
  5503. }
  5504. else if (command == "sunmooncolori")
  5505. {
  5506. LLColor3 sunlightcolor = skyp->getSunlightColor();
  5507. res = llmax(sunlightcolor.mV[0],sunlightcolor.mV[1],
  5508. sunlightcolor.mV[2]) / 3.f;
  5509. }
  5510. else if (command == "sunmooncolor")
  5511. {
  5512. std::stringstream str;
  5513. str << skyp->getSunlightColor().mV[0] / 3.f << ";";
  5514. str << skyp->getSunlightColor().mV[1] / 3.f << ";";
  5515. str << skyp->getSunlightColor().mV[2] / 3.f;
  5516. return str.str();
  5517. }
  5518. else if (command == "ambientr")
  5519. {
  5520. res = skyp->getAmbientColor().mV[0] / 3.f;
  5521. }
  5522. else if (command == "ambientg")
  5523. {
  5524. res = skyp->getAmbientColor().mV[1] / 3.f;
  5525. }
  5526. else if (command == "ambientb")
  5527. {
  5528. res = skyp->getAmbientColor().mV[2] / 3.f;
  5529. }
  5530. else if (command == "ambienti")
  5531. {
  5532. LLColor3 ambientcolor = skyp->getAmbientColor();
  5533. res = llmax(ambientcolor.mV[0], ambientcolor.mV[1],
  5534. ambientcolor.mV[2]) / 3.f;
  5535. }
  5536. else if (command == "ambient")
  5537. {
  5538. std::stringstream str;
  5539. str << skyp->getAmbientColor().mV[0] / 3.f << ";";
  5540. str << skyp->getAmbientColor().mV[1] / 3.f << ";";
  5541. str << skyp->getAmbientColor().mV[2] / 3.f;
  5542. return str.str();
  5543. }
  5544. else if (command == "sunglowfocus")
  5545. {
  5546. res = -skyp->getGlow().mV[2] / 5.f;
  5547. }
  5548. else if (command == "sunglowsize")
  5549. {
  5550. res = 2.f - skyp->getGlow().mV[0] / 20.f;
  5551. }
  5552. else if (command == "scenegamma")
  5553. {
  5554. res = skyp->getGamma();
  5555. }
  5556. else if (command == "sunazim" || command == "sunazimuth")
  5557. {
  5558. LLQuaternion orig_quat = skyp->getSunRotation();
  5559. F32 roll, pitch;
  5560. orig_quat.getEulerAngles(&roll, &pitch, &res);
  5561. }
  5562. else if (command == "sunelev" || command == "sunelevation")
  5563. {
  5564. LLQuaternion orig_quat = skyp->getSunRotation();
  5565. F32 roll, pitch, yaw;
  5566. orig_quat.getEulerAngles(&roll, &pitch, &yaw);
  5567. LLQuaternion rotation_world;
  5568. rotation_world.setEulerAngles(0.f, 0.f, -yaw);
  5569. rotation_world.normalize();
  5570. LLQuaternion new_quat = orig_quat * rotation_world;
  5571. new_quat.getEulerAngles(&roll, &pitch, &yaw);
  5572. if (roll <= -F_PI_BY_TWO || roll >= F_PI_BY_TWO)
  5573. {
  5574. pitch = -pitch;
  5575. }
  5576. res = -pitch;
  5577. }
  5578. else if (command == "moonazim" || command == "moonazimuth")
  5579. {
  5580. LLQuaternion orig_quat = skyp->getMoonRotation();
  5581. F32 roll, pitch;
  5582. orig_quat.getEulerAngles(&roll, &pitch, &res);
  5583. }
  5584. else if (command == "moonelev" || command == "moonelevation")
  5585. {
  5586. LLQuaternion orig_quat = skyp->getMoonRotation();
  5587. F32 roll, pitch, yaw;
  5588. orig_quat.getEulerAngles(&roll, &pitch, &yaw);
  5589. LLQuaternion rotation_world;
  5590. rotation_world.setEulerAngles(0.f, 0.f, -yaw);
  5591. rotation_world.normalize();
  5592. LLQuaternion new_quat = orig_quat * rotation_world;
  5593. new_quat.getEulerAngles(&roll, &pitch, &yaw);
  5594. if (roll <= -F_PI_BY_TWO || roll >= F_PI_BY_TWO)
  5595. {
  5596. pitch = -pitch;
  5597. }
  5598. res = -pitch;
  5599. }
  5600. #if 0 // *TODO: implement the EE approximations
  5601. else if (command == "sunmoonposition")
  5602. {
  5603. }
  5604. else if (command == "eastangle")
  5605. {
  5606. }
  5607. #endif
  5608. else if (command == "starbrightness")
  5609. {
  5610. res = skyp->getStarBrightness();
  5611. }
  5612. else if (command == "cloudcolorr")
  5613. {
  5614. res = skyp->getCloudColor().mV[0];
  5615. }
  5616. else if (command == "cloudcolorg")
  5617. {
  5618. res = skyp->getCloudColor().mV[1];
  5619. }
  5620. else if (command == "cloudcolorb")
  5621. {
  5622. res = skyp->getCloudColor().mV[2];
  5623. }
  5624. else if (command == "cloudcolori")
  5625. {
  5626. LLColor3 cloudcolor = skyp->getCloudColor();
  5627. res = llmax(cloudcolor.mV[0],cloudcolor.mV[1], cloudcolor.mV[2]);
  5628. }
  5629. else if (command == "cloudcolor")
  5630. {
  5631. std::stringstream str;
  5632. str << skyp->getCloudColor().mV[0] << ";";
  5633. str << skyp->getCloudColor().mV[1] << ";";
  5634. str << skyp->getCloudColor().mV[2];
  5635. return str.str();
  5636. }
  5637. else if (command == "cloudx")
  5638. {
  5639. res = skyp->getCloudPosDensity1().mV[0];
  5640. }
  5641. else if (command == "cloudy")
  5642. {
  5643. res = skyp->getCloudPosDensity1().mV[1];
  5644. }
  5645. else if (command == "cloudd")
  5646. {
  5647. res = skyp->getCloudPosDensity1().mV[2];
  5648. }
  5649. else if (command == "cloud")
  5650. {
  5651. std::stringstream str;
  5652. str << skyp->getCloudPosDensity1().mV[0] << ";";
  5653. str << skyp->getCloudPosDensity1().mV[1] << ";";
  5654. str << skyp->getCloudPosDensity1().mV[2];
  5655. return str.str();
  5656. }
  5657. else if (command == "clouddetailx")
  5658. {
  5659. res = skyp->getCloudPosDensity2().mV[0];
  5660. }
  5661. else if (command == "clouddetaily")
  5662. {
  5663. res = skyp->getCloudPosDensity2().mV[1];
  5664. }
  5665. else if (command == "clouddetaild")
  5666. {
  5667. res = skyp->getCloudPosDensity2().mV[2];
  5668. }
  5669. else if (command == "clouddetail")
  5670. {
  5671. std::stringstream str;
  5672. str << skyp->getCloudPosDensity2().mV[0] << ";";
  5673. str << skyp->getCloudPosDensity2().mV[1] << ";";
  5674. str << skyp->getCloudPosDensity2().mV[2];
  5675. return str.str();
  5676. }
  5677. else if (command == "cloudcoverage")
  5678. {
  5679. res = skyp->getCloudShadow();
  5680. }
  5681. else if (command == "cloudscale")
  5682. {
  5683. res = skyp->getCloudScale();
  5684. }
  5685. else if (command == "cloudvariance")
  5686. {
  5687. res = skyp->getCloudVariance();
  5688. }
  5689. else if (command == "cloudscrollx")
  5690. {
  5691. res = skyp->getCloudScrollRate().mV[0] - 10.f;
  5692. }
  5693. else if (command == "cloudscrolly")
  5694. {
  5695. res = skyp->getCloudScrollRate().mV[1] - 10.f;
  5696. }
  5697. else if (command == "cloudscroll")
  5698. {
  5699. std::stringstream str;
  5700. str << skyp->getCloudScrollRate().mV[0] - 10.f << ";";
  5701. str << skyp->getCloudScrollRate().mV[1] - 10.f;
  5702. return str.str();
  5703. }
  5704. else if (command == "moisturelevel")
  5705. {
  5706. res = skyp->getSkyMoistureLevel();
  5707. }
  5708. else if (command == "dropletradius")
  5709. {
  5710. res = skyp->getSkyDropletRadius();
  5711. }
  5712. else if (command == "icelevel")
  5713. {
  5714. res = skyp->getSkyIceLevel();
  5715. }
  5716. else if (command == "sunscale")
  5717. {
  5718. res = skyp->getSunScale();
  5719. }
  5720. else if (command == "moonscale")
  5721. {
  5722. res = skyp->getMoonScale();
  5723. }
  5724. else if (command == "moonbrightness")
  5725. {
  5726. res = skyp->getMoonBrightness();
  5727. }
  5728. else if (command == "sunimage" || command == "suntexture")
  5729. {
  5730. return skyp->getSunTextureId().asString();
  5731. }
  5732. else if (command == "moonimage" || command == "moontexture")
  5733. {
  5734. return skyp->getMoonTextureId().asString();
  5735. }
  5736. else if (command == "cloudimage" || command == "cloudtexture")
  5737. {
  5738. return skyp->getCloudNoiseTextureId().asString();
  5739. }
  5740. else if (command == "preset" || command == "asset")
  5741. {
  5742. return mLastLoadedPreset;
  5743. }
  5744. std::stringstream str;
  5745. str << res;
  5746. return str.str();
  5747. }
  5748. // MK: As some debug settings are critical to the user's experience and others
  5749. // are just useless/not used, we are following a whitelist approach: only allow
  5750. // certain debug settings to be changed and not all.
  5751. bool RLInterface::forceDebugSetting(std::string command, std::string option)
  5752. {
  5753. // Command is "setdebug_<something>"
  5754. constexpr size_t length = 9; // Size of "setdebug_"
  5755. command = command.substr(length); // Remove "setdebug_"
  5756. LLStringUtil::toLower(command);
  5757. // Find the index of the command in the list of allowed commands, ignoring
  5758. // the case
  5759. S32 ind = -1;
  5760. std::string tmp;
  5761. for (S32 i = 0, count = mAllowedSetDebug.size(); i < count; ++i)
  5762. {
  5763. tmp = mAllowedSetDebug[i];
  5764. LLStringUtil::toLower(tmp);
  5765. if (tmp == command)
  5766. {
  5767. ind = i;
  5768. break;
  5769. }
  5770. }
  5771. if (ind == -1)
  5772. {
  5773. return false;
  5774. }
  5775. tmp = mAllowedSetDebug[ind];
  5776. LLControlVariable* control = gSavedSettings.getControl(tmp.c_str());
  5777. if (!control)
  5778. {
  5779. llwarns << tmp
  5780. << " is listed among the modifiable settings, but is was not found in the viewer settings !"
  5781. << llendl;
  5782. return false;
  5783. }
  5784. // Ensure the changed variable will not be saved on log off
  5785. control->setPersist(false);
  5786. switch (control->type())
  5787. {
  5788. case TYPE_U32:
  5789. gSavedSettings.setU32(tmp.c_str(), atoi(option.c_str()));
  5790. break;
  5791. case TYPE_S32:
  5792. gSavedSettings.setS32(tmp.c_str(), atoi(option.c_str()));
  5793. break;
  5794. case TYPE_F32:
  5795. gSavedSettings.setF32(tmp.c_str(), atoi(option.c_str()));
  5796. break;
  5797. case TYPE_BOOLEAN:
  5798. gSavedSettings.setBool(tmp.c_str(), atoi(option.c_str()));
  5799. break;
  5800. case TYPE_STRING:
  5801. gSavedSettings.setString(tmp.c_str(), option);
  5802. break;
  5803. default:
  5804. llwarns << tmp << " type is currently unsuported. Not set."
  5805. << llendl;
  5806. return false;
  5807. }
  5808. return true;
  5809. }
  5810. std::string RLInterface::getDebugSetting(std::string command)
  5811. {
  5812. // Command is "getdebug_<something>"
  5813. constexpr size_t length = 9; // Size of "getdebug_"
  5814. command = command.substr(length); // Remove "getdebug_"
  5815. LLStringUtil::toLower(command);
  5816. // Find the index of the command in the list of allowed commands, ignoring
  5817. // the case
  5818. S32 ind = -1;
  5819. std::string tmp;
  5820. for (S32 i = 0, count = mAllowedGetDebug.size(); i < count; ++i)
  5821. {
  5822. tmp = mAllowedGetDebug[i];
  5823. LLStringUtil::toLower(tmp);
  5824. if (tmp == command)
  5825. {
  5826. ind = i;
  5827. break;
  5828. }
  5829. }
  5830. if (ind == -1)
  5831. {
  5832. return "";
  5833. }
  5834. tmp = mAllowedGetDebug[ind];
  5835. LLControlVariable* control = gSavedSettings.getControl(tmp.c_str());
  5836. if (!control)
  5837. {
  5838. llwarns << tmp
  5839. << " is listed among the modifiable settings, but is was not found in the viewer settings !"
  5840. << llendl;
  5841. return "";
  5842. }
  5843. std::stringstream res;
  5844. switch (control->type())
  5845. {
  5846. case TYPE_U32:
  5847. res << gSavedSettings.getU32(tmp.c_str());
  5848. break;
  5849. case TYPE_S32:
  5850. res << gSavedSettings.getS32(tmp.c_str());
  5851. break;
  5852. case TYPE_F32:
  5853. res << gSavedSettings.getF32(tmp.c_str());
  5854. break;
  5855. case TYPE_BOOLEAN:
  5856. res << gSavedSettings.getBool(tmp.c_str());
  5857. break;
  5858. case TYPE_STRING:
  5859. res << gSavedSettings.getString(tmp.c_str());
  5860. break;
  5861. case TYPE_RECT:
  5862. res << gSavedSettings.getRect(tmp.c_str());
  5863. break;
  5864. case TYPE_COL3:
  5865. res << gSavedSettings.getColor3(tmp.c_str());
  5866. break;
  5867. case TYPE_COL4:
  5868. res << gSavedSettings.getColor4(tmp.c_str());
  5869. break;
  5870. case TYPE_COL4U:
  5871. res << gSavedSettings.getColor4U(tmp.c_str());
  5872. break;
  5873. case TYPE_VEC3:
  5874. res << gSavedSettings.getVector3(tmp.c_str());
  5875. break;
  5876. case TYPE_VEC3D:
  5877. res << gSavedSettings.getVector3d(tmp.c_str());
  5878. break;
  5879. default:
  5880. llwarns << tmp << " type is currently unsuported." << llendl;
  5881. }
  5882. return res.str();
  5883. }
  5884. std::string RLInterface::getFullPath(LLInventoryCategory* cat)
  5885. {
  5886. if (!cat) return "";
  5887. LLInventoryCategory* rlv = getRlvShare();
  5888. if (!rlv) return "";
  5889. LLInventoryCategory* res = cat;
  5890. std::deque<std::string> tokens;
  5891. while (res && res != rlv)
  5892. {
  5893. tokens.push_front(res->getName());
  5894. const LLUUID& parent_id = res->getParentUUID();
  5895. res = gInventory.getCategory(parent_id);
  5896. }
  5897. return dumpList2String(tokens, "/");
  5898. }
  5899. std::string RLInterface::getFullPath(LLInventoryItem* item,
  5900. const std::string& option, bool full_list)
  5901. {
  5902. LL_DEBUGS("RestrainedLove") << "Item: "
  5903. << (item ? item->getName() : "NULL")
  5904. << " - Option: " << option << " - full_list = "
  5905. << full_list << LL_ENDL;
  5906. // Returns the path from the shared root to this object, or to the object
  5907. // worn at the attach point or clothing layer pointed by option if any
  5908. if (!option.empty())
  5909. {
  5910. // An option is specified; we do not want to check the item that issued
  5911. // the command, but something else that is currently worn (object or
  5912. // clothing)
  5913. item = NULL;
  5914. if (LLUUID::validate(option))
  5915. {
  5916. // if option is an UUID, get the path of the viewer object which
  5917. // bears this UUID
  5918. LLUUID id;
  5919. id.set(option, false);
  5920. if (id.notNull())
  5921. {
  5922. // We want the viewer object from the UUID, not the inventory
  5923. // object
  5924. item = getItem(id);
  5925. if (item && isUnderRlvShare(item))
  5926. {
  5927. // We have found the inventory item: add its path to the
  5928. // list.
  5929. // It looks like a recursive call but the recursion level
  5930. // is only 2 for we would not execute this instruction
  5931. // again in the called method since 'option' will be empty.
  5932. std::deque<std::string> res;
  5933. res.emplace_back(getFullPath(item, ""));
  5934. return dumpList2String(res, ",");
  5935. }
  5936. }
  5937. // UUID invalid, item not found, or not shared...
  5938. return "";
  5939. }
  5940. LLWearableType::EType wearable_type;
  5941. wearable_type = getOutfitLayerAsType(option);
  5942. if (wearable_type != LLWearableType::WT_INVALID)
  5943. {
  5944. // this is a clothing layer; replace item with the piece clothing
  5945. std::deque<std::string> res;
  5946. for (U32 i = 0; i < LLAgentWearables::MAX_CLOTHING_LAYERS; ++i)
  5947. {
  5948. const LLUUID& id =
  5949. gAgentWearables.getWearableItemID(wearable_type, i);
  5950. if (id.notNull())
  5951. {
  5952. item = gInventory.getItem(id);
  5953. // Security: we would return the path even if the item was
  5954. // not shared otherwise
  5955. if (item && isUnderRlvShare(item))
  5956. {
  5957. // We have found the inventory item => add its path to
  5958. // the list.
  5959. // It looks like a recursive call but the recursion
  5960. // level is only 2 for we would not execute this
  5961. // instruction again in the called method since
  5962. // 'option' will be empty.
  5963. res.emplace_back(getFullPath(item, ""));
  5964. LL_DEBUGS("RestrainedLove") << "res = "
  5965. << dumpList2String(res, ", ")
  5966. << LL_ENDL;
  5967. if (!full_list)
  5968. {
  5969. // old behaviour: we only return the first folder,
  5970. // not a full list
  5971. break;
  5972. }
  5973. }
  5974. }
  5975. }
  5976. return dumpList2String(res, ",");
  5977. }
  5978. // This is not a clothing layer => it has to be an attachment point
  5979. LLViewerJointAttachment* attach_point =
  5980. findAttachmentPointFromName(option, true);
  5981. if (attach_point)
  5982. {
  5983. std::deque<std::string> res;
  5984. for (U32 i = 0; i < attach_point->mAttachedObjects.size(); ++i)
  5985. {
  5986. LLViewerObject* attached_object =
  5987. attach_point->mAttachedObjects[i];
  5988. if (attached_object)
  5989. {
  5990. item = getItemAux(attached_object, getRlvShare());
  5991. if (item && !isUnderRlvShare(item))
  5992. {
  5993. // Otherwise, we would return the path even if the
  5994. // item is not shared...
  5995. item = NULL;
  5996. }
  5997. else
  5998. {
  5999. // We have found the inventory item => add its path
  6000. // to the list.
  6001. // It looks like a recursive call but the recursion
  6002. // level is only 2 for we would not execute this
  6003. // instruction again in the called method since
  6004. // 'option' will be empty.
  6005. res.emplace_back(getFullPath(item, ""));
  6006. LL_DEBUGS("RestrainedLove") << "res="
  6007. << dumpList2String(res, ", ")
  6008. << LL_ENDL;
  6009. // Old behaviour: we only return the first folder,
  6010. // not a full list
  6011. if (!full_list) break;
  6012. }
  6013. }
  6014. }
  6015. return dumpList2String(res, ",");
  6016. }
  6017. }
  6018. if (!item || !isUnderRlvShare(item))
  6019. {
  6020. // Otherwise, we would return the path even if the item is not shared
  6021. return "";
  6022. }
  6023. LLUUID parent_id = item->getParentUUID();
  6024. LLInventoryCategory* parent_cat = gInventory.getCategory(parent_id);
  6025. if (item->getType() == LLAssetType::AT_OBJECT &&
  6026. !item->getPermissions().allowModifyBy(gAgentID))
  6027. {
  6028. if (findAttachmentPointFromName(parent_cat->getName()))
  6029. {
  6030. // This item is no-mod and its parent folder contains the name of
  6031. // an attach point => probably we want the full path only to the
  6032. // containing folder of that folder
  6033. parent_id = parent_cat->getParentUUID();
  6034. parent_cat = gInventory.getCategory(parent_id);
  6035. return getFullPath(parent_cat);
  6036. }
  6037. }
  6038. return getFullPath(parent_cat);
  6039. }
  6040. // Auxiliary function for getItem()
  6041. LLInventoryItem* RLInterface::getItemAux(LLViewerObject* attached_object,
  6042. LLInventoryCategory* root)
  6043. {
  6044. if (attached_object && root && isAgentAvatarValid())
  6045. {
  6046. LLInventoryModel::cat_array_t* cats;
  6047. LLInventoryModel::item_array_t* items;
  6048. gInventory.getDirectDescendentsOf(root->getUUID(), cats, items);
  6049. // Try to find the item in the current category
  6050. for (S32 i = 0, count = items->size(); i < count; ++i)
  6051. {
  6052. LLInventoryItem* item = (*items)[i];
  6053. if (item &&
  6054. (item->getType() == LLAssetType::AT_OBJECT ||
  6055. item->getType() == LLAssetType::AT_CLOTHING) &&
  6056. gAgentAvatarp->getWornAttachment(item->getUUID()) == attached_object)
  6057. {
  6058. // Found the item in the current category
  6059. return item;
  6060. }
  6061. }
  6062. // We did not find it here => browse the children categories
  6063. for (S32 i = 0, count = cats->size(); i < count; ++i)
  6064. {
  6065. LLInventoryCategory* cat = (*cats)[i];
  6066. LLInventoryItem* item = getItemAux(attached_object, cat);
  6067. if (item)
  6068. {
  6069. return item;
  6070. }
  6071. }
  6072. }
  6073. return NULL;
  6074. }
  6075. // Returns the inventory item corresponding to the viewer object which UUID is
  6076. // "worn_object_id", if any
  6077. LLInventoryItem* RLInterface::getItem(const LLUUID& worn_object_id)
  6078. {
  6079. LLViewerObject* object = gObjectList.findObject(worn_object_id);
  6080. if (object)
  6081. {
  6082. object = object->getRootEdit();
  6083. if (object->isAttachment())
  6084. {
  6085. return gInventory.getItem(object->getAttachmentItemID());
  6086. }
  6087. }
  6088. // This object is not worn => it has nothing to do with any inventory item
  6089. return NULL;
  6090. }
  6091. // Beware: this method does NOT check that the target attach point is already
  6092. // used by a locked item.
  6093. void RLInterface::attachObjectByUUID(const LLUUID& asset_id, S32 attach_pt_num,
  6094. bool kick)
  6095. {
  6096. if (!isAgentAvatarValid()) return;
  6097. LLSD payload;
  6098. payload["item_id"] = asset_id;
  6099. if (!kick && gAgentAvatarp->canAttachMoreObjects())
  6100. {
  6101. payload["attachment_point"] = attach_pt_num | ATTACHMENT_ADD;
  6102. }
  6103. else
  6104. {
  6105. payload["attachment_point"] = attach_pt_num;
  6106. }
  6107. gNotifications.forceResponse(LLNotification::Params("ReplaceAttachment").payload(payload),
  6108. 0 /*YES*/);
  6109. }
  6110. bool RLInterface::canDetachAllSelectedObjects()
  6111. {
  6112. for (LLObjectSelection::iterator iter = gSelectMgr.getSelection()->begin(),
  6113. end = gSelectMgr.getSelection()->end();
  6114. iter != end; ++iter)
  6115. {
  6116. LLViewerObject* object = (*iter)->getObject();
  6117. if (object && !canDetach(object))
  6118. {
  6119. return false;
  6120. }
  6121. }
  6122. return true;
  6123. }
  6124. bool RLInterface::isSittingOnAnySelectedObject()
  6125. {
  6126. if (!isAgentAvatarValid() || !gAgentAvatarp->mIsSitting)
  6127. {
  6128. return false;
  6129. }
  6130. for (LLObjectSelection::iterator iter = gSelectMgr.getSelection()->begin(),
  6131. end = gSelectMgr.getSelection()->end();
  6132. iter != end; ++iter)
  6133. {
  6134. LLViewerObject* object = (*iter)->getObject();
  6135. if (object && object->isAgentSeat())
  6136. {
  6137. return true;
  6138. }
  6139. }
  6140. return false;
  6141. }
  6142. // Returns false if :
  6143. // - at least one object issued a @attachthis:folder restriction
  6144. // - at least one item in this folder is to be worn on an
  6145. // @attachthis:attachpt restriction
  6146. // - at least one piece of clothing in this folder is to be worn on an
  6147. // @attachthis:layer restriction
  6148. // - any parent folder returns false with @attachallthis
  6149. bool RLInterface::canAttachCategory(LLInventoryCategory* folder,
  6150. bool with_exceptions)
  6151. {
  6152. if (!folder || !isAgentAvatarValid()) return true;
  6153. #if RL_ALLOW_ATTACH_DETACH_RECENTLY_RECEIVED_ITEMS
  6154. if (isInventoryFolderNew(folder)) return true;
  6155. #endif
  6156. bool shared = isUnderRlvShare(folder);
  6157. if (!shared || !getRlvShare())
  6158. {
  6159. return !contains("unsharedwear");
  6160. }
  6161. else if (contains("sharedwear"))
  6162. {
  6163. return false;
  6164. }
  6165. return canAttachCategoryAux(folder, false, false, with_exceptions);
  6166. }
  6167. bool RLInterface::canAttachCategoryAux(LLInventoryCategory* folder,
  6168. bool in_parent, bool in_no_mod,
  6169. bool with_exceptions)
  6170. {
  6171. if (!isAgentAvatarValid()) return true;
  6172. EFolderLock folder_lock = FolderNotLocked;
  6173. if (folder)
  6174. {
  6175. // Check @attachthis:folder in all restrictions
  6176. std::string restriction = "attachthis";
  6177. if (in_parent)
  6178. {
  6179. restriction = "attachallthis";
  6180. }
  6181. folder_lock = isFolderLockedWithoutException(folder, "attach");
  6182. if (folder_lock == FolderLockedNoException)
  6183. {
  6184. return false;
  6185. }
  6186. if (!with_exceptions && folder_lock == FolderLockedWithException)
  6187. {
  6188. return false;
  6189. }
  6190. #if 0
  6191. LLInventoryCategory* restricted_cat;
  6192. std::string path_to_check;
  6193. while (it != mSpecialObjectBehaviours.end())
  6194. {
  6195. if (it->second.find(restriction + ":") == 0)
  6196. {
  6197. // Remove ":" as well:
  6198. path_to_check = it->second.substr(restriction.length() + 1);
  6199. restricted_cat = getCategoryUnderRlvShare(path_to_check);
  6200. if (restricted_cat == folder)
  6201. {
  6202. return false;
  6203. }
  6204. }
  6205. ++it;
  6206. }
  6207. #endif
  6208. LLInventoryModel::cat_array_t* cats;
  6209. LLInventoryModel::item_array_t* items;
  6210. gInventory.getDirectDescendentsOf(folder->getUUID(), cats, items);
  6211. // Try to find the item in the current category
  6212. for (S32 i = 0, count = items->size(); i < count; ++i)
  6213. {
  6214. LLInventoryItem* item = (*items)[i];
  6215. if (item)
  6216. {
  6217. if (item->getType() == LLAssetType::AT_OBJECT)
  6218. {
  6219. LLViewerJointAttachment* attachpt = NULL;
  6220. if (in_no_mod)
  6221. {
  6222. if (count > 1 ||
  6223. item->getPermissions().allowModifyBy(gAgentID))
  6224. {
  6225. return true;
  6226. }
  6227. LLInventoryCategory* parent =
  6228. gInventory.getCategory(folder->getParentUUID());
  6229. attachpt = findAttachmentPointFromName(parent->getName());
  6230. }
  6231. else
  6232. {
  6233. attachpt = findAttachmentPointFromName(item->getName());
  6234. }
  6235. if (attachpt &&
  6236. contains(restriction + ":" + attachpt->getName()))
  6237. {
  6238. return false;
  6239. }
  6240. }
  6241. else if (item->getType() == LLAssetType::AT_CLOTHING ||
  6242. item->getType() == LLAssetType::AT_BODYPART)
  6243. {
  6244. LLViewerWearable* wearable =
  6245. gAgentWearables.getWearableFromItemID(item->getLinkedUUID());
  6246. if (wearable &&
  6247. contains(restriction + ":" +
  6248. getOutfitLayerAsString(wearable->getType())))
  6249. {
  6250. return false;
  6251. }
  6252. }
  6253. }
  6254. }
  6255. // Now check all no-mod items => look at the sub-categories and return
  6256. // false if any of them returns false on a call to
  6257. // canAttachCategoryAux()
  6258. for (S32 i = 0, count = cats->size(); i < count; ++i)
  6259. {
  6260. LLInventoryCategory* cat = (*cats)[i];
  6261. if (cat)
  6262. {
  6263. const std::string& name = cat->getName();
  6264. if (!name.empty() && name[0] == '.' &&
  6265. findAttachmentPointFromName(name))
  6266. {
  6267. if (!canAttachCategoryAux(cat, false, true,
  6268. with_exceptions))
  6269. {
  6270. return false;
  6271. }
  6272. }
  6273. }
  6274. }
  6275. }
  6276. if (folder == getRlvShare()) return true;
  6277. if (!in_no_mod && folder_lock == FolderNotLocked)
  6278. {
  6279. // Check for @attachallthis in the parent
  6280. return canAttachCategoryAux(gInventory.getCategory(folder->getParentUUID()),
  6281. true, false, with_exceptions);
  6282. }
  6283. return true;
  6284. }
  6285. // Returns false if:
  6286. // - at least one object contained in this folder issued a @detachthis
  6287. // restriction
  6288. // - at least one object issued a @detachthis:folder restriction
  6289. // - at least one worn attachment in this folder is worn on a
  6290. // @detachthis:attachpt restriction
  6291. // - at least one worn piece of clothing in this folder is worn on a
  6292. // @detachthis:layer restriction
  6293. // - any parent folder returns false with @detachallthis
  6294. bool RLInterface::canDetachCategory(LLInventoryCategory* folder,
  6295. bool with_exceptions)
  6296. {
  6297. if (!folder || !isAgentAvatarValid()) return true;
  6298. if (mHandleNoStrip)
  6299. {
  6300. std::string name = folder->getName();
  6301. LLStringUtil::toLower(name);
  6302. if (name.find(RL_PROTECTED_FOLDER_TAG) != std::string::npos)
  6303. {
  6304. return false;
  6305. }
  6306. }
  6307. #if RL_ALLOW_ATTACH_DETACH_RECENTLY_RECEIVED_ITEMS
  6308. if (isInventoryFolderNew(folder)) return true;
  6309. #endif
  6310. bool shared = isUnderRlvShare(folder);
  6311. if (!shared || !getRlvShare())
  6312. {
  6313. return !contains("unsharedunwear");
  6314. }
  6315. else if (contains("sharedunwear"))
  6316. {
  6317. return false;
  6318. }
  6319. return canDetachCategoryAux(folder, false, false, with_exceptions);
  6320. }
  6321. bool RLInterface::canDetachCategoryAux(LLInventoryCategory* folder,
  6322. bool in_parent, bool in_no_mod,
  6323. bool with_exceptions)
  6324. {
  6325. if (!isAgentAvatarValid()) return true;
  6326. EFolderLock folder_lock = FolderNotLocked;
  6327. if (folder)
  6328. {
  6329. // check @detachthis:folder in all restrictions
  6330. std::string path_to_check;
  6331. std::string restriction = "detachthis";
  6332. if (in_parent)
  6333. {
  6334. restriction = "detachallthis";
  6335. }
  6336. folder_lock = isFolderLockedWithoutException(folder, "detach");
  6337. if (folder_lock == FolderLockedNoException)
  6338. {
  6339. return false;
  6340. }
  6341. if (!with_exceptions && folder_lock == FolderLockedWithException)
  6342. {
  6343. return false;
  6344. }
  6345. #if 0
  6346. LLInventoryCategory* restricted_cat;
  6347. while (it != mSpecialObjectBehaviours.end())
  6348. {
  6349. if (it->second.find(restriction + ":") == 0)
  6350. {
  6351. // remove ":" as well:
  6352. path_to_check = it->second.substr(restriction.length()+1);
  6353. restricted_cat = getCategoryUnderRlvShare(path_to_check);
  6354. if (restricted_cat == folder) return false;
  6355. }
  6356. ++it;
  6357. }
  6358. #endif
  6359. LLInventoryModel::cat_array_t* cats;
  6360. LLInventoryModel::item_array_t* items;
  6361. gInventory.getDirectDescendentsOf(folder->getUUID(), cats, items);
  6362. // Try to find the item in the current category
  6363. for (S32 i = 0, count = items->size(); i < count; ++i)
  6364. {
  6365. LLInventoryItem* item = (*items)[i];
  6366. if (item)
  6367. {
  6368. if (item->getType() == LLAssetType::AT_OBJECT)
  6369. {
  6370. if (in_no_mod)
  6371. {
  6372. if (count > 1 ||
  6373. item->getPermissions().allowModifyBy(gAgentID))
  6374. {
  6375. return true;
  6376. }
  6377. }
  6378. LLViewerObject* attached_object;
  6379. attached_object = gAgentAvatarp->getWornAttachment(item->getLinkedUUID());
  6380. if (attached_object)
  6381. {
  6382. if (!isAllowed(attached_object->getRootEdit()->getID(),
  6383. restriction))
  6384. {
  6385. return false;
  6386. }
  6387. if (!in_parent &&
  6388. !isAllowed(attached_object->getRootEdit()->getID(),
  6389. "detachallthis"))
  6390. {
  6391. // special case for objects contained into this
  6392. // folder and that issued a @detachallthis command
  6393. // without any parameter without issuing a
  6394. // @detachthis command along with it
  6395. return false;
  6396. }
  6397. if (contains(restriction + ":" +
  6398. gAgentAvatarp->getAttachedPointName(item->getLinkedUUID())))
  6399. {
  6400. return false;
  6401. }
  6402. }
  6403. }
  6404. else if (item->getType() == LLAssetType::AT_CLOTHING ||
  6405. item->getType() == LLAssetType::AT_BODYPART)
  6406. {
  6407. LLViewerWearable* wearable;
  6408. wearable = gAgentWearables.getWearableFromItemID(item->getLinkedUUID());
  6409. if (wearable &&
  6410. contains(restriction + ":" +
  6411. getOutfitLayerAsString(wearable->getType())))
  6412. {
  6413. return false;
  6414. }
  6415. }
  6416. }
  6417. }
  6418. // Now check all no-mod items => look at the sub-categories and return
  6419. // false if any of them returns false on a call to
  6420. // canDetachCategoryAux()
  6421. for (S32 i = 0, count = cats->size(); i < count; ++i)
  6422. {
  6423. LLInventoryCategory* cat = (*cats)[i];
  6424. if (cat)
  6425. {
  6426. const std::string& name = cat->getName();
  6427. if (!name.empty() && name[0] == '.' &&
  6428. findAttachmentPointFromName(name))
  6429. {
  6430. if (!canDetachCategoryAux(cat, false, true)) return false;
  6431. }
  6432. }
  6433. }
  6434. }
  6435. if (folder == getRlvShare()) return true;
  6436. if (!in_no_mod && folder_lock == FolderNotLocked)
  6437. {
  6438. // check for @detachallthis in the parent
  6439. return canDetachCategoryAux(gInventory.getCategory(folder->getParentUUID()),
  6440. true, false, with_exceptions);
  6441. }
  6442. return true;
  6443. }
  6444. bool RLInterface::isRestoringOutfit()
  6445. {
  6446. return !gRLenabled || mRestoringOutfit || !isAgentAvatarValid() ||
  6447. gAgentAvatarp->getIsCloud();
  6448. }
  6449. bool RLInterface::canUnwear(LLViewerInventoryItem* item)
  6450. {
  6451. if (item && !isRestoringOutfit())
  6452. {
  6453. if (item->getType() == LLAssetType::AT_OBJECT)
  6454. {
  6455. return canDetach(item);
  6456. }
  6457. if (item->getType() == LLAssetType::AT_CLOTHING ||
  6458. item->getType() == LLAssetType::AT_BODYPART)
  6459. {
  6460. if (!canUnwear(item->getWearableType()))
  6461. {
  6462. return false;
  6463. }
  6464. LLInventoryCategory* parent;
  6465. parent = gInventory.getCategory(item->getParentUUID());
  6466. if (!canDetachCategory(parent))
  6467. {
  6468. return false;
  6469. }
  6470. }
  6471. }
  6472. return true;
  6473. }
  6474. bool RLInterface::canUnwear(LLWearableType::EType type)
  6475. {
  6476. if (!isRestoringOutfit())
  6477. {
  6478. if (contains("remoutfit"))
  6479. {
  6480. return false;
  6481. }
  6482. if (contains("remoutfit:" + getOutfitLayerAsString(type)))
  6483. {
  6484. return false;
  6485. }
  6486. }
  6487. return true;
  6488. }
  6489. bool RLInterface::canWear(LLViewerInventoryItem* item)
  6490. {
  6491. if (item && !isRestoringOutfit())
  6492. {
  6493. #if RL_ALLOW_ATTACH_DETACH_RECENTLY_RECEIVED_ITEMS
  6494. if (isInventoryItemNew(item)) return true;
  6495. #endif
  6496. LLInventoryCategory* parent =
  6497. gInventory.getCategory(item->getParentUUID());
  6498. if (item->getType() == LLAssetType::AT_OBJECT)
  6499. {
  6500. LLViewerJointAttachment* attachpt;
  6501. attachpt = findAttachmentPointFromName(item->getName());
  6502. if (attachpt && !canAttach(NULL, attachpt->getName()))
  6503. {
  6504. return false;
  6505. }
  6506. return canAttachCategory(parent);
  6507. }
  6508. if (item->getType() == LLAssetType::AT_CLOTHING ||
  6509. item->getType() == LLAssetType::AT_BODYPART)
  6510. {
  6511. if (!canWear(item->getWearableType()) ||
  6512. !canAttachCategory(parent))
  6513. {
  6514. return false;
  6515. }
  6516. }
  6517. }
  6518. return true;
  6519. }
  6520. bool RLInterface::canWear(LLWearableType::EType type)
  6521. {
  6522. if (!isRestoringOutfit())
  6523. {
  6524. if (contains("addoutfit"))
  6525. {
  6526. return false;
  6527. }
  6528. if (contains("addoutfit:" + getOutfitLayerAsString(type)))
  6529. {
  6530. return false;
  6531. }
  6532. }
  6533. return true;
  6534. }
  6535. bool RLInterface::canDetach(LLViewerInventoryItem* item)
  6536. {
  6537. if (!item || isRestoringOutfit()) return true;
  6538. if (mHandleNoStrip)
  6539. {
  6540. std::string name = item->getName();
  6541. LLStringUtil::toLower(name);
  6542. if (name.find(RL_PROTECTED_FOLDER_TAG) != std::string::npos)
  6543. {
  6544. return false;
  6545. }
  6546. }
  6547. if (item->getType() == LLAssetType::AT_OBJECT)
  6548. {
  6549. // We will check canDetachCategory() inside this function
  6550. return canDetach(gAgentAvatarp->getWornAttachment(item->getLinkedUUID()));
  6551. }
  6552. else if (item->getType() == LLAssetType::AT_CLOTHING)
  6553. {
  6554. LLInventoryCategory* parentp =
  6555. gInventory.getCategory(item->getParentUUID());
  6556. if (parentp && !canDetachCategory(parentp))
  6557. {
  6558. return false;
  6559. }
  6560. const LLViewerWearable* wearable =
  6561. gAgentWearables.getWearableFromItemID(item->getUUID());
  6562. if (wearable)
  6563. {
  6564. return canUnwear(wearable->getType());
  6565. }
  6566. }
  6567. return true;
  6568. }
  6569. bool RLInterface::canDetach(LLViewerObject* attached_object)
  6570. {
  6571. if (!attached_object || isRestoringOutfit()) return true;
  6572. LLViewerObject* root = attached_object->getRootEdit();
  6573. if (!root) return true;
  6574. // Check all the current restrictions, if "detach" is issued from a child
  6575. // prim of the root prim of attached_object, then the whole object is
  6576. // undetachable
  6577. for (rl_map_it_t it = mSpecialObjectBehaviours.begin(),
  6578. end = mSpecialObjectBehaviours.end();
  6579. it != end; ++it)
  6580. {
  6581. if (it->second == "detach")
  6582. {
  6583. LLViewerObject* this_prim =
  6584. gObjectList.findObject(LLUUID(it->first));
  6585. if (this_prim && this_prim->getRootEdit() == root)
  6586. {
  6587. return false;
  6588. }
  6589. }
  6590. }
  6591. const LLUUID& obj_id = attached_object->getID();
  6592. if (!isAllowed(obj_id, "detach", false) ||
  6593. !isAllowed(obj_id, "detachthis", false) ||
  6594. !isAllowed(obj_id, "detachallthis", false))
  6595. {
  6596. return false;
  6597. }
  6598. LLInventoryItem* item = getItem(root->getID());
  6599. if (item)
  6600. {
  6601. if (mHandleNoStrip)
  6602. {
  6603. std::string name = item->getName();
  6604. LLStringUtil::toLower(name);
  6605. if (name.find(RL_PROTECTED_FOLDER_TAG) != std::string::npos)
  6606. {
  6607. return false;
  6608. }
  6609. }
  6610. #if RL_ALLOW_ATTACH_DETACH_RECENTLY_RECEIVED_ITEMS
  6611. if (isInventoryItemNew(item)) return true;
  6612. #endif
  6613. LLInventoryCategory* parentp =
  6614. gInventory.getCategory(item->getParentUUID());
  6615. if (parentp && !canDetachCategory(parentp)) return false;
  6616. std::string attachpt;
  6617. attachpt = gAgentAvatarp->getAttachedPointName(item->getLinkedUUID());
  6618. if (contains("detach:" + attachpt)) return false;
  6619. if (contains("remattach")) return false;
  6620. if (contains("remattach:" + attachpt)) return false;
  6621. }
  6622. return true;
  6623. }
  6624. bool RLInterface::canDetach(std::string attachpt)
  6625. {
  6626. if (isRestoringOutfit()) return true;
  6627. LLStringUtil::toLower(attachpt);
  6628. if (contains("detach:" + attachpt)) return false;
  6629. if (contains("remattach")) return false;
  6630. if (contains("remattach:" + attachpt)) return false;
  6631. LLViewerJointAttachment* attachment;
  6632. attachment = findAttachmentPointFromName(attachpt, true);
  6633. return canDetachAllObjectsFromAttachment(attachment);
  6634. }
  6635. // Beware: this function does not check if we are replacing and there is a
  6636. // locked object already present on the attachment point
  6637. bool RLInterface::canAttach(LLViewerObject* object_to_attach,
  6638. std::string attachpt)
  6639. {
  6640. if (isRestoringOutfit())
  6641. {
  6642. return true;
  6643. }
  6644. LLStringUtil::toLower(attachpt);
  6645. if (contains("addattach") || contains("addattach:" + attachpt))
  6646. {
  6647. return false;
  6648. }
  6649. if (object_to_attach)
  6650. {
  6651. LLInventoryItem* item =
  6652. getItem(object_to_attach->getRootEdit()->getID());
  6653. if (item)
  6654. {
  6655. #if RL_ALLOW_ATTACH_DETACH_RECENTLY_RECEIVED_ITEMS
  6656. if (isInventoryItemNew(item)) return true;
  6657. #endif
  6658. LLInventoryCategory* parentp =
  6659. gInventory.getCategory(item->getParentUUID());
  6660. if (parentp && !canAttachCategory(parentp))
  6661. {
  6662. return false;
  6663. }
  6664. }
  6665. }
  6666. return true;
  6667. }
  6668. bool RLInterface::canAttach(LLViewerInventoryItem* item)
  6669. {
  6670. if (!item || isRestoringOutfit()) return true;
  6671. #if RL_ALLOW_ATTACH_DETACH_RECENTLY_RECEIVED_ITEMS
  6672. if (isInventoryItemNew(item)) return true;
  6673. #endif
  6674. if (contains("addattach")) return false;
  6675. LLViewerJointAttachment* attachpt;
  6676. attachpt = findAttachmentPointFromName(item->getName());
  6677. if (attachpt && contains("addattach:" + attachpt->getName())) return false;
  6678. LLInventoryCategory* parentp =
  6679. gInventory.getCategory(item->getParentUUID());
  6680. return !parentp || canAttachCategory(parentp);
  6681. }
  6682. bool RLInterface::canStartIM(const LLUUID& to_id)
  6683. {
  6684. std::string id_str = to_id.asString();
  6685. return !contains("startimto:" + id_str) &&
  6686. !containsWithoutException("startim", id_str);
  6687. }
  6688. bool RLInterface::canSendIM(const LLUUID& to_id)
  6689. {
  6690. std::string id_str = to_id.asString();
  6691. return !contains("sendimto:" + id_str) &&
  6692. !containsWithoutException("sendim", id_str);
  6693. }
  6694. bool RLInterface::canReceiveIM(const LLUUID& from_id)
  6695. {
  6696. std::string id_str = from_id.asString();
  6697. return !contains("recvimfrom:" + id_str) &&
  6698. !containsWithoutException("recvim", id_str);
  6699. }
  6700. bool RLInterface::canSendGroupIM(std::string group_name)
  6701. {
  6702. // Remove any separators from the group name
  6703. LLStringUtil::replaceString(group_name, ",", "");
  6704. LLStringUtil::replaceString(group_name, ";", "");
  6705. return !((contains("sendimto:allgroups") &&
  6706. contains("sendimto:" + group_name)) ||
  6707. containsWithoutException("sendim", "allgroups") ||
  6708. containsWithoutException("sendim", group_name));
  6709. }
  6710. bool RLInterface::canReceiveGroupIM(std::string group_name)
  6711. {
  6712. // Remove any separators from the group name
  6713. LLStringUtil::replaceString(group_name, ",", "");
  6714. LLStringUtil::replaceString(group_name, ";", "");
  6715. return !((contains("recvimfrom:allgroups") &&
  6716. contains("recvimfrom:" + group_name)) ||
  6717. containsWithoutException("recvim", "allgroups") ||
  6718. containsWithoutException("recvim", group_name));
  6719. }
  6720. bool RLInterface::canEdit(LLViewerObject* object)
  6721. {
  6722. if (!object) return false;
  6723. LLViewerObject* root = object->getRootEdit();
  6724. if (!root) return false;
  6725. if (!mContainsEdit)
  6726. {
  6727. return true;
  6728. }
  6729. if (containsWithoutException("edit", root->getID().asString()))
  6730. {
  6731. return false;
  6732. }
  6733. bool is_attachment = object->isAttachment();
  6734. if (is_attachment && contains("editworld"))
  6735. {
  6736. return false;
  6737. }
  6738. if (!is_attachment && contains("editattach"))
  6739. {
  6740. return false;
  6741. }
  6742. if (contains("editobj:" + root->getID().asString()))
  6743. {
  6744. return false;
  6745. }
  6746. return !mContainsInteract || object->isHUDAttachment();
  6747. }
  6748. bool RLInterface::canTouch(LLViewerObject* object,
  6749. LLVector3 pick_intersection)
  6750. {
  6751. if (!object)
  6752. {
  6753. return true;
  6754. }
  6755. LLViewerObject* root = object->getRootEdit();
  6756. if (!root)
  6757. {
  6758. return true;
  6759. }
  6760. // To check the presence of "touchme" on this object, which means that we
  6761. // can touch it
  6762. if (!isAllowed(root->getID(), "touchme"))
  6763. {
  6764. return true;
  6765. }
  6766. bool is_hud = root->isHUDAttachment();
  6767. if (!is_hud && contains("touchall"))
  6768. {
  6769. return false;
  6770. }
  6771. #if 0 // Not implemented
  6772. if (!is_hud && contains("touchallnonhud"))
  6773. {
  6774. return false;
  6775. }
  6776. #endif
  6777. if (is_hud &&
  6778. containsWithoutException("touchhud",
  6779. object->getRootEdit()->getID().asString()))
  6780. {
  6781. return false;
  6782. }
  6783. if (contains("touchthis:" + root->getID().asString()))
  6784. {
  6785. return false;
  6786. }
  6787. if (!canTouchFar(object, pick_intersection))
  6788. {
  6789. return false;
  6790. }
  6791. if (root->isAttachment())
  6792. {
  6793. if (!is_hud)
  6794. {
  6795. if (contains("touchattach")) return false;
  6796. LLInventoryItem* inv_item = getItem(root->getID());
  6797. if (inv_item)
  6798. {
  6799. // This attachment is in my inv => it belongs to me
  6800. if (contains("touchattachself"))
  6801. {
  6802. return false;
  6803. }
  6804. }
  6805. else
  6806. {
  6807. // This attachment is not in my inv => it does not belong to me
  6808. if (contains("touchattachother"))
  6809. {
  6810. return false;
  6811. }
  6812. LLVOAvatar* av = root->getAvatar();
  6813. if (!av ||
  6814. contains("touchattachother:" + av->getID().asString()))
  6815. {
  6816. return false;
  6817. }
  6818. }
  6819. }
  6820. }
  6821. else if (containsWithoutException("touchworld", root->getID().asString()))
  6822. {
  6823. return false;
  6824. }
  6825. return true;
  6826. }
  6827. bool RLInterface::canTouchFar(LLViewerObject* object,
  6828. LLVector3 pick_intersection)
  6829. {
  6830. if (!object || object->isHUDAttachment()) return true;
  6831. if (mContainsInteract) return false;
  6832. LLVector3 pos = object->getPositionRegion();
  6833. if (pick_intersection != LLVector3::zero)
  6834. {
  6835. pos = pick_intersection;
  6836. }
  6837. pos -= gAgent.getPositionAgent();
  6838. F32 dist = pos.length();
  6839. #if 0 // Lift this restriction for now, as there may be cases where we want the
  6840. // avatar to touch something that is beyond their vision range.
  6841. return dist <= mFartouchMax && dist <= mCamDistDrawMax;
  6842. #else
  6843. return dist <= mFartouchMax;
  6844. #endif
  6845. }
  6846. #if RL_ALLOW_ATTACH_DETACH_RECENTLY_RECEIVED_ITEMS
  6847. bool RLInterface::isInventoryFolderNew(LLInventoryCategory* folder)
  6848. {
  6849. return folder && mReceivedInventoryFolders.count(folder->getName()) != 0;
  6850. }
  6851. bool RLInterface::isInventoryItemNew(LLInventoryItem* item)
  6852. {
  6853. if (!item) return false;
  6854. const LLUUID& parent_id = item->getParentUUID();
  6855. LLInventoryCategory* parent = gInventory.getCategory(parent_id);
  6856. return parent && mReceivedInventoryFolders.count(parent->getName()) != 0;
  6857. }
  6858. #endif
  6859. // Updates the min and max values not related to camera and vision restrictions
  6860. void RLInterface::updateLimits()
  6861. {
  6862. mFartouchMax = llmin(getMin("fartouch", EXTREMUM),
  6863. getMin("touchfar", EXTREMUM));
  6864. mSittpMax = getMin("sittp", EXTREMUM);
  6865. mTplocalMax = getMin("tplocal", EXTREMUM);
  6866. }
  6867. // Checks that we are within the imposed limits, forces the camera back into
  6868. // the limits and returns false when not, returns true when the camera is ok.
  6869. bool RLInterface::checkCameraLimits(bool and_correct)
  6870. {
  6871. if (!gAgent.mInitialized)
  6872. {
  6873. return true;
  6874. }
  6875. if (mCamDistMax <= 0.f && !gAgent.cameraMouselook())
  6876. {
  6877. if (and_correct)
  6878. {
  6879. gAgent.changeCameraToMouselook();
  6880. }
  6881. return false;
  6882. }
  6883. else if (mCamDistMin > 0.f && gAgent.cameraMouselook())
  6884. {
  6885. if (and_correct)
  6886. {
  6887. gAgent.changeCameraToDefault();
  6888. }
  6889. return false;
  6890. }
  6891. return true;
  6892. }
  6893. bool RLInterface::updateCameraLimits()
  6894. {
  6895. // Update the min and max
  6896. mShowavsDistMax = getMin("camavdist", EXTREMUM);
  6897. if (mShowavsDistMax < EXTREMUM)
  6898. {
  6899. LLVOAvatar::sUseImpostors = true;
  6900. LLVOAvatar::updateSettings();
  6901. }
  6902. else if (LLStartUp::isLoggedIn())
  6903. {
  6904. LLVOAvatar::updateSettings();
  6905. }
  6906. F32 old_dist_min = mCamDistDrawMin;
  6907. F32 old_dist_max = mCamDistDrawMax;
  6908. F32 old_alpha_min = mCamDistDrawAlphaMin;
  6909. F32 old_alpha_max = mCamDistDrawAlphaMax;
  6910. mCamZoomMax = getMin("camzoommax", EXTREMUM);
  6911. if (mCamZoomMax == 0.f) mCamZoomMax = EXTREMUM;
  6912. mCamZoomMin = getMax("camzoommin", -EXTREMUM);
  6913. if (mCamZoomMin == 0.f) mCamZoomMin = -EXTREMUM;
  6914. // setcam_fovmin and setcam_fovmax set the FOV, i.e. 60°/multiplier;
  6915. // in other words, they are equivalent to camzoommin and camzoommax.
  6916. F32 fovmin = getMax("setcam_fovmin", 0.001f);
  6917. if (fovmin != 0.f && fovmin != 0.001f)
  6918. {
  6919. F32 zoommax_from_fovmin = DEFAULT_FIELD_OF_VIEW / fovmin;
  6920. if (zoommax_from_fovmin < mCamZoomMax)
  6921. {
  6922. mCamZoomMax = zoommax_from_fovmin;
  6923. }
  6924. }
  6925. F32 fovmax = getMin("setcam_fovmax", EXTREMUM);
  6926. if (fovmax != 0.f && fovmax != EXTREMUM)
  6927. {
  6928. F32 zoommin_from_fovmax = DEFAULT_FIELD_OF_VIEW / fovmax;
  6929. if (zoommin_from_fovmax > mCamZoomMin)
  6930. {
  6931. mCamZoomMin = zoommin_from_fovmax;
  6932. }
  6933. }
  6934. mCamDistMax = getMin("camdistmax,setcam_avdistmax", EXTREMUM);
  6935. mCamDistMin = getMax("camdistmin,setcam_avdistmin", -EXTREMUM);
  6936. mCamDistDrawMax = getMin("camdrawmax", EXTREMUM);
  6937. mCamDistDrawMin = getMin("camdrawmin", EXTREMUM);
  6938. mCamDistDrawAlphaMin = getMax("camdrawalphamin", 0.f);
  6939. mCamDistDrawAlphaMax = getMax("camdrawalphamax", 1.f);
  6940. mCamDistDrawColor = getMixedColors("camdrawcolor", LLColor3::black);
  6941. if (mCamDistDrawMin <= 0.4f)
  6942. {
  6943. // So we are sure to render the spheres even when restricted to
  6944. // mouselook
  6945. mCamDistDrawMin = 0.4f;
  6946. }
  6947. if (mCamDistDrawMax < mCamDistDrawMin)
  6948. {
  6949. // Sort the two limits in order
  6950. if (mCamDistDrawMin < EXTREMUM)
  6951. {
  6952. mCamDistDrawMax = mCamDistDrawMin;
  6953. }
  6954. else
  6955. {
  6956. mCamDistDrawMin = mCamDistDrawMax;
  6957. }
  6958. }
  6959. if (mCamDistMax >= mCamDistDrawMin && mCamDistDrawMin < EXTREMUM)
  6960. {
  6961. // Make sure we cannot move the camera outside the minimum render limit
  6962. mCamDistMax = mCamDistDrawMin * 0.75f;
  6963. }
  6964. if (mCamDistMax >= mCamDistDrawMax && mCamDistDrawMax < EXTREMUM)
  6965. {
  6966. // Make sure we cannot move the camera outside the maximum render limit
  6967. mCamDistMax = mCamDistDrawMax * 0.75f;
  6968. }
  6969. if (mCamDistDrawAlphaMax < mCamDistDrawAlphaMin)
  6970. {
  6971. // Make sure the "fog" goes in the right direction
  6972. mCamDistDrawAlphaMax = mCamDistDrawAlphaMin;
  6973. }
  6974. if (mCamZoomMin > mCamZoomMax)
  6975. {
  6976. mCamZoomMin = mCamZoomMax;
  6977. }
  6978. if (mCamDistMin > mCamDistMax)
  6979. {
  6980. mCamDistMin = mCamDistMax;
  6981. }
  6982. if (old_dist_min != mCamDistDrawMin || old_dist_max != mCamDistDrawMax ||
  6983. old_alpha_min != mCamDistDrawAlphaMin ||
  6984. old_alpha_max != mCamDistDrawAlphaMax)
  6985. {
  6986. // Force all the rendering types back to true (and we would not be able
  6987. // to switch them off while the vision is restricted)
  6988. if (mCamDistDrawMin < EXTREMUM || mCamDistDrawMax < EXTREMUM)
  6989. {
  6990. gSavedSettings.setBool("BeaconAlwaysOn", false);
  6991. gPipeline.setAllRenderTypes();
  6992. }
  6993. // Silly hack, but we need to force all textures in world to be updated
  6994. mNeedsVisibilityRefresh = true;
  6995. }
  6996. // Limit the number of gradients to 10 per meter, with 2 as the minimum
  6997. // and 40 as the maximum.
  6998. mCamDistNbGradients =
  6999. llclamp((U32)((mCamDistDrawMax - mCamDistDrawMin) * 10.f), 2U, 40U);
  7000. mVisionRestricted = mCamDistDrawMin < EXTREMUM ||
  7001. mCamDistDrawMax < EXTREMUM;
  7002. // And check the camera is still within the limits
  7003. return checkCameraLimits(true);
  7004. }
  7005. #define UPPER_ALPHA_LIMIT 0.999999f
  7006. // This function returns the effective alpha to set to each step when going
  7007. // from 0.0 to "desired_alpha", so that everything seen through the last layer
  7008. // will be obscured as if it were behind only one layer of desired_alpha,
  7009. // regardless of nb_layers If we have N layers and want a transparency T
  7010. // (T = 1-A), we want to find X so that X**N = T (because combined
  7011. // transparencies multiply), in other words, X = T**(1/N). The problem with
  7012. // this formula is that with a target transparency of 0 (alpha = 1), we would
  7013. // not get any gradient at all so we need to limit the alpha to a maximum that
  7014. // is lower than 1.
  7015. F32 calculateDesiredAlphaPerStep(F32 desired_alpha, S32 nb_layers)
  7016. {
  7017. if (desired_alpha > UPPER_ALPHA_LIMIT)
  7018. {
  7019. desired_alpha = UPPER_ALPHA_LIMIT;
  7020. }
  7021. F64 desired_trans = (F64)(1.f - desired_alpha);
  7022. F64 trans_at_this_step = pow(desired_trans, 1.0 / (F64)nb_layers);
  7023. return (F32)(1.0 - trans_at_this_step);
  7024. }
  7025. // This method draws several big black spheres around the avatar, with various
  7026. // alphas. Alpha goes from mCamDistDrawAlphaMin to mCamDistDrawAlphaMax.
  7027. // Things to remember :
  7028. // - There are two render limits in RLV: min and max (min is a sphere with a
  7029. // variable alpha and max is an opaque sphere).
  7030. // - Render limit min <= render limit max.
  7031. // - If a render limit is <= 1.0, make it 1.0 because we will be forced into
  7032. // mouselook anyway, so it would be better to render the sphere
  7033. // - If a render limit is unspecified (i.e. equal to EXTREMUM), do not render
  7034. // it.
  7035. // - If both render limits are specified and different, render both and several
  7036. // in-between at regular intervals, with a linear interpolation for alpha
  7037. // between mCamDistDrawAlphaMin and mCamDistDrawAlphaMax for each sphere.
  7038. // - There are not too many spheres to render, because stacking alphas make the
  7039. // video card complain.
  7040. void RLInterface::drawRenderLimit(bool force_opaque)
  7041. {
  7042. if (!mVisionRestricted)
  7043. {
  7044. return;
  7045. }
  7046. gGL.setColorMask(true, false);
  7047. gUIProgram.bind();
  7048. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  7049. gGL.matrixMode(LLRender::MM_MODELVIEW);
  7050. gPipeline.disableLights();
  7051. // Calculate the center of the spheres
  7052. LLJoint* ref_joint = getCamDistDrawFromJoint();
  7053. LLVector3 center = ref_joint ? ref_joint->getWorldPosition()
  7054. : gAgent.getPositionAgent();
  7055. static LLCachedControl<U32> policy(gSavedSettings,
  7056. "RenderHighlightSelectionsPolicy");
  7057. // If the inner sphere is opaque, just render it and no other
  7058. // Also make the inner sphere opaque if we are highlighting invisible
  7059. // surfaces or if anything is highlighted by a selection (edit, select or
  7060. // drag and drop).
  7061. if (force_opaque || mCamDistDrawAlphaMin >= UPPER_ALPHA_LIMIT ||
  7062. LLDrawPoolAlpha::sShowDebugAlpha ||
  7063. (policy > 0 && (!gSelectMgr.getSelection()->isEmpty() ||
  7064. gToolDragAndDrop.getCargoCount())))
  7065. {
  7066. drawSphere(center, mCamDistDrawMin, mCamDistDrawColor, 1.f);
  7067. }
  7068. else
  7069. {
  7070. // If the outer sphere is opaque, render it now before switching to
  7071. // blend mode
  7072. bool outer_opaque = mCamDistDrawAlphaMax >= UPPER_ALPHA_LIMIT;
  7073. if (outer_opaque)
  7074. {
  7075. drawSphere(center, mCamDistDrawMax, mCamDistDrawColor, 1.f);
  7076. }
  7077. // Switch to blend mode now
  7078. LLGLEnable gls_blend(GL_BLEND);
  7079. LLGLEnable gls_cull(GL_CULL_FACE);
  7080. LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
  7081. gGL.setColorMask(true, false);
  7082. F32 alpha_step = calculateDesiredAlphaPerStep(mCamDistDrawAlphaMax,
  7083. mCamDistNbGradients);
  7084. // If the outer sphere is not opaque, render it now since we have not
  7085. // before switching to blend mode.
  7086. if (!outer_opaque)
  7087. {
  7088. drawSphere(center, mCamDistDrawMax, mCamDistDrawColor, alpha_step);
  7089. }
  7090. F32 lerp_factor = 1.f / (F32)mCamDistNbGradients;
  7091. for (S32 i = mCamDistNbGradients - 1; i > 0; --i)
  7092. {
  7093. drawSphere(center,
  7094. lerp(mCamDistDrawMin, mCamDistDrawMax,
  7095. (F32)i * lerp_factor),
  7096. mCamDistDrawColor, alpha_step);
  7097. }
  7098. }
  7099. gGL.flush();
  7100. gGL.setColorMask(true, false);
  7101. gUIProgram.unbind();
  7102. mRenderLimitRenderedThisFrame = true;
  7103. }
  7104. void RLInterface::drawSphere(const LLVector3& center, F32 scale,
  7105. const LLColor3& color, F32 alpha)
  7106. {
  7107. if (alpha < 0.001f)
  7108. {
  7109. return; // Sphere is almost invisible, so...
  7110. }
  7111. gGL.pushMatrix();
  7112. gGL.translatef(center[0], center[1], center[2]);
  7113. gGL.scalef(scale, scale, scale);
  7114. LLColor4 color_alpha(color, alpha);
  7115. gGL.color4fv(color_alpha.mV);
  7116. // Render inside only (the camera is not supposed to go outside anyway)
  7117. glCullFace(GL_FRONT);
  7118. gSphere.render();
  7119. glCullFace(GL_BACK);
  7120. gGL.popMatrix();
  7121. }
  7122. LLJoint* RLInterface::getCamDistDrawFromJoint()
  7123. {
  7124. if (!isAgentAvatarValid())
  7125. {
  7126. return NULL;
  7127. }
  7128. if (!mCamDistDrawFromJoint ||
  7129. gAgent.getCameraMode() == CAMERA_MODE_MOUSELOOK)
  7130. {
  7131. return gAgentAvatarp->mHeadp;
  7132. }
  7133. return mCamDistDrawFromJoint;
  7134. }
  7135. S32 RLInterface::avatarVisibility(LLVOAvatar* avatarp)
  7136. {
  7137. // Fastest tests first.
  7138. if (!avatarp)
  7139. {
  7140. return 0;
  7141. }
  7142. if ((mShowavsDistMax == EXTREMUM && mCamDistDrawMax == EXTREMUM) ||
  7143. avatarp->isSelf() || avatarp->isUIAvatar())
  7144. {
  7145. return 1;
  7146. }
  7147. // Get the distance from our agent avatar
  7148. LLVector3d dist_vec = gAgent.getPositionGlobal() -
  7149. gAgent.getPosGlobalFromAgent(avatarp->getCharacterPosition()) -
  7150. gAgent.getPositionGlobal();
  7151. F32 squared_dist = dist_vec.lengthSquared();
  7152. // For camavdist, we always jelly-dollify avatars beyond its distance.
  7153. if (mShowavsDistMax < EXTREMUM &&
  7154. squared_dist > mShowavsDistMax * mShowavsDistMax)
  7155. {
  7156. return -1;
  7157. }
  7158. // For camdrawmax, when the avatar is beyond this distance and the outer
  7159. // sphere is opaque, we do not bother rendering it at all. When the outer
  7160. // sphere is not opaque but ALM is off, we jelly-dollify any avatar beyond
  7161. // this distance since legacy avatars are unaffected by the spheres. HB
  7162. if (mCamDistDrawMax < EXTREMUM &&
  7163. squared_dist > mCamDistDrawMax * mCamDistDrawMax)
  7164. {
  7165. if (mCamDistDrawAlphaMax >= 0.999f)
  7166. {
  7167. return 0;
  7168. }
  7169. return LLPipeline::sRenderDeferred ? 1 : -1;
  7170. }
  7171. return 1;
  7172. }