123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764 |
- /**
- * @file mkrlinterface.cpp
- * @author Marine Kelley (many parts rewritten/expanded by Henri Beauchamp)
- * @brief Implementation of the RLV features
- *
- * RLV Source Code
- * The source code in this file("Source Code") is provided by Marine Kelley
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Marine Kelley. Terms of
- * the GPL can be found in doc/GPL-license.txt in the distribution of the
- * original source of the Second Life Viewer, or online at
- * http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL SOURCE CODE FROM MARINE KELLEY IS PROVIDED "AS IS." MARINE KELLEY
- * MAKES NO WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING
- * ITS ACCURACY, COMPLETENESS OR PERFORMANCE.
- */
- #include "llviewerprecompiledheaders.h"
- #include "mkrlinterface.h"
- #include "llapp.h"
- #include "llcachename.h"
- #include "llregionhandle.h"
- #include "llrenderutils.h" // For gSphere
- #include "llagent.h"
- #include "llagentwearables.h"
- #include "llappearancemgr.h"
- #include "llappviewer.h" // For gFrameTimeSeconds
- #include "lldrawpoolalpha.h"
- #include "llenvironment.h"
- #include "llenvsettings.h"
- #include "llfloaterchat.h"
- #include "hbfloaterrlv.h"
- #include "llfloaterwindlight.h"
- #include "llgesturemgr.h"
- #include "llhudtext.h"
- #include "llinventorybridge.h"
- #include "llpipeline.h"
- #include "llselectmgr.h"
- #include "llsky.h"
- #include "llstartup.h"
- #include "lltracker.h"
- #include "lltooldraganddrop.h"
- #include "hbviewerautomation.h"
- #include "llviewercamera.h"
- #include "llviewercontrol.h"
- #include "llviewerinventory.h"
- #include "llviewerfoldertype.h"
- #include "llviewerjointattachment.h"
- #include "llviewermenu.h"
- #include "llviewermessage.h" // For send_agent_update()
- #include "llviewerobjectlist.h"
- #include "llviewerparcelmgr.h"
- #include "llviewerregion.h"
- #include "llviewertexture.h"
- #include "llviewerwearable.h"
- #include "llvoavatarself.h"
- #include "llworld.h"
- #include "llworldmap.h"
- #include "roles_constants.h"
- RLInterface gRLInterface;
- // Global and static variables initialization.
- bool gRLenabled = true;
- bool RLInterface::sRLNoSetEnv = false;
- bool RLInterface::sUntruncatedEmotes = false;
- bool RLInterface::sCanOoc = true;
- std::string RLInterface::sRecvimMessage;
- std::string RLInterface::sSendimMessage;
- std::string RLInterface::sBlackList;
- std::string RLInterface::sRolePlayBlackList;
- std::string RLInterface::sVanillaBlackList;
- RLInterface::rl_command_map_t RLInterface::sCommandsMap;
- //----------------------------------------------------------------------------
- // Helper functions
- //----------------------------------------------------------------------------
- static std::string dumpList2String(std::deque<std::string> list,
- std::string sep, S32 size = -1)
- {
- if (size < 0)
- {
- size = (S32)list.size();
- }
- std::string res;
- for (S32 i = 0; i < (S32)list.size() && i < size; ++i)
- {
- if (i != 0)
- {
- res += sep;
- }
- res += list[i];
- }
- return res;
- }
- static S32 match(std::deque<std::string> list, std::string str,
- bool& exact_match)
- {
- // does str contain list[0]/list[1]/.../list[n] ?
- // yes => return the size of the list
- // no => try again after removing the last element
- // return 0 if never found
- // exact_match is an output, set to true when strict matching is found,
- // false otherwise.
- U32 size = list.size();
- std::string dump;
- exact_match = false;
- while (size > 0)
- {
- dump = dumpList2String(list, "/", (S32) size);
- if (str == dump)
- {
- exact_match = true;
- return (S32)size;
- }
- else if (str.find(dump) != std::string::npos)
- {
- return (S32)size;
- }
- --size;
- }
- return 0;
- }
- static std::deque<std::string> getSubList(std::deque<std::string> list,
- S32 min, S32 max = -1)
- {
- if (min < 0)
- {
- min = 0;
- }
- if (max < 0)
- {
- max = list.size() - 1;
- }
- std::deque<std::string> res;
- for (S32 i = min; i <= max; ++i)
- {
- res.emplace_back(list[i]);
- }
- return res;
- }
- static bool findMultiple(std::deque<std::string> list, std::string str)
- {
- // returns true if all the tokens in list are contained into str
- U32 size = list.size();
- for (U32 i = 0; i < size; ++i)
- {
- if (str.find(list[i]) == std::string::npos) return false;
- }
- return true;
- }
- static void updateAllHudTexts()
- {
- for (LLHUDText::htobj_list_it_t it = LLHUDText::sTextObjects.begin(),
- end = LLHUDText::sTextObjects.end();
- it != end; ++it)
- {
- LLHUDText* hud_text = *it;
- if (hud_text && !hud_text->mLastMessageText.empty() &&
- hud_text->getDoFade())
- {
- // do not update the floating names of the avatars around
- LLViewerObject* obj = hud_text->getSourceObject();
- if (obj && !obj->isAvatar())
- {
- hud_text->setStringUTF8(hud_text->mLastMessageText);
- }
- }
- }
- }
- static void updateOneHudText(LLUUID id)
- {
- LLViewerObject* obj = gObjectList.findObject(id);
- if (obj && obj->mText.notNull())
- {
- LLHUDText* hud_text = obj->mText.get();
- if (hud_text && !hud_text->mLastMessageText.empty() &&
- hud_text->getDoFade())
- {
- hud_text->setStringUTF8(hud_text->mLastMessageText);
- }
- }
- }
- //----------------------------------------------------------------------------
- // RLInterface() class proper
- //----------------------------------------------------------------------------
- RLInterface::RLInterface()
- : mInventoryFetched(false),
- mAllowCancelTp(true),
- mReattaching(false),
- mReattachTimeout(false),
- mRestoringOutfit(false),
- mSnappingBackToLastStandingLocation(false),
- mSitGroundOnStandUp(false),
- mHasLockedHuds(false),
- mContainsDetach(false),
- mContainsShowinv(false),
- mContainsUnsit(false),
- mContainsStandtp(false),
- mContainsInteract(false),
- mContainsShowworldmap(false),
- mContainsShowminimap(false),
- mContainsShowloc(false),
- mContainsShownames(false),
- mContainsShownametags(false),
- mContainsShowNearby(false),
- mContainsSetenv(false),
- mContainsSetdebug(false),
- mContainsFly(false),
- mContainsEdit(false),
- mContainsRez(false),
- mContainsShowhovertextall(false),
- mContainsShowhovertexthud(false),
- mContainsShowhovertextworld(false),
- mContainsDefaultwear(false),
- mContainsPermissive(false),
- mContainsRun(false),
- mContainsAlwaysRun(false),
- mContainsViewscript(false),
- mContainsCamTextures(false),
- mNeedsVisibilityRefresh(false),
- mContainsTp(false),
- mGotSit(false),
- mGotUnsit(false),
- mSkipAll(false),
- mHandleBackToLastStanding(false),
- mHandleNoStrip(false),
- mHandleNoRelay(false),
- mLastCmdBlacklisted(false),
- mLaunchTimestamp((U32)LLTimer::getEpochSeconds()),
- // Give the garbage collector a moment before even kicking in the first
- // time, in case we are logging in a very laggy place, taking time to rez
- mNextGarbageCollection(30.f),
- mVisionRestricted(false),
- mRenderLimitRenderedThisFrame(false),
- mCamDistNbGradients(10),
- mCamDistDrawFromJoint(NULL),
- mCamZoomMax(EXTREMUM),
- mCamZoomMin(-EXTREMUM),
- mCamDistMax(EXTREMUM),
- mCamDistMin(-EXTREMUM),
- mCamDistDrawMax(EXTREMUM),
- mCamDistDrawMin(EXTREMUM),
- mShowavsDistMax(EXTREMUM),
- mFartouchMax(EXTREMUM),
- mSittpMax(EXTREMUM),
- mTplocalMax(EXTREMUM)
- {
- mAllowedGetDebug.emplace_back("AvatarSex");
- mAllowedGetDebug.emplace_back("RenderResolutionDivisor");
- mAllowedGetDebug.emplace_back("RestrainedLoveForbidGiveToRLV");
- mAllowedGetDebug.emplace_back("RestrainedLoveNoSetEnv");
- // 0 female, 1 male (unreliable: depends on shape)
- mAllowedSetDebug.emplace_back("AvatarSex");
- // To allow simulating blur; default is 1 for no blur
- mAllowedSetDebug.emplace_back("RenderResolutionDivisor");
- mJustDetached.mId.setNull();
- mJustDetached.mName.clear();
- #if 0
- mJustReattached.mId.setNull();
- mJustReattached.mName.clear();
- #endif
- }
- RLInterface::~RLInterface()
- {
- mCamTexturesCustom = NULL;
- }
- // init() must be called at an early stage, to setup all RestrainedLove session
- // variables. It is called from LLAppViewer::init() in llappviewer.cpp. This
- // cannot be done in the constructor for RLInterface, because calling
- // gSavedSettings.get*() at that stage would cause crashes under Windows
- // (working fine under Linux): probably a race condition in constructors.
- //static
- void RLInterface::init()
- {
- // Info commands (not "blacklistable").
- sCommandsMap.emplace("version", RL_INFO);
- sCommandsMap.emplace("versionnew", RL_INFO);
- sCommandsMap.emplace("versionnum", RL_INFO);
- sCommandsMap.emplace("versionnumbl", RL_INFO);
- sCommandsMap.emplace("getcommand", RL_INFO);
- sCommandsMap.emplace("getstatus", RL_INFO);
- sCommandsMap.emplace("getstatusall", RL_INFO);
- sCommandsMap.emplace("getsitid", RL_INFO);
- sCommandsMap.emplace("getoutfit", RL_INFO);
- sCommandsMap.emplace("getattach", RL_INFO);
- sCommandsMap.emplace("getinv", RL_INFO);
- sCommandsMap.emplace("getinvworn", RL_INFO);
- sCommandsMap.emplace("getpath", RL_INFO);
- sCommandsMap.emplace("getpathnew", RL_INFO);
- sCommandsMap.emplace("findfolder", RL_INFO);
- sCommandsMap.emplace("findfolders", RL_INFO);
- sCommandsMap.emplace("getgroup", RL_INFO);
- sCommandsMap.emplace("getdebug_", RL_INFO);
- sCommandsMap.emplace("getenv_", RL_INFO);
- sCommandsMap.emplace("getcam_", RL_INFO);
- // Miscellaneous non-info commands that are not "blacklistable".
- sCommandsMap.emplace("notify", RL_MISCELLANEOUS);
- sCommandsMap.emplace("clear", RL_MISCELLANEOUS);
- sCommandsMap.emplace("detachme%f", RL_MISCELLANEOUS);
- sCommandsMap.emplace("setrot%f", RL_MISCELLANEOUS);
- sCommandsMap.emplace("adjustheight%f", RL_MISCELLANEOUS);
- sCommandsMap.emplace("emote", RL_MISCELLANEOUS);
- sCommandsMap.emplace("relayed", RL_MISCELLANEOUS);
- // Normal commands, "blacklistable".
- // Movement restrictions
- sCommandsMap.emplace("fly", RL_MOVE);
- sCommandsMap.emplace("temprun", RL_MOVE);
- sCommandsMap.emplace("alwaysrun", RL_MOVE);
- sVanillaBlackList += "fly,temprun,alwaysrun,";
- // Chat sending restrictions
- sCommandsMap.emplace("sendchat", RL_SENDCHAT);
- sCommandsMap.emplace("chatshout", RL_SENDCHAT);
- sCommandsMap.emplace("chatnormal", RL_SENDCHAT);
- sCommandsMap.emplace("chatwhisper", RL_SENDCHAT);
- sCommandsMap.emplace("sendgesture", RL_SENDCHAT);
- sVanillaBlackList += "sendchat,chatshout,chatnormal,chatwhisper,sendgesture,";
- // Chat receiving restrictions
- sCommandsMap.emplace("recvchat", RL_RECEIVECHAT);
- sCommandsMap.emplace("recvchat_sec", RL_RECEIVECHAT);
- sCommandsMap.emplace("recvchatfrom", RL_RECEIVECHAT);
- sVanillaBlackList += "recvchat,recvchat_sec,recvchatfrom,";
- // Chat on private channels restrictions
- sCommandsMap.emplace("sendchannel", RL_CHANNEL);
- sCommandsMap.emplace("sendchannel_sec", RL_CHANNEL);
- sCommandsMap.emplace("sendchannel_except", RL_CHANNEL);
- sRolePlayBlackList += "sendchannel,sendchannel_sec,sendchannel_except,";
- sVanillaBlackList += "sendchannel,sendchannel_sec,sendchannel_except,";
- // Chat and emotes redirections
- sCommandsMap.emplace("redirchat", RL_REDIRECTION);
- sCommandsMap.emplace("rediremote", RL_REDIRECTION);
- // Emotes restrictions
- sCommandsMap.emplace("recvemote", RL_EMOTE);
- sCommandsMap.emplace("recvemote_sec", RL_EMOTE);
- sCommandsMap.emplace("recvemotefrom", RL_EMOTE);
- sRolePlayBlackList += "recvemote,recvemote_sec,recvemotefrom,";
- sVanillaBlackList += "recvemote,recvemote_sec,recvemotefrom,";
- // Instant messaging restrictions
- sCommandsMap.emplace("sendim", RL_INSTANTMESSAGE);
- sCommandsMap.emplace("sendim_sec", RL_INSTANTMESSAGE);
- sCommandsMap.emplace("sendimto", RL_INSTANTMESSAGE);
- sCommandsMap.emplace("startim", RL_INSTANTMESSAGE);
- sCommandsMap.emplace("startimto", RL_INSTANTMESSAGE);
- sCommandsMap.emplace("recvim", RL_INSTANTMESSAGE);
- sCommandsMap.emplace("recvim_sec", RL_INSTANTMESSAGE);
- sCommandsMap.emplace("recvimfrom", RL_INSTANTMESSAGE);
- sRolePlayBlackList += "sendim,sendim_sec,sendimto,startim,startimto,recvim,recvim_sec,recvimfrom,";
- sVanillaBlackList += "sendim,sendim_sec,sendimto,startim,startimto,recvim,recvim_sec,recvimfrom,";
- // Teleport restrictions
- sCommandsMap.emplace("tplm", RL_TELEPORT);
- sCommandsMap.emplace("tploc", RL_TELEPORT);
- sCommandsMap.emplace("tplocal", RL_TELEPORT);
- sCommandsMap.emplace("tplure", RL_TELEPORT);
- sCommandsMap.emplace("tplure_sec", RL_TELEPORT);
- sCommandsMap.emplace("sittp", RL_TELEPORT);
- sCommandsMap.emplace("standtp", RL_TELEPORT);
- sCommandsMap.emplace("tpto%f", RL_TELEPORT);
- sCommandsMap.emplace("accepttp", RL_TELEPORT);
- sCommandsMap.emplace("accepttprequest", RL_TELEPORT);
- sCommandsMap.emplace("tprequest", RL_TELEPORT);
- // Note: tpto is used by teleporters: allow
- sVanillaBlackList += "tplm,tploc,tplocal,tplure,tplure_sec,sittp,standtp,accepttp,accepttprequest,tprequest,";
- // Inventory access restrictions
- sCommandsMap.emplace("showinv", RL_INVENTORY);
- sCommandsMap.emplace("viewnote", RL_INVENTORY);
- sCommandsMap.emplace("viewscript", RL_INVENTORY);
- sCommandsMap.emplace("viewtexture", RL_INVENTORY);
- sCommandsMap.emplace("sharedwear", RL_INVENTORYLOCK);
- sCommandsMap.emplace("unsharedwear", RL_INVENTORYLOCK);
- sCommandsMap.emplace("unsharedunwear", RL_INVENTORYLOCK);
- sRolePlayBlackList += "showinv,viewnote,viewscript,viewtexture,sharedwear,unsharedwear,unsharedunwear,";
- sVanillaBlackList += "showinv,viewnote,viewscript,viewtexture,sharedwear,unsharedwear,unsharedunwear,";
- // Building restrictions
- sCommandsMap.emplace("edit", RL_BUILD);
- sCommandsMap.emplace("editattach", RL_BUILD);
- sCommandsMap.emplace("editobj", RL_BUILD);
- sCommandsMap.emplace("editworld", RL_BUILD);
- sCommandsMap.emplace("rez", RL_BUILD);
- sRolePlayBlackList += "edit,editattach,editobj,editworld,rez,";
- sVanillaBlackList += "edit,editattach,editobj,editworld,rez,";
- // Sitting restrictions
- sCommandsMap.emplace("unsit", RL_SIT);
- sCommandsMap.emplace("unsit%f", RL_SIT);
- sCommandsMap.emplace("sit", RL_SIT);
- sCommandsMap.emplace("sit%f", RL_SIT);
- sCommandsMap.emplace("sitground%f", RL_SIT);
- sVanillaBlackList += "unsit,unsit%f,sit,sit%f,sitground%f";
- // Locking commands
- sCommandsMap.emplace("detach", RL_LOCK);
- sCommandsMap.emplace("detachthis", RL_LOCK);
- sCommandsMap.emplace("detachallthis", RL_LOCK);
- sCommandsMap.emplace("detachthis_except", RL_LOCK);
- sCommandsMap.emplace("detachallthis_except", RL_LOCK);
- sCommandsMap.emplace("attachthis", RL_LOCK);
- sCommandsMap.emplace("attachallthis", RL_LOCK);
- sCommandsMap.emplace("attachthis_except", RL_LOCK);
- sCommandsMap.emplace("attachallthis_except", RL_LOCK);
- sCommandsMap.emplace("addattach", RL_LOCK);
- sCommandsMap.emplace("remattach", RL_LOCK);
- sCommandsMap.emplace("addoutfit", RL_LOCK);
- sCommandsMap.emplace("remoutfit", RL_LOCK);
- sCommandsMap.emplace("defaultwear", RL_LOCK);
- sVanillaBlackList += "detach,detachthis,detachallthis,detachthis_except,detachallthis_except,attachthis,attachallthis,attachthis_except,attachallthis_except,addattach,remattach,addoutfit,remoutfit,defaultwear,";
- // Detach/remove commands
- sCommandsMap.emplace("detach%f", RL_DETACH);
- sCommandsMap.emplace("detachall%f", RL_DETACH);
- sCommandsMap.emplace("detachthis%f", RL_DETACH);
- sCommandsMap.emplace("detachallthis%f", RL_DETACH);
- sCommandsMap.emplace("remattach%f", RL_DETACH);
- sCommandsMap.emplace("remoutfit%f", RL_DETACH);
- // Attach/wear commands
- sCommandsMap.emplace("attach%f", RL_ATTACH);
- sCommandsMap.emplace("attachover%f", RL_ATTACH);
- sCommandsMap.emplace("attachoverorreplace%f", RL_ATTACH);
- sCommandsMap.emplace("attachall%f", RL_ATTACH);
- sCommandsMap.emplace("attachallover%f", RL_ATTACH);
- sCommandsMap.emplace("attachalloverorreplace%f", RL_ATTACH);
- sCommandsMap.emplace("attachthis%f", RL_ATTACH);
- sCommandsMap.emplace("attachthisover%f", RL_ATTACH);
- sCommandsMap.emplace("attachthisover%f", RL_ATTACH);
- sCommandsMap.emplace("attachthisoverorreplace%f", RL_ATTACH);
- sCommandsMap.emplace("attachallthis%f", RL_ATTACH);
- sCommandsMap.emplace("attachallthisover%f", RL_ATTACH);
- sCommandsMap.emplace("attachallthisoverorreplace%f", RL_ATTACH);
- // Touch restrictions
- sCommandsMap.emplace("fartouch", RL_TOUCH);
- sCommandsMap.emplace("interact", RL_TOUCH);
- sCommandsMap.emplace("touchfar", RL_TOUCH);
- sCommandsMap.emplace("touchall", RL_TOUCH);
- sCommandsMap.emplace("touchworld", RL_TOUCH);
- sCommandsMap.emplace("touchthis", RL_TOUCH);
- sCommandsMap.emplace("touchme", RL_TOUCH);
- sCommandsMap.emplace("touchattach", RL_TOUCH);
- sCommandsMap.emplace("touchattachself", RL_TOUCH);
- sCommandsMap.emplace("touchhud", RL_TOUCH);
- sCommandsMap.emplace("touchattachother", RL_TOUCH);
- sVanillaBlackList += "fartouch,interact,touchfar,touchall,touchworld,touchthis,touchme,touchattach,touchattachself,touchhud,touchattachother,";
- // Location/mapping restrictions
- sCommandsMap.emplace("showworldmap", RL_LOCATION);
- sCommandsMap.emplace("showminimap", RL_LOCATION);
- sCommandsMap.emplace("showloc", RL_LOCATION);
- sRolePlayBlackList += "showworldmap,showminimap,showloc,";
- sVanillaBlackList += "showworldmap,showminimap,showloc,";
- // Name viewing restrictions
- sCommandsMap.emplace("shownames", RL_NAME);
- sCommandsMap.emplace("shownames_sec", RL_NAME);
- sCommandsMap.emplace("shownametags", RL_NAME);
- sCommandsMap.emplace("shownearby", RL_NAME);
- sCommandsMap.emplace("showhovertextall", RL_NAME);
- sCommandsMap.emplace("showhovertext", RL_NAME);
- sCommandsMap.emplace("showhovertexthud", RL_NAME);
- sCommandsMap.emplace("showhovertextworld", RL_NAME);
- sRolePlayBlackList += "shownames,shownametags,showhovertextall,showhovertext,showhovertexthud,showhovertextworld,";
- sVanillaBlackList += "shownames,shownametags,showhovertextall,showhovertext,showhovertexthud,showhovertextworld,";
- // Group restrictions
- sCommandsMap.emplace("setgroup", RL_GROUP);
- sCommandsMap.emplace("setgroup%f", RL_GROUP);
- sRolePlayBlackList += "setgroup,";
- sVanillaBlackList += "setgroup,"; // @setgroup=force May be used as a helper: allow
- // Sharing restrictions
- sCommandsMap.emplace("share", RL_SHARE);
- sCommandsMap.emplace("share_sec", RL_SHARE);
- sRolePlayBlackList += "share,share_sec,";
- sVanillaBlackList += "share,share_sec,";
- // Permissions/extra-restriction commands.
- sCommandsMap.emplace("permissive", RL_PERM);
- sCommandsMap.emplace("acceptpermission", RL_PERM);
- sVanillaBlackList += "permissive,acceptpermission,";
- // Camera restriction commands.
- sCommandsMap.emplace("camtextures", RL_CAMERA);
- sCommandsMap.emplace("camunlock", RL_CAMERA);
- sCommandsMap.emplace("camzoommax", RL_CAMERA);
- sCommandsMap.emplace("camzoommin", RL_CAMERA);
- sCommandsMap.emplace("camdistmax", RL_CAMERA);
- sCommandsMap.emplace("camdistmin", RL_CAMERA);
- sCommandsMap.emplace("camdrawmax", RL_CAMERA);
- sCommandsMap.emplace("camdrawmin", RL_CAMERA);
- sCommandsMap.emplace("camdrawalphamax", RL_CAMERA);
- sCommandsMap.emplace("camdrawalphamin", RL_CAMERA);
- sCommandsMap.emplace("camdrawcolor", RL_CAMERA);
- sCommandsMap.emplace("camavdist", RL_CAMERA);
- sCommandsMap.emplace("setcam_", RL_CAMERA);
- sCommandsMap.emplace("setcam_fov%f", RL_CAMERA);
- sRolePlayBlackList += "camtextures,camunlock,camzoommax,camzoommin,camdistmax,camdistmin,camdrawmax,camdrawmin,camdrawalphamax,camdrawalphamin,camdrawcolor,camavdist,setcam_,setcam_fov%f,";
- sVanillaBlackList += "camtextures,camunlock,camzoommax,camzoommin,camdistmax,camdistmin,camdrawmax,camdrawmin,camdrawalphamax,camdrawalphamin,camdrawcolor,camavdist,setcam_,setcam_fov%f,";
- // Debug settings commands.
- sCommandsMap.emplace("setdebug", RL_DEBUG);
- sCommandsMap.emplace("setdebug_%f", RL_DEBUG);
- sRolePlayBlackList += "setdebug";
- sVanillaBlackList += "setdebug,setdebug_%f,";
- sVanillaBlackList += "setenv";
- gRLInterface.mCamTexturesCustom = LLViewerFetchedTexture::sDefaultImagep;
- gRLenabled = gSavedSettings.getBool("RestrainedLove");
- if (gRLenabled)
- {
- sRLNoSetEnv = gSavedSettings.getBool("RestrainedLoveNoSetEnv");
- sUntruncatedEmotes =
- gSavedSettings.getBool("RestrainedLoveUntruncatedEmotes");
- sCanOoc = gSavedSettings.getBool("RestrainedLoveCanOoc");
- sBlackList = gSavedSettings.getString("RestrainedLoveBlacklist");
- if (!sRLNoSetEnv)
- {
- sCommandsMap.emplace("setenv", RL_ENVIRONMENT);
- sCommandsMap.emplace("setenv_%f", RL_ENVIRONMENT);
- }
- gRLInterface.updateCameraLimits();
- gRLInterface.updateLimits();
- llinfos << "RestrainedLove enabled and initialized." << llendl;
- }
- }
- //static
- void RLInterface::usePerAccountSettings()
- {
- if (gRLenabled)
- {
- sRecvimMessage =
- gSavedPerAccountSettings.getString("RestrainedLoveRecvimMessage");
- sSendimMessage =
- gSavedPerAccountSettings.getString("RestrainedLoveSendimMessage");
- }
- }
- // Call this function when adding/removing a restriction only, i.e. in this
- // file. Test the cached variables in the code of the viewer itself.
- void RLInterface::refreshCachedVariable(const std::string& var)
- {
- if (!isAgentAvatarValid()) return;
- bool update_names_exceptions = false;
- bool contained = contains(var);
- if (var == "detach" || var.compare(0, 7, "detach:") == 0 ||
- var.compare(0, 9, "addattach") == 0 ||
- var.compare(0, 9, "remattach") == 0)
- {
- contained = contains("detach") || containsSubstr("detach:") ||
- containsSubstr("addattach") || containsSubstr("remattach");
- mContainsDetach = contained;
- mHasLockedHuds = hasLockedHuds();
- if (mHasLockedHuds)
- {
- // To force the viewer to render the HUDs again, just in case
- LLPipeline::sShowHUDAttachments = true;
- }
- if (gUseWireframe && (mHasLockedHuds || mCamDistDrawMax < EXTREMUM))
- {
- handle_toggle_wireframe(NULL);
- }
- }
- else if (var == "showinv")
- {
- mContainsShowinv = contained;
- }
- else if (var == "unsit")
- {
- mContainsUnsit = contained;
- }
- else if (var == "standtp")
- {
- mContainsStandtp = contained;
- }
- else if (var == "interact")
- {
- mContainsInteract = contained;
- }
- else if (var == "showworldmap")
- {
- mContainsShowworldmap = contained;
- }
- else if (var == "showminimap")
- {
- mContainsShowminimap = contained;
- }
- else if (var == "showloc")
- {
- mContainsShowloc = contained;
- }
- else if (var == "shownames" || var == "shownames_sec")
- {
- mContainsShownames = contained;
- update_names_exceptions = true;
- }
- else if (var == "shownametags")
- {
- mContainsShownametags = contained;
- update_names_exceptions = true;
- }
- else if (var == "shownearby")
- {
- mContainsShowNearby = contained;
- }
- else if (var == "setenv")
- {
- mContainsSetenv = contained;
- }
- else if (var == "setdebug")
- {
- mContainsSetdebug = contained;
- }
- else if (var == "fly")
- {
- mContainsFly = contained;
- }
- else if (var == "edit")
- {
- mContainsEdit =
- #if 0
- containsSubstr("editobj") ||
- #endif
- containsWithoutException("edit");
- }
- else if (var == "rez")
- {
- mContainsRez = contained;
- }
- else if (var == "showhovertextall")
- {
- mContainsShowhovertextall = contained;
- }
- else if (var == "showhovertexthud")
- {
- mContainsShowhovertexthud = contained;
- }
- else if (var == "showhovertextworld")
- {
- mContainsShowhovertextworld = contained;
- }
- else if (var == "defaultwear")
- {
- mContainsDefaultwear = contained;
- }
- else if (var == "permissive")
- {
- mContainsPermissive = contained;
- }
- else if (var == "temprun")
- {
- mContainsRun = contained;
- }
- else if (var == "alwaysrun")
- {
- mContainsAlwaysRun = contained;
- }
- else if (var == "viewscript")
- {
- mContainsViewscript = contained;
- }
- else if (var.compare(0, 11, "camtextures") == 0 ||
- var.compare(0, 15, "setcam_textures") == 0)
- {
- mContainsCamTextures = containsSubstr("camtextures") ||
- containsSubstr("setcam_textures");
- // Is there a uuid specified ?
- size_t i = var.find(":");
- if (i != std::string::npos)
- {
- std::string id_str = var.substr(i + 1);
- LLUUID tex_id;
- tex_id.set(id_str, false);
- if (tex_id.notNull())
- {
- mCamTexturesCustom =
- LLViewerTextureManager::getFetchedTexture(tex_id,
- FTT_DEFAULT,
- true,
- LLGLTexture::BOOST_NONE,
- LLViewerTexture::LOD_TEXTURE);
- }
- else
- {
- mCamTexturesCustom = LLViewerFetchedTexture::sDefaultImagep;
- }
- }
- // Silly hack, but we need to force all textures in world to be updated
- mNeedsVisibilityRefresh = true;
- }
- else if (var == "camzoommax" || var == "camzoommin")
- {
- gViewerCamera.setDefaultFOV(gSavedSettings.getF32("CameraAngle"));
- }
- mContainsTp = contains("tplm") || contains("tploc") ||
- contains("tplure") ||
- (mContainsUnsit && gAgentAvatarp->mIsSitting);
- refreshTPflag(true);
- if (update_names_exceptions)
- {
- // Rebuild the list of exceptions for shownames and shownametags
- std::string command, behav, option, param;
- LLUUID avid;
- mExceptions.clear();
- for (rl_map_it_t it = mSpecialObjectBehaviours.begin(),
- end = mSpecialObjectBehaviours.end();
- it != end; ++it)
- {
- command = it->second;
- LLStringUtil::toLower(command);
- if (command.compare(0, 10, "shownames:") == 0 ||
- command.compare(0, 13, "shownames_sec:") == 0 ||
- command.compare(0, 13, "shownametags:") == 0)
- {
- if (parseCommand(command, behav, option, param))
- {
- avid.set(option, false);
- if (avid.notNull())
- {
- mExceptions.emplace(avid);
- }
- }
- }
- }
- }
- }
- void RLInterface::refreshTPflag(bool save)
- {
- static bool last_value =
- gSavedPerAccountSettings.getBool("RestrainedLoveTPOK");
- bool new_value = !mContainsTp;
- if (new_value != last_value)
- {
- last_value = new_value;
- gSavedPerAccountSettings.setBool("RestrainedLoveTPOK", new_value);
- if (save)
- {
- gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"));
- }
- }
- }
- void RLInterface::idleTasks()
- {
- static F32 last_refresh = 0.f;
- if (mNeedsVisibilityRefresh && gFrameTimeSeconds - last_refresh > 1.f)
- {
- handle_objects_visibility(NULL);
- last_refresh = gFrameTimeSeconds;
- mNeedsVisibilityRefresh = false;
- }
- // If RLV share inventory has not been fetched yet, fetch it now
- fetchInventory();
- // Perform some maintenance only if no object is waiting to be reattached
- if (mAssetsToReattach.empty())
- {
- // Fire all the stored commands that we received while initializing
- fireCommands();
- // Fire the garbage collector for orphaned restrictions
- if (gFrameTimeSeconds > mNextGarbageCollection)
- {
- garbageCollector(false);
- mNextGarbageCollection = gFrameTimeSeconds + 30.f;
- }
- }
- // We must check whether there is an object waiting to be reattached after
- // having been kicked off while locked.
- if (!mAssetsToReattach.empty())
- {
- // Get the elapsed time since detached, and the delay before reattach.
- U32 elapsed = (U32)mReattachTimer.getElapsedTimeF32();
- static LLCachedControl<U32> reattach_delay(gSavedSettings,
- "RestrainedLoveReattachDelay");
- // Timeout flag.
- bool timeout = mReattaching && elapsed > 4 * reattach_delay;
- if (timeout)
- {
- // If we timed out, reset the timer and tell the interface...
- mReattachTimer.reset();
- mReattachTimeout = true;
- llwarns << "Timeout reattaching an asset, retrying." << llendl;
- }
- if (!mReattaching || timeout)
- {
- // We are not reattaching an object (or we timed out), so let's see
- // if the delay before auto-reattach has elapsed.
- if (elapsed >= reattach_delay)
- {
- // Let's reattach the object to its default attach point.
- const RLAttachment& at = mAssetsToReattach.front();
- S32 tmp_attachpt_nb = 0;
- LLViewerJointAttachment* attachpt =
- findAttachmentPointFromName(at.mName, true);
- if (attachpt)
- {
- tmp_attachpt_nb = findAttachmentPointNumber(attachpt);
- }
- llinfos << "Reattaching asset " << at.mId << " to point '"
- << at.mName << "' (number " << tmp_attachpt_nb << ")"
- << llendl;
- mReattaching = true;
- attachObjectByUUID(at.mId, tmp_attachpt_nb);
- }
- }
- }
- }
- std::string RLInterface::getVersion()
- {
- return RL_VIEWER_NAME " viewer v" RL_VERSION;
- }
- std::string RLInterface::getVersion2()
- {
- return RL_VIEWER_NAME_NEW " viewer v" RL_VERSION;
- }
- std::string RLInterface::getVersionNum()
- {
- std::string res = RL_VERSION_NUM;
- if (!sBlackList.empty())
- {
- res += "," + sBlackList;
- }
- return res;
- }
- bool RLInterface::isAllowed(LLUUID object_id, std::string action,
- bool log_it)
- {
- if (log_it)
- {
- LL_DEBUGS("RestrainedLove") << object_id << " " << action
- << LL_ENDL;
- }
- rl_map_it_t it = mSpecialObjectBehaviours.find(object_id.asString());
- while (it != mSpecialObjectBehaviours.end() &&
- it != mSpecialObjectBehaviours.upper_bound(object_id.asString()))
- {
- #if 0
- if (log_it)
- {
- LL_DEBUGS("RestrainedLove") << " checking " << it->second
- << LL_ENDL;
- }
- #endif
- if (it->second == action)
- {
- if (log_it)
- {
- LL_DEBUGS("RestrainedLove") << " => forbidden. " << LL_ENDL;
- }
- return false;
- }
- ++it;
- }
- if (log_it)
- {
- LL_DEBUGS("RestrainedLove") << " => allowed. " << LL_ENDL;
- }
- return true;
- }
- bool RLInterface::contains(std::string action)
- {
- LLStringUtil::toLower(action);
- for (rl_map_it_t it = mSpecialObjectBehaviours.begin(),
- end = mSpecialObjectBehaviours.end();
- it != end; ++it)
- {
- if (it->second == action)
- {
- return true;
- }
- }
- return false;
- }
- bool RLInterface::containsSubstr(std::string action)
- {
- LLStringUtil::toLower(action);
- for (rl_map_it_t it = mSpecialObjectBehaviours.begin(),
- end = mSpecialObjectBehaviours.end();
- it != end; ++it)
- {
- if (it->second.find(action) != std::string::npos)
- {
- return true;
- }
- }
- return false;
- }
- bool RLInterface::containsWithoutException(std::string action,
- const std::string& except)
- {
- // 'action' is a restriction like @sendim, which can accept exceptions
- // (@sendim:except_uuid=add)
- // action_sec is the same action, with "_sec" appended (like @sendim_sec)
- LLStringUtil::toLower(action);
- std::string action_sec = action + "_sec";
- LLUUID id;
- // 1. If except is empty, behave like contains(), but looking for both
- // action and action_sec
- if (except.empty())
- {
- return contains(action) || contains(action_sec);
- }
- // 2. For each action_sec, if we do not find an exception tied to the same
- // object, return true. If @permissive is set, then even action needs the
- // exception to be tied to the same object, not just action_sec (@permissive
- // restrains the scope of all the exceptions to their own objects)
- for (rl_map_it_t it = mSpecialObjectBehaviours.begin(),
- end = mSpecialObjectBehaviours.end();
- it != end; ++it)
- {
- if (it->second == action_sec ||
- (it->second == action && mContainsPermissive))
- {
- id.set(it->first);
- // We use isAllowed because we need to check the object, but it
- // really means "does not contain"
- if (isAllowed(id, action + ":" + except, false) &&
- isAllowed(id, action_sec + ":" + except, false))
- {
- return true;
- }
- }
- }
- // 3. If we did not return yet, but the map contains action, just look for
- // except_uuid without regard to its object, if none is found return true
- if (contains(action))
- {
- if (!contains(action + ":" + except) &&
- !contains(action_sec + ":" + except))
- {
- return true;
- }
- }
- // 4. Finally return false if we did not find anything
- return false;
- }
- F32 RLInterface::getMax(std::string action, F32 dflt)
- {
- LLStringUtil::toLower(action);
- // an action may be a comma separated list list of behaviours
- action = "," + action + ",";
- F32 res = -EXTREMUM;
- F32 tmp;
- std::string command, behav, option, param;
- bool found_one = false;
- for (rl_map_it_t it = mSpecialObjectBehaviours.begin(),
- end = mSpecialObjectBehaviours.end();
- it != end; ++it)
- {
- command = it->second;
- LLStringUtil::toLower(command);
- if (parseCommand(command + "=n", behav, option, param))
- {
- if (action.find("," + behav + ",") != std::string::npos)
- {
- if (option.empty())
- {
- tmp = 1.5f;
- }
- else
- {
- tmp = atof(option.c_str());
- }
- if (tmp > res)
- {
- res = tmp;
- found_one = true;
- }
- }
- }
- }
- return found_one ? res : dflt;
- }
- F32 RLInterface::getMin(std::string action, F32 dflt)
- {
- LLStringUtil::toLower(action);
- // An action may be a comma separated list list of behaviours
- action = "," + action + ",";
- F32 res = EXTREMUM;
- F32 tmp;
- std::string command, behav, option, param;
- bool found_one = false;
- for (rl_map_it_t it = mSpecialObjectBehaviours.begin(),
- end = mSpecialObjectBehaviours.end();
- it != end; ++it)
- {
- command = it->second;
- LLStringUtil::toLower(command);
- if (parseCommand(command + "=n", behav, option, param))
- {
- if (action.find("," + behav + ",") != std::string::npos)
- {
- if (option.empty())
- {
- tmp = 1.5f;
- }
- else
- {
- tmp = atof(option.c_str());
- }
- if (tmp < res)
- {
- res = tmp;
- found_one = true;
- }
- }
- }
- }
- return found_one ? res : dflt;
- }
- LLColor3 RLInterface::getMixedColors(std::string action, LLColor3 dflt)
- {
- bool found = false;
- LLColor3 res = LLColor3::white;
- LLStringUtil::toLower(action);
- // An action may be a comma separated list list of behaviours
- action = "," + action + ",";
- LLColor3 tmp;
- std::string command, behav, option, param;
- std::deque<std::string> tokens;
- for (rl_map_it_t it = mSpecialObjectBehaviours.begin(),
- end = mSpecialObjectBehaviours.end();
- it != end; ++it)
- {
- command = it->second;
- LLStringUtil::toLower(command);
- if (parseCommand(command + "=n", behav, option, param))
- {
- if (action.find("," + behav + ",") != std::string::npos)
- {
- tokens = parse(option, ";");
- tmp.mV[0] = atof(tokens[0].c_str());
- tmp.mV[1] = atof(tokens[1].c_str());
- tmp.mV[2] = atof(tokens[2].c_str());
- res *= tmp;
- found = true;
- }
- }
- }
- return found ? res : dflt;
- }
- bool RLInterface::isFolderLocked(LLInventoryCategory* cat)
- {
- if (!cat) return false;
- const LLFolderType::EType folder_type = cat->getPreferredType();
- if (LLFolderType::lookupIsProtectedType(folder_type)) return false;
- bool shared = isUnderRlvShare(cat);
- if (!shared && contains("unsharedwear")) return true;
- if (shared && contains("sharedwear")) return true;
- if (isFolderLockedWithoutException(cat, "attach") != FolderNotLocked)
- {
- return true;
- }
- return isFolderLockedWithoutException(cat, "detach") != FolderNotLocked;
- }
- RLInterface::EFolderLock
- RLInterface::isFolderLockedWithoutException(LLInventoryCategory* cat,
- std::string attach_or_detach)
- {
- if (!cat) return FolderNotLocked;
- LL_DEBUGS("RestrainedLove") << "Category: " << cat->getName()
- << " - attach_or_detach: " << attach_or_detach
- << LL_ENDL;
- // For each object that is locking this folder, check whether it also
- // issues exceptions to this lock
- std::deque<std::string> commands_list;
- std::string command, behav, option, param;
- std::string this_command, this_behav, this_option, this_param;
- bool this_object_locks;
- EFolderLock current_lock = FolderNotLocked;
- for (rl_map_it_t it = mSpecialObjectBehaviours.begin(),
- end = mSpecialObjectBehaviours.end();
- it != end; ++it)
- {
- LLUUID id(it->first);
- command = it->second;
- LL_DEBUGS("RestrainedLove") << "command = " << command << LL_ENDL;
- // param will always be equal to "n" in this case since we added it to
- // command, but we do not care about this here
- // detach=n, recvchat=n, recvim=n, unsit=n, recvim:<uuid>=add,
- // clear=tplure...
- // Attention, an option must absolutely be specified here (there must
- // be a ':' character), or we would not be able to tell "detachthis"
- // from "detachthis:" and both have different meanings.
- if (command.find(':') != std::string::npos &&
- parseCommand(command + "=n", behav, option, param))
- {
- // find whether this object has issued a "{attach|detach}[all]this"
- // command on a folder that is either this one, or a parent
- this_object_locks = false;
- if (behav == attach_or_detach + "this")
- {
- if (getCategoryUnderRlvShare(option) == cat)
- {
- this_object_locks = true;
- }
- }
- else if (behav == attach_or_detach + "allthis")
- {
- if (isUnderFolder(getCategoryUnderRlvShare(option), cat))
- {
- this_object_locks = true;
- }
- }
- // This object has issued such a command, check whether it has
- // issued an exception to it as well
- if (this_object_locks)
- {
- commands_list = getListOfRestrictions(id);
- EFolderLock this_lock =
- isFolderLockedWithoutExceptionAux(cat, attach_or_detach,
- commands_list);
- if (this_lock == FolderLockedNoException)
- {
- return FolderLockedNoException;
- }
- else
- {
- current_lock = this_lock;
- }
- LL_DEBUGS("RestrainedLove") << "this_lock=" << this_lock
- << LL_ENDL;
- }
- }
- }
- // Finally, return unlocked since we did not find any lock on this folder
- return current_lock;
- }
- RLInterface::EFolderLock
- RLInterface::isFolderLockedWithoutExceptionAux(LLInventoryCategory* cat,
- std::string attach_or_detach,
- std::deque<std::string> restrictions)
- {
- // 'restrictions' contains the list of restrictions issued by one
- // particular object, at least one is supposed to be a
- // "{attach|detach}[all]this".
- // For each folder from cat up to the root folder, check :
- // - if we are on cat and we find "{attach|detach}this_except", there is an
- // exception, keep looking up
- // - if we are on cat and we find "{attach|detach}this", there is no
- // exception, return FolderLockedNoException
- // - if we are on a parent and we find "{attach|detach}allthis_except",
- // there is an exception, keep looking up
- // - if we are on a parent and we find "{attach|detach}allthis", if we
- // found an exception return FolderLockedWithException, else return
- // FolderLockedNoException
- // - finally, if we are on the root, return FolderLocked_unlocked (whether
- // there was an exception or not)
- if (!cat) return FolderNotLocked;
- LL_DEBUGS("RestrainedLove") << "isFolderLockedWithoutExceptionAux("
- << cat->getName() << ", " << attach_or_detach
- << ", ["
- << dumpList2String(restrictions, ",")
- << "])" << LL_ENDL;
- EFolderLock current_lock = FolderNotLocked;
- std::string command, behav, option, param;
- const LLUUID& root_id = gInventory.getRootFolderID();
- const LLUUID& cat_id = cat->getUUID();
- LLInventoryCategory* it = gInventory.getCategory(cat_id);
- LLInventoryCategory* cat_option = NULL;
- do
- {
- LL_DEBUGS("RestrainedLove") << "it=" << it->getName() << LL_ENDL;
- for (U32 i = 0; i < restrictions.size(); ++i)
- {
- command = restrictions[i];
- LL_DEBUGS("RestrainedLove") << "command2=" << command << LL_ENDL;
- // 'param' will always be equal to "n" in this case since we added
- // it to command, but we do not care about this here
- // detach=n, recvchat=n, recvim=n, unsit=n, recvim:<uuid>=add,
- // clear=tplure:
- if (parseCommand(command + "=n", behav, option, param))
- {
- cat_option = getCategoryUnderRlvShare(option);
- if (cat_option == it)
- {
- if (it == cat)
- {
- if (behav == attach_or_detach + "this_except" ||
- behav == attach_or_detach + "allthis_except")
- {
- current_lock = FolderLockedWithException;
- }
- else if (behav == attach_or_detach + "this" ||
- behav == attach_or_detach + "allthis")
- {
- return FolderLockedNoException;
- }
- }
- else if (behav == attach_or_detach + "allthis_except")
- {
- current_lock = FolderLockedWithException;
- }
- else if (behav == attach_or_detach + "allthis")
- {
- if (current_lock == FolderLockedWithException)
- {
- return FolderLockedWithException;
- }
- else
- {
- return FolderLockedNoException;
- }
- }
- }
- }
- }
- const LLUUID& parent_id = it->getParentUUID();
- it = gInventory.getCategory(parent_id);
- }
- while (it && it->getUUID() != root_id);
- // This should never happen since list_of_commands is supposed to contain
- // at least one "{attach|detach}[all]this" restriction
- return FolderNotLocked;
- }
- bool RLInterface::isBlacklisted(const LLUUID& id, std::string command,
- const std::string& option, bool force)
- {
- // Possibly allow all RestrainedLove commands for Lua scripts (automation
- // script, chat command line script, executed Lua file script, but not a
- // Lua command line relayed from an object, or via D-Bus under Linux), even
- // black-listed ones.
- static LLCachedControl<bool> lua_skip(gSavedSettings,
- "RestrainedLoveLuaNoBlacklist");
- if (lua_skip && id == gAgentID)
- {
- return false;
- }
- if (sRLNoSetEnv && command.compare(0, 6, "setenv") == 0)
- {
- return true;
- }
- if (mHandleNoRelay && !option.empty() &&
- option.find(RL_NORELAY_FOLDER_TAG) != std::string::npos)
- {
- return true;
- }
- if (sBlackList.empty())
- {
- return false;
- }
- size_t i = command.find('_');
- if (i != std::string::npos && command.find("_sec") != i &&
- command.find("_except") != i)
- {
- command = command.substr(0, i + 1);
- }
- if (force)
- {
- command += "%f";
- }
- rl_command_map_it_t it = sCommandsMap.find(command);
- if (it == sCommandsMap.end())
- {
- return false;
- }
- S32 type = it->second;
- if (type == (S32)RL_INFO || type == (S32)RL_MISCELLANEOUS)
- {
- return false;
- }
- std::string blacklist = "," + sBlackList + ",";
- return blacklist.find("," + command + ",") != std::string::npos;
- }
- bool RLInterface::add(const LLUUID& obj_id, std::string action,
- std::string option)
- {
- LL_DEBUGS("RestrainedLove") << obj_id << ": " << action << " / " << option
- << LL_ENDL;
- mLastCmdBlacklisted = false;
- std::string canon_action = action;
- if (!option.empty())
- {
- action += ":" + option;
- }
- if (!isAllowed(obj_id, action))
- {
- return false;
- }
- // Notify if needed
- notify(action, "=n");
- // Check the action against the blacklist
- if (isBlacklisted(obj_id, canon_action, option))
- {
- mLastCmdBlacklisted = true;
- llinfos << "Blacklisted RestrainedLove command: " << action
- << "=n for object " << obj_id << llendl;
- return true;
- }
- // Actions to do BEFORE inserting the new behav
- if (action == "shownames" || action == "shownames_sec" ||
- action == "shownametags")
- {
- LLFloaterChat::getInstance()->childSetVisible("active_speakers_panel",
- false);
- }
- else if (action == "fly")
- {
- gAgent.setFlying(false);
- }
- else if (action == "temprun")
- {
- if (gAgent.getRunning())
- {
- if (gAgent.getAlwaysRun())
- {
- gAgent.clearAlwaysRun();
- }
- gAgent.clearRunning();
- gAgent.sendWalkRun(false);
- }
- }
- else if (action == "alwaysrun")
- {
- if (gAgent.getAlwaysRun())
- {
- if (gAgent.getRunning())
- {
- gAgent.clearRunning();
- }
- gAgent.clearAlwaysRun();
- gAgent.sendWalkRun(false);
- }
- }
- else if (action == "edit")
- {
- gSavedSettings.setBool("BeaconAlwaysOn", false);
- LLDrawPoolAlpha::sShowDebugAlpha = false;
- }
- else if (action == "setenv")
- {
- gSavedSettings.setBool("UseLocalEnvironment", false);
- gSavedSettings.setBool("UseParcelEnvironment", false);
- }
- else if (action == "camunlock" || action == "setcam_unlock")
- {
- gAgent.resetView(true, true);
- }
- // Insert the new behav
- mSpecialObjectBehaviours.emplace(obj_id.asString(), action);
- refreshCachedVariable(action);
- // Actions to do AFTER inserting the new behav
- if (action == "showhovertextall" || action == "showloc" ||
- action == "shownames" || action == "showhovertexthud" ||
- action == "showhovertextworld")
- {
- updateAllHudTexts();
- }
- else if (canon_action == "showhovertext")
- {
- updateOneHudText(LLUUID(option));
- }
- else if (canon_action.compare(0, 3, "cam") == 0 ||
- canon_action.compare(0, 7, "setcam_") == 0)
- {
- updateCameraLimits();
- // Force an update of the zoom if necessary
- if (canon_action == "camzoommax" || canon_action == "camzoommin" ||
- canon_action == "setcam_fovmin" || canon_action == "setcam_fovmax")
- {
- gViewerCamera.setDefaultFOV(gSavedSettings.getF32("CameraAngle"));
- // setView() may have clamped it:
- gSavedSettings.setF32("CameraAngle", gViewerCamera.getView());
- }
- }
- else if (canon_action == "fartouch" || canon_action == "touchfar" ||
- canon_action == "sittp" || canon_action == "tplocal")
- {
- updateLimits();
- }
- // Update the stored last standing location, to allow grabbers to
- // transport a victim inside a cage while sitting, and restrict them
- // before standing up. If we did not do this, the avatar would snap
- // back to a safe location when being unsitted by the grabber, which
- // would be rather silly.
- if (action == "standtp")
- {
- storeLastStandingLoc(true);
- }
- return true;
- }
- bool RLInterface::remove(const LLUUID& obj_id, std::string action,
- std::string option)
- {
- LL_DEBUGS("RestrainedLove") << obj_id << ":" << action << " / " << option
- << LL_ENDL;
- std::string canon_action = action;
- if (!option.empty())
- {
- action += ":" + option;
- }
- // Notify if needed
- notify(action, "=y");
- // Actions to do BEFORE removing the behav
- // Remove the behav
- rl_map_it_t it = mSpecialObjectBehaviours.find(obj_id.asString());
- while (it != mSpecialObjectBehaviours.end() &&
- it != mSpecialObjectBehaviours.upper_bound(obj_id.asString()))
- {
- #if 0
- LL_DEBUGS("RestrainedLove") << " Checking " << it->second << LL_ENDL;
- #endif
- if (it->second == action)
- {
- mSpecialObjectBehaviours.erase(it);
- LL_DEBUGS("RestrainedLove") << " => removed." << LL_ENDL;
- refreshCachedVariable(action);
- // Actions to do AFTER removing the behav
- if (action == "shownames" || action == "showloc" ||
- action == "showhovertexthud" || action == "showhovertextall" ||
- action == "showhovertextworld")
- {
- updateAllHudTexts();
- }
- else if (canon_action == "showhovertext")
- {
- updateOneHudText(LLUUID(option));
- }
- else if (action == "standtp")
- {
- // If not sitting, then we can clear the last standing location
- if (isAgentAvatarValid() && !gAgentAvatarp->mIsSitting)
- {
- mLastStandingLocation.clear();
- gSavedPerAccountSettings.setVector3d("RestrainedLoveLastStandingLocation",
- mLastStandingLocation);
- }
- }
- else if (canon_action.compare(0, 3, "cam") == 0 ||
- canon_action.compare(0, 7, "setcam_") == 0)
- {
- updateCameraLimits();
- }
- else if (canon_action == "fartouch" ||
- canon_action == "touchfar" ||
- canon_action == "sittp" || canon_action == "tplocal")
- {
- updateLimits();
- }
- return true;
- }
- ++it;
- }
- LL_DEBUGS("RestrainedLove") << " => not in force." << LL_ENDL;
- return false;
- }
- bool RLInterface::clear(const LLUUID& obj_id, const std::string& command)
- {
- LL_DEBUGS("RestrainedLove") << obj_id << ": " << command << LL_ENDL;
- // Notify if needed
- notify("clear" + (command.empty() ? "" : ":" + command));
- const std::string id_as_str = obj_id.asString();
- rl_map_it_t it = mSpecialObjectBehaviours.begin();
- while (it != mSpecialObjectBehaviours.end())
- {
- LL_DEBUGS("RestrainedLove") << " removing " << it->second << LL_ENDL;
- if (it->first == id_as_str &&
- (command.empty() || it->second.find(command) != std::string::npos))
- {
- notify(it->second, "=y");
- LL_DEBUGS("RestrainedLove") << it->second << " => removed."
- << LL_ENDL;
- std::string tmp = it->second;
- mSpecialObjectBehaviours.erase(it);
- refreshCachedVariable(tmp);
- it = mSpecialObjectBehaviours.begin();
- }
- else
- {
- ++it;
- }
- }
- // If not still under @standtp restriction, or not sitting, then we can
- // clear the last standing location
- if (!mContainsStandtp ||
- (isAgentAvatarValid() && !gAgentAvatarp->mIsSitting))
- {
- mLastStandingLocation.clear();
- gSavedPerAccountSettings.setVector3d("RestrainedLoveLastStandingLocation",
- mLastStandingLocation);
- }
- updateAllHudTexts();
- updateCameraLimits();
- updateLimits();
- return true;
- }
- void RLInterface::replace(const LLUUID& src_id, const LLUUID& by_id)
- {
- LLUUID id;
- rl_map_it_t it = mSpecialObjectBehaviours.begin();
- while (it != mSpecialObjectBehaviours.end())
- {
- id.set(it->first);
- if (id == src_id)
- {
- // Found the UUID to replace => add a copy of the command with the
- // new UUID
- mSpecialObjectBehaviours.emplace(by_id.asString(), it->second);
- }
- ++it;
- }
- // And then clear the old UUID
- clear(src_id, "");
- HBFloaterRLV::setDirty();
- }
- bool RLInterface::garbageCollector(bool all)
- {
- bool res = false;
- LLUUID id;
- rl_map_it_t it = mSpecialObjectBehaviours.begin();
- while (it != mSpecialObjectBehaviours.end())
- {
- id.set(it->first);
- #if LL_LINUX
- bool is_lua = id == gAgentID ||
- (id == HBViewerAutomation::sLuaDBusFakeObjectId &&
- id.notNull());
- #else
- bool is_lua = id == gAgentID;
- #endif
- if (!is_lua && (all || id.notNull()))
- {
- LLViewerObject* objp = gObjectList.findObject(id);
- if (!objp)
- {
- LL_DEBUGS("RestrainedLove") << it->first
- << " not found => cleaning... "
- << LL_ENDL;
- clear(id);
- res = true;
- it = mSpecialObjectBehaviours.begin();
- HBFloaterRLV::setDirty();
- }
- else
- {
- ++it;
- }
- }
- else
- {
- LL_DEBUGS("RestrainedLove") << "Ignoring " << it->second
- << LL_ENDL;
- ++it;
- }
- }
- return res;
- }
- std::deque<std::string> RLInterface::parse(std::string str, std::string sep)
- {
- size_t ind;
- size_t length = sep.length();
- std::string token;
- std::deque<std::string> res;
- do
- {
- ind = str.find(sep);
- if (ind != std::string::npos)
- {
- token = str.substr(0, ind);
- if (!token.empty())
- {
- res.emplace_back(token);
- }
- str = str.substr(ind + length);
- }
- else if (!str.empty())
- {
- res.emplace_back(str);
- }
- }
- while (ind != std::string::npos);
- return res;
- }
- void RLInterface::notify(const std::string& action, const std::string& suffix)
- {
- size_t length = 7; // size of "notify:"
- std::deque<std::string> tokens;
- std::string rule;
- LLUUID obj_id;
- for (rl_map_it_t it = mSpecialObjectBehaviours.begin(),
- end = mSpecialObjectBehaviours.end();
- it != end; ++it)
- {
- // We are looking for rules like "notify:2222;tp", if action contains
- // "tp" then notify the scripts on channel 2222
- rule = it->second;
- if (rule.compare(0, 7, "notify:") == 0)
- {
- // Found a possible notification to send
- rule = rule.substr(length); // keep right part only(here "2222;tp")
- tokens = parse(rule, ";");
- S32 size = tokens.size();
- if (size == 1 ||
- (size > 1 && action.find(tokens[1]) != std::string::npos))
- {
- obj_id.set(it->first);
- // suffix can be "=n", "=y" or whatever else we want, "/" is
- // needed to avoid some clever griefing
- answerOnChat(obj_id, tokens[0], "/" + action + suffix);
- }
- }
- }
- }
- bool RLInterface::parseCommand(const std::string& command,
- std::string& behaviour, std::string& option,
- std::string& param)
- {
- size_t i = command.find('=');
- if (i == std::string::npos)
- {
- behaviour = command;
- param.clear();
- option.clear();
- return false;
- }
- behaviour = command.substr(0, i);
- param = command.substr(i + 1);
- i = behaviour.find(':');
- if (i != std::string::npos)
- {
- option = behaviour.substr(i + 1);
- // Keep in this order(option first, then behav) or crash
- behaviour = behaviour.substr(0, i);
- }
- else
- {
- option.clear();
- }
- return true;
- }
- bool RLInterface::handleCommand(const LLUUID& id, std::string command)
- {
- mHandleNoRelay = mRelays.count(id) != 0;
- // Parse the command, which is of one of these forms:
- // behav=param
- // behav:option=param
- std::string behav, option, param;
- LLStringUtil::toLower(command);
- // detach=n, recvchat=n, recvim=n, unsit=n, recvim:<uuid>=add,
- // clear=tplure:
- if (parseCommand(command, behav, option, param))
- {
- LL_DEBUGS("RestrainedLove") << "[" << id << "] [" << behav << "] ["
- << option << "] [" << param << "]"
- << LL_ENDL;
- if (gAutomationp)
- {
- gAutomationp->onRLVHandleCommand(id, behav, option, param);
- }
- if (behav == "version")
- {
- return answerOnChat(id, param, getVersion());
- }
- else if (behav == "versionnew")
- {
- return answerOnChat(id, param, getVersion2());
- }
- else if (behav == "versionnum")
- {
- return answerOnChat(id, param, RL_VERSION_NUM);
- }
- else if (behav == "versionnumbl")
- {
- return answerOnChat(id, param, getVersionNum());
- }
- else if (behav == "getblacklist")
- {
- return answerOnChat(id, param,
- dumpList2String(getBlacklist(option), ","));
- }
- else if (behav == "getoutfit")
- {
- return answerOnChat(id, param, getOutfit(option));
- }
- else if (behav == "getattach")
- {
- return answerOnChat(id, param, getAttachments(option));
- }
- else if (behav == "getstatus")
- {
- return answerOnChat(id, param, getStatus(id, option));
- }
- else if (behav == "getstatusall")
- {
- return answerOnChat(id, param, getStatus(LLUUID::null, option));
- }
- else if (behav == "getcommand")
- {
- return answerOnChat(id, param, getCommand(option));
- }
- else if (behav == "getinv")
- {
- return answerOnChat(id, param, getInventoryList(option));
- }
- else if (behav == "getinvworn")
- {
- return answerOnChat(id, param, getInventoryList(option, true));
- }
- else if (behav == "getsitid")
- {
- return answerOnChat(id, param, mSitTargetId.asString());
- }
- else if (behav == "getpath")
- {
- // Option can be empty (=> find path to object) or the name of an
- // attach pt or the name of a clothing layer
- return answerOnChat(id, param,
- getFullPath(getItem(id), option, false));
- }
- else if (behav == "getpathnew")
- {
- // Option can be empty (=> find path to object) or the name of an
- // attach pt or the name of a clothing layer
- return answerOnChat(id, param, getFullPath(getItem(id), option));
- }
- else if (behav == "findfolder")
- {
- return answerOnChat(id, param,
- getFullPath(findCategoryUnderRlvShare(option)));
- }
- else if (behav == "findfolders")
- {
- std::string response;
- std::deque<std::string> options = parse(option, ";");
- S32 opt_count = options.size();
- if (opt_count)
- {
- const std::string& folder_to_find = options[0];
- const std::string& separator = opt_count > 1 ? options[1] : ",";
- std::deque<LLInventoryCategory*> cats =
- findCategoriesUnderRlvShare(folder_to_find);
- for (S32 i = 0, count = cats.size(); i < count; ++i)
- {
- if (i > 0)
- {
- response += separator;
- }
- response += getFullPath(cats[i]);
- }
- }
- return answerOnChat(id, param, response);
- }
- else if (behav.compare(0, 7, "getenv_") == 0)
- {
- return answerOnChat(id, param, getEnvironment(behav));
- }
- else if (behav.compare(0, 9, "getdebug_") == 0)
- {
- return answerOnChat(id, param, getDebugSetting(behav));
- }
- else if (behav == "getgroup")
- {
- LLUUID group_id = gAgent.getGroupID();
- std::string group_name = "none";
- if (group_id.notNull() && gCacheNamep)
- {
- gCacheNamep->getGroupName(group_id, group_name);
- }
- return answerOnChat(id, param, group_name);
- }
- else if (behav == "getcam_avdistmin")
- {
- std::stringstream str;
- str << std::fixed << mCamDistMin;
- return answerOnChat(id, param, str.str());
- }
- else if (behav == "getcam_avdistmax")
- {
- std::stringstream str;
- str << std::fixed << mCamDistMax;
- return answerOnChat(id, param, str.str());
- }
- else if (behav == "getcam_zoommin")
- {
- std::stringstream str;
- str << std::fixed << mCamZoomMin;
- return answerOnChat(id, param, str.str());
- }
- else if (behav == "getcam_zoommax")
- {
- std::stringstream str;
- str << std::fixed << mCamZoomMax;
- return answerOnChat(id, param, str.str());
- }
- else if (behav == "getcam_fovmin")
- {
- std::stringstream str;
- str << std::fixed << DEFAULT_FIELD_OF_VIEW / mCamZoomMax;
- return answerOnChat(id, param, str.str());
- }
- else if (behav == "getcam_fovmax")
- {
- std::stringstream str;
- str << std::fixed << DEFAULT_FIELD_OF_VIEW / mCamZoomMin;
- return answerOnChat(id, param, str.str());
- }
- else if (behav == "getcam_fov")
- {
- std::stringstream str;
- str << std::fixed << gViewerCamera.getView();
- return answerOnChat(id, param, str.str());
- }
- else if (behav == "getcam_textures")
- {
- LLUUID tex_id;
- if (mCamTexturesCustom)
- {
- tex_id = mCamTexturesCustom->getID();
- }
- return answerOnChat(id, param, tex_id.asString());
- }
- else if (param == "n" || param == "add")
- {
- if (behav == "unsit" && (mGotSit || mGotUnsit))
- {
- mSkipAll = true;
- LL_DEBUGS("RestrainedLove") << "Detected @unsit=n command right after @"
- << (mGotSit ? "sit" : "unsit")
- << "=force. Delaying." << LL_ENDL;
- return true;
- }
- add(id, behav, option);
- }
- else if (param == "y" || param == "rem")
- {
- remove(id, behav, option);
- }
- else if (behav == "clear")
- {
- clear(id, param);
- }
- else if (param == "force")
- {
- if ((mGotUnsit && (behav == "sit" || behav == "sitground")) ||
- (mGotSit && behav == "unsit"))
- {
- // When we just executed an (un)sit=force command in the queue,
- // skip any opposite (un)sit=force command and everything
- // following it, so to let some time for the viewer and server
- // to agree on the sitting status...
- mSkipAll = true;
- LL_DEBUGS("RestrainedLove") << "Detected @" << behav
- << "=force command right after @"
- << (mGotSit ? "sit*" : "unsit")
- << "=force. Delaying." << LL_ENDL;
- return true;
- }
- return force(id, behav, option);
- }
- else
- {
- return false;
- }
- }
- else
- {
- LL_DEBUGS("RestrainedLove") << id << ": "
- << (behav == " " ? "Cancelling @relayed"
- : behav)
- << LL_ENDL;
- if (behav == "clear")
- {
- clear(id);
- }
- else if (behav == "relayed")
- {
- mRelays.emplace(id);
- }
- else if (behav == " ") // A single space means "end relayed"
- {
- mRelays.erase(id);
- }
- else
- {
- return false;
- }
- }
- return true;
- }
- void RLInterface::fireCommands()
- {
- // Do not execute queued commands if the avatar is not yet fully baked !
- if (!LLStartUp::isLoggedIn() || !isAgentAvatarValid() ||
- (!mAssetsToReattach.empty() && !mReattachTimeout) ||
- !gAppearanceMgr.isAvatarFullyBaked())
- {
- return;
- }
- // Check if the last @sit=force or @unsit=force has been executed
- bool is_sitting = gAgentAvatarp->mIsSitting;
- if (mGotSit && is_sitting)
- {
- mSkipAll = mGotSit = false;
- }
- if (mGotUnsit && !is_sitting)
- {
- mSkipAll = mGotUnsit = false;
- }
- if (mSkipAll && mSitUnsitDelayTimer.getElapsedTimeF32() > 1.f)
- {
- llwarns << "Timeout waiting for " << (mGotSit ? "sit" : "unsit")
- << " event. Resuming command queue processing." << llendl;
- mSkipAll = mGotSit = mGotUnsit = false;
- }
- if (mQueuedCommands.empty())
- {
- return;
- }
- LL_DEBUGS("RestrainedLove") << "Number of currently queued commands: "
- << mQueuedCommands.size() << LL_ENDL;
- while (!mQueuedCommands.empty() && !mSkipAll)
- {
- S32 result = HBFloaterRLV::EXECUTED;
- const RLCommand& cmd = mQueuedCommands[0];
- mLastCmdBlacklisted = false;
- if (handleCommand(cmd.mId, cmd.mCommand))
- {
- // "Success" executing this command (which could as well have been
- // black-listed and thus ignored).
- if (mLastCmdBlacklisted)
- {
- mLastCmdBlacklisted = false;
- result = HBFloaterRLV::BLACKLISTED;
- }
- }
- else
- {
- // Failure executing this command
- result = HBFloaterRLV::FAILED;
- }
- HBFloaterRLV::logCommand(cmd.mId, cmd.mName, cmd.mCommand, result);
- mQueuedCommands.pop_front();
- }
- LL_DEBUGS("RestrainedLove") << "Number of remaining queued commands: "
- << mQueuedCommands.size() << LL_ENDL;
- }
- void RLInterface::queueCommand(const LLUUID& id, const std::string& name,
- const std::string& command)
- {
- // Never queue any of the @version* and @getcommand commands: answer them
- // immediately. These commands are likely to be sent as soon as a scripted
- // RLV attachment rezzes as a form of "ping" to discover whether the viewer
- // supports RestrainedLove or not, and with what features; since we delay
- // other commands processing after full rezzing and baking of the agent
- // (which may take an indeterminate amount of time, especially if the
- // inventory cache got emptied before login), we cannot risk having the
- // attachment timing out on us...
- if (command.compare(0, 7, "version") == 0 ||
- command.compare(0, 10, "getcommand") == 0)
- {
- if (handleCommand(id, command))
- {
- // Success executing this command. Note: "version" and "getcommand"
- // cannot be black-listed, so we do not check for it.
- HBFloaterRLV::logCommand(id, name, command);
- }
- else
- {
- // Failure executing this command
- HBFloaterRLV::logCommand(id, name, command, HBFloaterRLV::FAILED);
- }
- }
- else
- {
- // A single space means "end relayed": do not log it.
- if (command != " ")
- {
- HBFloaterRLV::logCommand(id, name, command, HBFloaterRLV::QUEUED);
- }
- mQueuedCommands.emplace_back(id, name.empty() ? id.asString() : name,
- command);
- }
- }
- void RLInterface::queueCommands(const LLUUID& id, const std::string& name,
- const std::string& cmd_line)
- {
- // Check whether the command is a single one or instead a coma-separated
- // list of commands, and act accordingly.
- if (cmd_line.find(',') != std::string::npos)
- {
- bool has_relayed = false;
- std::deque<std::string> list_of_commands = parse(cmd_line, ",");
- for (U32 i = 0; i < list_of_commands.size(); ++i)
- {
- const std::string& command = list_of_commands[i];
- if (command.length() > 1 && command[0] != ' ')
- {
- queueCommand(id, name, command);
- }
- if (command == "relayed")
- {
- has_relayed = true;
- }
- }
- if (has_relayed)
- {
- // A single space means "end relayed"
- queueCommand(id, name, " ");
- }
- }
- else if (cmd_line != "relayed") // a single @relayed command is a NOP
- {
- queueCommand(id, name, cmd_line);
- }
- }
- void RLInterface::storeLastStandingLoc(bool force)
- {
- if (force || (isAgentAvatarValid() && !gAgentAvatarp->mIsSitting))
- {
- // We are now standing, and we want to sit down => store our current
- // location so that we can snap back here when we stand up, if under
- // @standtp
- LLVector3d pos = LLVector3d(gAgent.getPositionGlobal());
- mLastStandingLocation = pos;
- gSavedPerAccountSettings.setVector3d("RestrainedLoveLastStandingLocation",
- pos);
- mHandleBackToLastStanding = false;
- }
- }
- void RLInterface::validateLastStandingLoc()
- {
- if (!gRLenabled || (!mContainsStandtp && !mHandleBackToLastStanding))
- {
- // Reset this position to zero if not restricted with @standtp
- gSavedPerAccountSettings.setVector3d("RestrainedLoveLastStandingLocation",
- LLVector3d(0.0, 0.0, 0.0));
- }
- }
- void RLInterface::restoreLastStandingLoc()
- {
- mLastStandingLocation =
- gSavedPerAccountSettings.getVector3d("RestrainedLoveLastStandingLocation");
- mHandleBackToLastStanding = !mLastStandingLocation.isExactlyZero();
- }
- static void force_sit(const LLUUID& object_id)
- {
- LL_DEBUGS("RestrainedLove") << "Attempting to force-sit agent on object: "
- << object_id << LL_ENDL;
- LLViewerObject* objectp = gObjectList.findObject(object_id);
- if (!objectp)
- {
- LL_DEBUGS("RestrainedLove") << "Object not found !" << LL_ENDL;
- return;
- }
- LLViewerRegion* regionp = objectp->getRegion();
- if (!regionp)
- {
- LL_DEBUGS("RestrainedLove") << "Region not found for object."
- << LL_ENDL;
- return;
- }
- if (isAgentAvatarValid() && gAgentAvatarp->mIsSitting)
- {
- if (gRLInterface.mContainsUnsit)
- {
- // Do not allow a script to force the avatar to sit somewhere
- // if already forced to stay sitting here
- LL_DEBUGS("RestrainedLove") << "@unsit=n in force. Aborting."
- << LL_ENDL;
- return;
- }
- LLViewerObject* parent = (LLViewerObject*)gAgentAvatarp->getParent();
- if (parent && parent->getID() == object_id)
- {
- // Already sitting there !
- LL_DEBUGS("RestrainedLove") << "Already sitting on that object."
- << LL_ENDL;
- return;
- }
- }
- if (gRLInterface.mContainsInteract || gRLInterface.contains("sit"))
- {
- LL_DEBUGS("RestrainedLove") << "Not permitted to force-sit."
- << LL_ENDL;
- return;
- }
- // Store our current standing location if adequate and possible
- gRLInterface.storeLastStandingLoc();
- LL_DEBUGS("RestrainedLove") << "Sending the sit request to the server."
- << LL_ENDL;
- LL_DEBUGS("AgentSit") << "RestrainedLove sending agent sit on object request"
- << LL_ENDL;
- LLMessageSystem* msg = gMessageSystemp;
- msg->newMessageFast(_PREHASH_AgentRequestSit);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
- msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
- msg->nextBlockFast(_PREHASH_TargetObject);
- msg->addUUIDFast(_PREHASH_TargetID, objectp->mID);
- #if 0 // Note: for seats without a sit target, transmitting the offset
- // results in a sit failure with "There is no suitable surface to sit
- // on" message, while transmitting a 0 offset seems to work, as long as
- // the seat is close to the avatar (8 meters away at most)...
- msg->addVector3Fast(_PREHASH_Offset,
- gAgent.calcFocusOffset(objectp,
- gAgent.getPositionAgent(),
- 0, 0));
- #else
- msg->addVector3Fast(_PREHASH_Offset, LLVector3::zero);
- #endif
- regionp->sendReliableMessage();
- }
- void RLInterface::backToLastStandingLoc()
- {
- if (!mLastStandingLocation.isExactlyZero() && !LLApp::isExiting())
- {
- // Verify that a TP on the agent parcel would not cause the said agent
- // to either fail to TP (blocked TPs) or be TPed to a landing point.
- LLParcel* parcel = gViewerParcelMgr.getAgentParcel();
- if (parcel)
- {
- S32 type = parcel->getLandingType();
- if (type == LLParcel::L_NONE ||
- (type == LLParcel::L_LANDING_POINT &&
- !parcel->getUserLocation().isExactlyZero()))
- {
- static uuid_list_t warned_parcels;
- const LLUUID& parcel_id = parcel->getID();
- if (warned_parcels.count(parcel_id) == 0 &&
- LLViewerParcelMgr::isParcelModifiableByAgent(parcel,
- GP_LAND_SET_LANDING_POINT))
- {
- warned_parcels.emplace(parcel_id);
- gNotifications.add("RLVStandtpFailsOnRoutedParcel");
- }
- else
- {
- llwarns << "Cannot enforce @standtp on a parcel with teleport routing..."
- << llendl;
- }
- return;
- }
- }
- mSnappingBackToLastStandingLocation = true;
- gAgent.teleportViaLocationLookAt(mLastStandingLocation);
- mSnappingBackToLastStandingLocation = false;
- mHandleBackToLastStanding = false;
- }
- }
- static void force_tp_callback(U64 handle, const LLVector3& pos_region,
- bool keep_lookat)
- {
- if (handle)
- {
- LLVector3d pos_global = from_region_handle(handle) +
- LLVector3d(pos_region);
- if (keep_lookat)
- {
- gAgent.teleportViaLocationLookAt(pos_global);
- }
- else
- {
- gAgent.teleportViaLocation(pos_global);
- }
- }
- }
- // Note: "location" must be X/Y/Z where X, Y and Z are ABSOLUTE coordinates =>
- // use a script in-world to translate from local to global.
- bool RLInterface::forceTeleport(const std::string& location, bool keep_lookat)
- {
- std::string region_name;
- S32 x = 128;
- S32 y = 128;
- S32 z = 0;
- std::deque<std::string> tokens = parse(location, "/");
- if (tokens.size() == 3)
- {
- x = atoi(tokens[0].c_str());
- y = atoi(tokens[1].c_str());
- z = atoi(tokens[2].c_str());
- }
- else if (tokens.size() == 4)
- {
- region_name = tokens[0];
- x = atoi(tokens[1].c_str());
- y = atoi(tokens[2].c_str());
- z = atoi(tokens[3].c_str());
- }
- else
- {
- return false;
- }
- LL_DEBUGS("RestrainedLove") << "Location = '" << location
- << "' decoded as: " << x << "," << y << ","
- << z << " - Region name: " << region_name
- << LL_ENDL;
- // Will be checked once receiving the tp order from the sim, then set to
- // true again:
- mAllowCancelTp = false;
- if (region_name.empty())
- {
- LLVector3d pos_global((F32)x, (F32)y, (F32)z);
- if (keep_lookat)
- {
- gAgent.teleportViaLocationLookAt(pos_global);
- }
- else
- {
- gAgent.teleportViaLocation(pos_global);
- }
- }
- else
- {
- const LLVector3 pos_local((F32)x, (F32)y, (F32)z);
- LLWorldMap::url_callback_t cb = boost::bind(&force_tp_callback, _1,
- pos_local, keep_lookat);
- gWorldMap.sendNamedRegionRequest(region_name, cb, "", true);
- }
- return true;
- }
- bool RLInterface::force(const LLUUID& obj_id, std::string command,
- std::string option)
- {
- LL_DEBUGS("RestrainedLove") << command << " / " << option << LL_ENDL;
- mLastCmdBlacklisted = false;
- // Check the command against the blacklist
- if (isBlacklisted(obj_id, command, option, true))
- {
- mLastCmdBlacklisted = true;
- if (!option.empty())
- {
- command += ":" + option;
- }
- llinfos << "Blacklisted RestrainedLove command: " << command
- << "=force for object " << obj_id << llendl;
- return true;
- }
- // RLVa allows #RLV/ to be used at the start of the path in an option, so
- // support it too for compatibility.
- if (option.compare(0, RL_HRLVS_LENGTH, RL_RLV_REDIR_FOLDER_PREFIX) == 0)
- {
- // Remove #RLV/, keep the tilde.
- option.erase(0, RL_HRLVS_LENGTH);
- }
- bool res = true;
- mHandleNoStrip = true;
- if (command == "sit")
- { // sit:UUID
- bool allowed_to_sittp = true;
- if (!isAllowed(obj_id, "sittp"))
- {
- allowed_to_sittp = false;
- remove(obj_id, "sittp", "");
- }
- LLUUID id(option);
- force_sit(id);
- mGotSit = true;
- mSitUnsitDelayTimer.reset();
- if (!allowed_to_sittp)
- {
- add(obj_id, "sittp", "");
- }
- }
- else if (command == "sitground")
- {
- if (isAgentAvatarValid() &&
- // Verify we are not already sat on ground...
- !(gAgentAvatarp->mIsSitting && mSitTargetId.isNull()))
- {
- mGotSit = true;
- if (gAgentAvatarp->mIsSitting)
- {
- mSitGroundOnStandUp = true;
- gAgent.setControlFlags(AGENT_CONTROL_STAND_UP);
- }
- else
- {
- gAgent.setFlying(false);
- gAgent.clearControlFlags(AGENT_CONTROL_STAND_UP);
- gAgent.setControlFlags(AGENT_CONTROL_SIT_ON_GROUND);
- storeLastStandingLoc(true);
- }
- }
- }
- else if (command == "unsit")
- { // unsit
- LL_DEBUGS("RestrainedLove") << "trying to unsit" << LL_ENDL;
- if (isAgentAvatarValid() && gAgentAvatarp->mIsSitting)
- {
- LL_DEBUGS("RestrainedLove") << "Found sitting avatar object"
- << LL_ENDL;
- if (mContainsUnsit)
- {
- LL_DEBUGS("RestrainedLove") << "prevented from unsitting" << LL_ENDL;
- }
- else
- {
- LL_DEBUGS("RestrainedLove") << "unsitting agent" << LL_ENDL;
- mGotUnsit = true;
- mSitUnsitDelayTimer.reset();
- LL_DEBUGS("AgentSit") << "Sending agent unsit request"
- << LL_ENDL;
- gAgent.setControlFlags(AGENT_CONTROL_STAND_UP);
- send_agent_update(true, true);
- if (mContainsStandtp)
- {
- backToLastStandingLoc();
- }
- }
- }
- }
- else if (command == "remoutfit")
- { // remoutfit or remoutfit:shoes
- if (option.empty())
- {
- gAgentWearables.removeWearable(LLWearableType::WT_GLOVES, true, 0);
- gAgentWearables.removeWearable(LLWearableType::WT_JACKET, true, 0);
- gAgentWearables.removeWearable(LLWearableType::WT_PANTS, true, 0);
- gAgentWearables.removeWearable(LLWearableType::WT_SHIRT, true, 0);
- gAgentWearables.removeWearable(LLWearableType::WT_SHOES, true, 0);
- gAgentWearables.removeWearable(LLWearableType::WT_SKIRT, true, 0);
- gAgentWearables.removeWearable(LLWearableType::WT_SOCKS, true, 0);
- gAgentWearables.removeWearable(LLWearableType::WT_UNDERPANTS, true,
- 0);
- gAgentWearables.removeWearable(LLWearableType::WT_UNDERSHIRT, true,
- 0);
- gAgentWearables.removeWearable(LLWearableType::WT_ALPHA, true, 0);
- gAgentWearables.removeWearable(LLWearableType::WT_TATTOO, true, 0);
- gAgentWearables.removeWearable(LLWearableType::WT_UNIVERSAL, true,
- 0);
- gAgentWearables.removeWearable(LLWearableType::WT_PHYSICS, true,
- 0);
- }
- else
- {
- LLWearableType::EType type = getOutfitLayerAsType(option);
- if (type != LLWearableType::WT_INVALID)
- {
- // clothes only, not skin, eyes, hair or shape
- if (LLWearableType::getAssetType(type) ==
- LLAssetType::AT_CLOTHING)
- {
- // Remove by layer
- gAgentWearables.removeWearable(type, true, 0);
- }
- }
- else
- {
- // Remove by category (in RLV share)
- forceDetachByName(option, false);
- }
- }
- }
- else if (command == "detach" || command == "remattach")
- {
- // detach:chest=force OR detach:restraints/cuffs=force (@remattach is a
- // synonym). If option is an UUID, detach the corresponding object.
- if (LLUUID::validate(option))
- {
- res = forceDetachByUuid(option);
- }
- else
- {
- LLViewerJointAttachment* attachpt =
- findAttachmentPointFromName(option, true); // Exact name
- if (attachpt || option.empty())
- {
- res = forceDetach(option); // Remove by attach pt
- }
- else
- {
- res = forceDetachByName(option, false);
- }
- }
- }
- else if (command == "detachme")
- {
- // detachme=force to detach this object specifically
- res = forceDetachByUuid(obj_id.asString()); // Remove by uuid
- }
- else if (command == "detachthis")
- {
- // detachthis=force to detach the folder containing this object. If
- // option is an UUID, we do not detach the folder containing the
- // calling object, but the referenced object instead.
- std::string pathes_str;
- if (LLUUID::validate(option))
- {
- pathes_str = getFullPath(getItem(LLUUID(option)));
- }
- else
- {
- pathes_str = getFullPath(getItem(obj_id), option);
- }
- std::deque<std::string> pathes = parse(pathes_str, ",");
- for (U32 i = 0; i < pathes.size(); ++i)
- {
- res &= forceDetachByName(pathes[i], false);
- }
- }
- else if (command == "detachall")
- {
- // detachall:cuffs=force to detach a folder and its subfolders
- res = forceDetachByName(option, true);
- }
- else if (command == "detachallthis")
- {
- // detachallthis=force to detach the folder containing this object and
- // also its subfolders. If option is an UUID, we do not detach the
- // folder containing the calling object, but the referenced object
- // instead.
- std::string pathes_str;
- if (LLUUID::validate(option))
- {
- pathes_str = getFullPath(getItem(LLUUID(option)));
- }
- else
- {
- pathes_str = getFullPath(getItem(obj_id), option);
- }
- std::deque<std::string> pathes = parse(pathes_str, ",");
- for (U32 i = 0; i < pathes.size(); ++i)
- {
- res &= forceDetachByName(pathes[i], true);
- }
- }
- else if (command == "tpto")
- {
- bool keep_lookat = false;
- // tpto:[region/]X/Y/Z=force(X, Y, Z are local or global coordinates,
- // depending on the presence of the region name or not)
- size_t i = option.find(";");
- if (i != std::string::npos && i + 1 < option.length())
- {
- // Strip off the "lookat" vector: we do not support it.
- option = option.substr(0, i);
- // Instead, pass a flag telling there was a lookat vector, and use
- // that in the teleport function to keep facing in the same
- // direction after TP as before it.
- keep_lookat = true;
- }
- bool allowed_to_tploc = true;
- bool allowed_to_local = true;
- bool allowed_to_unsit = true;
- bool allowed_to_sittp = true;
- if (!isAllowed(obj_id, "tploc"))
- {
- allowed_to_tploc = false;
- remove(obj_id, "tploc", "");
- }
- if (!isAllowed(obj_id, "tplocal"))
- {
- allowed_to_local = false;
- remove(obj_id, "tplocal", "");
- }
- if (!isAllowed(obj_id, "unsit"))
- {
- allowed_to_unsit = false;
- remove(obj_id, "unsit", "");
- }
- if (!isAllowed(obj_id, "sittp"))
- {
- allowed_to_sittp = false;
- remove(obj_id, "sittp", "");
- }
- res = forceTeleport(option, keep_lookat);
- if (!allowed_to_tploc)
- {
- add(obj_id, "tploc", "");
- }
- if (!allowed_to_local)
- {
- add(obj_id, "tplocal", "");
- }
- if (!allowed_to_unsit)
- {
- add(obj_id, "unsit", "");
- }
- if (!allowed_to_sittp)
- {
- add(obj_id, "sittp", "");
- }
- }
- else if (command == "attach" || command == "addoutfit")
- {
- // attach:cuffs=force
- // Will have to be changed back to AttachReplace eventually, but not
- // before a clear and early communication
- forceAttach(option, false, AttachOverOrReplace);
- }
- else if (command == "attachover" || command == "addoutfitover")
- {
- // attachover:cuffs=force
- forceAttach(option, false, AttachOver);
- }
- else if (command == "attachoverorreplace" ||
- command == "addoutfitoverorreplace")
- {
- // attachoverorreplace:cuffs=force
- forceAttach(option, false, AttachOverOrReplace);
- }
- else if (command == "attachthis" || command == "addoutfitthis")
- {
- // attachthis=force to attach the folder containing this object
- std::string pathes_str = getFullPath(getItem(obj_id), option);
- if (!pathes_str.empty())
- {
- std::deque<std::string> pathes = parse(pathes_str, ",");
- for (U32 i = 0; i < pathes.size(); ++i)
- {
- // Will have to be changed back to AttachReplace eventually,
- // but not before a clear and early communication
- forceAttach(pathes[i], false, AttachOverOrReplace);
- }
- }
- }
- else if (command == "attachthisover" || command == "addoutfitthisover")
- {
- // attachthisover=force to attach the folder containing this object
- std::string pathes_str = getFullPath(getItem(obj_id), option);
- if (!pathes_str.empty())
- {
- std::deque<std::string> pathes = parse(pathes_str, ",");
- for (U32 i = 0; i < pathes.size(); ++i)
- {
- forceAttach(pathes[i], false, AttachOver);
- }
- }
- }
- else if (command == "attachthisoverorreplace" ||
- command == "addoutfitthisoverorreplace")
- {
- // attachthisoverorreplace=force to attach the folder containing this
- // object
- std::string pathes_str = getFullPath(getItem(obj_id), option);
- if (!pathes_str.empty())
- {
- std::deque<std::string> pathes = parse(pathes_str, ",");
- for (U32 i = 0; i < pathes.size(); ++i)
- {
- forceAttach(pathes[i], false, AttachOverOrReplace);
- }
- }
- }
- else if (command == "attachall" || command == "addoutfitall")
- {
- // attachall:cuffs=force to attach a folder and its subfolders. Will
- // have to be changed back to AttachReplace eventually, but not before
- // a clear and early communication.
- forceAttach(option, true, AttachOverOrReplace);
- }
- else if (command == "attachallover" || command == "addoutfitallover")
- {
- // attachallover:cuffs=force to attach a folder and its subfolders
- forceAttach(option, true, AttachOver);
- }
- else if (command == "attachalloverorreplace" ||
- command == "addoutfitalloverorreplace")
- {
- // attachalloverorreplace:cuffs=force to attach a folder and its
- // subfolders
- forceAttach(option, true, AttachOverOrReplace);
- }
- else if (command == "attachallthis" || command == "addoutfitallthis")
- {
- // attachallthis=force to attach the folder containing this object and
- // its subfolders
- std::string pathes_str = getFullPath(getItem(obj_id), option);
- if (!pathes_str.empty())
- {
- std::deque<std::string> pathes = parse(pathes_str, ",");
- for (U32 i = 0; i < pathes.size(); ++i)
- {
- // Will have to be changed back to AttachReplace eventually,
- // but not before a clear and early communication
- forceAttach(pathes[i], true, AttachOverOrReplace);
- }
- }
- }
- else if (command == "attachallthisover" ||
- command == "addoutfitallthisover")
- {
- // attachallthisover=force to attach the folder containing this object
- // and its subfolders
- std::string pathes_str = getFullPath(getItem(obj_id), option);
- if (!pathes_str.empty())
- {
- std::deque<std::string> pathes = parse(pathes_str, ",");
- for (U32 i = 0; i < pathes.size(); ++i)
- {
- forceAttach(pathes[i], true, AttachOver);
- }
- }
- }
- else if (command == "attachallthisoverorreplace" ||
- command == "addoutfitallthisoverorreplace")
- {
- // attachallthisoverorreplace=force to attach the folder containing
- // this object and its subfolders
- std::string pathes_str = getFullPath(getItem(obj_id), option);
- if (!pathes_str.empty())
- {
- std::deque<std::string> pathes = parse(pathes_str, ",");
- for (U32 i = 0; i < pathes.size(); ++i)
- {
- forceAttach(pathes[i], true, AttachOverOrReplace);
- }
- }
- }
- else if (command.compare(0, 7, "setenv_") == 0)
- {
- bool allowed = true;
- if (!isAllowed(obj_id, "setenv"))
- {
- allowed = false;
- remove(obj_id, "setenv", "");
- }
- if (!mContainsSetenv)
- {
- res = forceEnvironment(command, option);
- }
- if (!allowed)
- {
- add(obj_id, "setenv", "");
- }
- }
- else if (command.compare(0, 9, "setdebug_") == 0)
- {
- bool allowed = true;
- if (!isAllowed(obj_id, "setdebug"))
- {
- allowed = false;
- remove(obj_id, "setdebug", "");
- }
- if (!contains("setdebug"))
- {
- res = forceDebugSetting(command, option);
- }
- if (!allowed)
- {
- add(obj_id, "setdebug", "");
- }
- }
- else if (command == "setrot")
- {
- // setrot:angle_radians=force
- F32 val = atof(option.c_str());
- gAgent.startCameraAnimation();
- LLVector3 rot(0.f, 1.f, 0.f);
- rot = rot.rotVec(-val, LLVector3::z_axis);
- rot.normalize();
- gAgent.resetAxes(rot);
- }
- else if (command == "adjustheight")
- {
- // adjustheight:adjustment_centimeters=force or
- // adjustheight:ref_pelvis_to_foot;scalar[;delta]=force
- if (isAgentAvatarValid())
- {
- F32 val = (F32)atoi(option.c_str()) / 100.f;
- size_t i = option.find(';');
- if (i != std::string::npos && i + 1 < option.length())
- {
- F32 scalar = (F32)atof(option.substr(i + 1).c_str());
- if (scalar != 0.f)
- {
- LL_DEBUGS("RestrainedLove") << "Pelvis to foot = "
- << gAgentAvatarp->getPelvisToFoot()
- << "m" << LL_ENDL;
- val = (atof(option.c_str()) -
- gAgentAvatarp->getPelvisToFoot()) * scalar;
- option = option.substr(i + 1);
- i = option.find(';');
- if (i != std::string::npos && i + 1 < option.length())
- {
- val += (F32)atof(option.substr(i + 1).c_str());
- }
- }
- }
- if (!LLVOAvatarSelf::canUseServerBaking() ||
- LLVOAvatarSelf::useAvatarHoverHeight())
- {
- gSavedSettings.setF32("AvatarOffsetZ", val);
- }
- }
- }
- else if (command == "setgroup")
- {
- std::string target_group_name = option;
- LLStringUtil::toLower(target_group_name);
- // Note: "none" is not localized here because a script should not have
- // to bother about viewer language
- if (target_group_name == "none")
- {
- gAgent.setGroup(LLUUID::null);
- }
- else
- {
- std::string name;
- for (S32 i = 0, count = gAgent.mGroups.size(); i < count; ++i)
- {
- const LLGroupData& gdatap = gAgent.mGroups[i];
- name = gdatap.mName;
- LLStringUtil::toLower(name);
- if (name == target_group_name)
- {
- gAgent.setGroup(gdatap.mID);
- break;
- }
- }
- }
- }
- else if (command == "setcam_fov")
- {
- F32 new_fov_rad = atof(option.c_str());
- gViewerCamera.setDefaultFOV(new_fov_rad);
- // setView() may have clamped it:
- gSavedSettings.setF32("CameraAngle", gViewerCamera.getView());
- }
- else
- {
- // Unknown command
- res = false;
- }
- mHandleNoStrip = false;
- return res;
- }
- void RLInterface::removeWearableItemFromAvatar(LLViewerInventoryItem* item_or_link)
- {
- if (!item_or_link)
- {
- return;
- }
- LLViewerInventoryItem* item = item_or_link;
- if (LLViewerInventoryItem* linked_item = item_or_link->getLinkedItem())
- {
- item = linked_item;
- }
- if (item->getInventoryType() != LLInventoryType::IT_WEARABLE ||
- !canUnwear(item))
- {
- return;
- }
- LLViewerWearable* wearable;
- wearable = gAgentWearables.getWearableFromItemID(item->getUUID());
- if (!wearable)
- {
- return;
- }
- LLWearableType::EType type = wearable->getType();
- U32 index;
- if (gAgentWearables.getWearableIndex(wearable, index))
- {
- gAgentWearables.removeWearable(type, false, index);
- }
- }
- bool RLInterface::answerOnChat(const LLUUID& obj_id,
- const std::string& channel, std::string msg)
- {
- S32 chan = (S32)atoi(channel.c_str());
- if (chan == 0)
- {
- // Protection against abusive "@getstatus=0" commands, or against a
- // non-numerical channel
- return false;
- }
- if (msg.length() > (size_t)(chan > 0 ? 1023 : 254))
- {
- llwarns << "Too large an answer: maximum is "
- << (chan > 0 ? "1023 characters"
- : "254 characters for a negative channel")
- << ". Truncated reply." << llendl;
- msg = msg.substr(0, (size_t)(chan > 0 ? 1022 : 254));
- }
- LLMessageSystem* msgsys = gMessageSystemp;
- if (chan > 0)
- {
- msgsys->newMessageFast(_PREHASH_ChatFromViewer);
- msgsys->nextBlockFast(_PREHASH_AgentData);
- msgsys->addUUIDFast(_PREHASH_AgentID, gAgentID);
- msgsys->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
- msgsys->nextBlockFast(_PREHASH_ChatData);
- msgsys->addStringFast(_PREHASH_Message, msg);
- msgsys->addU8Fast(_PREHASH_Type, CHAT_TYPE_SHOUT);
- msgsys->addS32(_PREHASH_Channel, chan);
- }
- else
- {
- msgsys->newMessage(_PREHASH_ScriptDialogReply);
- msgsys->nextBlock(_PREHASH_AgentData);
- msgsys->addUUID(_PREHASH_AgentID, gAgentID);
- msgsys->addUUID(_PREHASH_SessionID, gAgentSessionID);
- msgsys->nextBlock(_PREHASH_Data);
- msgsys->addUUID(_PREHASH_ObjectID, gAgentID);
- msgsys->addS32(_PREHASH_ChatChannel, chan);
- msgsys->addS32(_PREHASH_ButtonIndex, 1);
- msgsys->addString(_PREHASH_ButtonLabel, msg);
- }
- gAgent.sendReliableMessage();
- if (gAutomationp)
- {
- gAutomationp->onRLVAnswerOnChat(obj_id, chan, msg);
- }
- LL_DEBUGS("RestrainedLove") << "/" << chan << " " << msg << LL_ENDL;
- return true;
- }
- std::string RLInterface::crunchEmote(const std::string& msg, U32 truncate_to)
- {
- if (msg.empty())
- {
- return LLStringUtil::null;
- }
- std::string crunched = msg;
- if (msg.compare(0, 4, "/me ") == 0 || msg.compare(0, 4, "/me'") == 0)
- {
- // Only allow emotes without "spoken" text.
- // Forbid text containing any symbol which could be used as quotes.
- if (msg.find('"') != std::string::npos ||
- msg.find("''") != std::string::npos ||
- msg.find('(') != std::string::npos ||
- msg.find(')') != std::string::npos ||
- msg.find(" -") != std::string::npos ||
- msg.find("- ") != std::string::npos ||
- msg.find('*') != std::string::npos ||
- msg.find('=') != std::string::npos ||
- msg.find('^') != std::string::npos ||
- msg.find('_') != std::string::npos ||
- msg.find('~') != std::string::npos)
- {
- crunched = "...";
- }
- else if (truncate_to > 0 && !sUntruncatedEmotes && !contains("emote"))
- {
- // Only allow short emotes.
- size_t i = msg.find('.');
- if (i != std::string::npos)
- {
- crunched = msg.substr(0, ++i);
- }
- if (crunched.length() > truncate_to)
- {
- crunched = crunched.substr(0, truncate_to);
- }
- }
- }
- else if (msg[0] == '/')
- {
- // Only allow short gesture names(to avoid cheats).
- if (msg.length() > 7)
- { // allows things like "/ao off", "/hug X"
- crunched = "...";
- }
- }
- else if (!sCanOoc || msg.compare(0, 2, "((") != 0 ||
- msg.find("))") != msg.length() - 2)
- {
- // Only allow OOC chat, starting with "((" and ending with "))".
- crunched = "...";
- }
- return crunched;
- }
- std::string RLInterface::getOutfitLayerAsString(LLWearableType::EType layer)
- {
- switch (layer)
- {
- case LLWearableType::WT_SKIN:
- return WS_SKIN;
- case LLWearableType::WT_GLOVES:
- return WS_GLOVES;
- case LLWearableType::WT_JACKET:
- return WS_JACKET;
- case LLWearableType::WT_PANTS:
- return WS_PANTS;
- case LLWearableType::WT_SHIRT:
- return WS_SHIRT;
- case LLWearableType::WT_SHOES:
- return WS_SHOES;
- case LLWearableType::WT_SKIRT:
- return WS_SKIRT;
- case LLWearableType::WT_SOCKS:
- return WS_SOCKS;
- case LLWearableType::WT_UNDERPANTS:
- return WS_UNDERPANTS;
- case LLWearableType::WT_UNDERSHIRT:
- return WS_UNDERSHIRT;
- case LLWearableType::WT_ALPHA:
- return WS_ALPHA;
- case LLWearableType::WT_TATTOO:
- return WS_TATTOO;
- case LLWearableType::WT_UNIVERSAL:
- return WS_UNIVERSAL;
- case LLWearableType::WT_PHYSICS:
- return WS_PHYSICS;
- case LLWearableType::WT_EYES:
- return WS_EYES;
- case LLWearableType::WT_HAIR:
- return WS_HAIR;
- case LLWearableType::WT_SHAPE:
- return WS_SHAPE;
- default:
- return "";
- }
- }
- LLWearableType::EType RLInterface::getOutfitLayerAsType(const std::string& layer)
- {
- if (layer == WS_SKIN) return LLWearableType::WT_SKIN;
- if (layer == WS_GLOVES) return LLWearableType::WT_GLOVES;
- if (layer == WS_JACKET) return LLWearableType::WT_JACKET;
- if (layer == WS_PANTS) return LLWearableType::WT_PANTS;
- if (layer == WS_SHIRT) return LLWearableType::WT_SHIRT;
- if (layer == WS_SHOES) return LLWearableType::WT_SHOES;
- if (layer == WS_SKIRT) return LLWearableType::WT_SKIRT;
- if (layer == WS_SOCKS) return LLWearableType::WT_SOCKS;
- if (layer == WS_UNDERPANTS) return LLWearableType::WT_UNDERPANTS;
- if (layer == WS_UNDERSHIRT) return LLWearableType::WT_UNDERSHIRT;
- if (layer == WS_ALPHA) return LLWearableType::WT_ALPHA;
- if (layer == WS_TATTOO) return LLWearableType::WT_TATTOO;
- if (layer == WS_UNIVERSAL) return LLWearableType::WT_UNIVERSAL;
- if (layer == WS_PHYSICS) return LLWearableType::WT_PHYSICS;
- if (layer == WS_EYES) return LLWearableType::WT_EYES;
- if (layer == WS_HAIR) return LLWearableType::WT_HAIR;
- if (layer == WS_SHAPE) return LLWearableType::WT_SHAPE;
- return LLWearableType::WT_INVALID;
- }
- std::string RLInterface::getOutfit(const std::string& layer)
- {
- if (layer == WS_SKIN) return (gAgentWearables.getWearable(LLWearableType::WT_SKIN, 0) ? "1" : "0");
- if (layer == WS_GLOVES) return (gAgentWearables.getWearable(LLWearableType::WT_GLOVES, 0) ? "1" : "0");
- if (layer == WS_JACKET) return (gAgentWearables.getWearable(LLWearableType::WT_JACKET, 0) ? "1" : "0");
- if (layer == WS_PANTS) return (gAgentWearables.getWearable(LLWearableType::WT_PANTS, 0) ? "1" : "0");
- if (layer == WS_SHIRT) return (gAgentWearables.getWearable(LLWearableType::WT_SHIRT, 0) ? "1" : "0");
- if (layer == WS_SHOES) return (gAgentWearables.getWearable(LLWearableType::WT_SHOES, 0) ? "1" : "0");
- if (layer == WS_SKIRT) return (gAgentWearables.getWearable(LLWearableType::WT_SKIRT, 0) ? "1" : "0");
- if (layer == WS_SOCKS) return (gAgentWearables.getWearable(LLWearableType::WT_SOCKS, 0) ? "1" : "0");
- if (layer == WS_UNDERPANTS) return (gAgentWearables.getWearable(LLWearableType::WT_UNDERPANTS, 0) ? "1" : "0");
- if (layer == WS_UNDERSHIRT) return (gAgentWearables.getWearable(LLWearableType::WT_UNDERSHIRT, 0) ? "1" : "0");
- if (layer == WS_ALPHA) return (gAgentWearables.getWearable(LLWearableType::WT_ALPHA, 0) ? "1" : "0");
- if (layer == WS_TATTOO) return (gAgentWearables.getWearable(LLWearableType::WT_TATTOO, 0) ? "1" : "0");
- if (layer == WS_UNIVERSAL) return (gAgentWearables.getWearable(LLWearableType::WT_UNIVERSAL, 0) ? "1" : "0");
- if (layer == WS_PHYSICS) return (gAgentWearables.getWearable(LLWearableType::WT_PHYSICS, 0) ? "1" : "0");
- if (layer == WS_EYES) return (gAgentWearables.getWearable(LLWearableType::WT_EYES, 0) ? "1" : "0");
- if (layer == WS_HAIR) return (gAgentWearables.getWearable(LLWearableType::WT_HAIR, 0) ? "1" : "0");
- if (layer == WS_SHAPE) return (gAgentWearables.getWearable(LLWearableType::WT_SHAPE, 0) ? "1" : "0");
- return getOutfit(WS_GLOVES) + getOutfit(WS_JACKET) + getOutfit(WS_PANTS) +
- getOutfit(WS_SHIRT) + getOutfit(WS_SHOES) + getOutfit(WS_SKIRT) +
- getOutfit(WS_SOCKS) + getOutfit(WS_UNDERPANTS) + getOutfit(WS_UNDERSHIRT) +
- getOutfit(WS_SKIN) + getOutfit(WS_EYES) + getOutfit(WS_HAIR) +
- getOutfit(WS_SHAPE) + getOutfit(WS_ALPHA) + getOutfit(WS_TATTOO) +
- getOutfit(WS_PHYSICS) + getOutfit(WS_UNIVERSAL);
- }
- std::string RLInterface::getAttachments(const std::string& attachpt)
- {
- std::string res, name;
- if (!isAgentAvatarValid())
- {
- llwarns << "NULL avatar pointer. Aborting." << llendl;
- return res;
- }
- if (attachpt.empty())
- {
- res += "0"; // to match the LSL macros
- }
- for (LLVOAvatar::attachment_map_t::iterator
- iter = gAgentAvatarp->mAttachmentPoints.begin(),
- end = gAgentAvatarp->mAttachmentPoints.end();
- iter != end; ++iter)
- {
- LLViewerJointAttachment* attachment = iter->second;
- name = attachment->getName();
- if (name == "Avatar Center")
- {
- name = "Root";
- }
- LLStringUtil::toLower(name);
- LL_DEBUGS("RestrainedLove") << "trying <" << name << ">" << LL_ENDL;
- if (attachpt.empty() || attachpt == name)
- {
- if (attachment->getNumObjects() > 0)
- {
- res += "1"; // attachment->getName();
- }
- else
- {
- res += "0";
- }
- }
- }
- return res;
- }
- std::string RLInterface::getStatus(const LLUUID& obj_id, std::string rule)
- {
- std::string res, name;
- std::string separator = "/";
- // If rule contains a specification of the separator, extract it
- size_t ind = rule.find(";");
- if (ind != std::string::npos)
- {
- separator = rule.substr(ind + 1);
- rule = rule.substr(0, ind);
- }
- if (separator.empty())
- {
- // Prevent a hack to force the avatar to say something
- separator = "/";
- }
- rl_map_it_t it;
- if (obj_id.isNull())
- {
- it = mSpecialObjectBehaviours.begin();
- }
- else
- {
- it = mSpecialObjectBehaviours.find(obj_id.asString());
- }
- while (it != mSpecialObjectBehaviours.end() &&
- (obj_id.isNull() ||
- it != mSpecialObjectBehaviours.upper_bound(obj_id.asString())))
- {
- if (rule.empty() || it->second.find(rule) != std::string::npos)
- {
- res += separator;
- res += it->second;
- }
- ++it;
- }
- return res;
- }
- std::string RLInterface::getCommand(std::string match, bool blacklist)
- {
- std::string res, command, name, temp;
- LLStringUtil::toLower(match);
- for (rl_command_map_it_t it = sCommandsMap.begin(),
- end = sCommandsMap.end();
- it != end; ++it)
- {
- command = it->first;
- size_t i = command.find("%f");
- bool force = i != std::string::npos;
- name = force ? command.substr(0, i) : command;
- temp = res + "/";
- if (match.empty() || command.find(match) != std::string::npos)
- {
- if (temp.find("/" + command + "/") == std::string::npos &&
- (blacklist || !isBlacklisted(LLUUID::null, name, "", force)))
- {
- res += "/" + command;
- }
- }
- }
- return res;
- }
- std::string RLInterface::getCommandsByType(S32 type, bool blacklist)
- {
- std::string res, command, name, temp;
- for (rl_command_map_it_t it = sCommandsMap.begin(),
- end = sCommandsMap.end();
- it != end; ++it)
- {
- S32 cmdtype = (S32)it->second;
- if (cmdtype == type)
- {
- command = it->first;
- size_t i = command.find("%f");
- bool force = i != std::string::npos;
- name = force ? command.substr(0, i) : command;
- temp = res + "/";
- if (temp.find("/" + command + "/") == std::string::npos &&
- (blacklist || !isBlacklisted(LLUUID::null, name, "", force)))
- {
- res += "/" + command;
- }
- }
- }
- return res;
- }
- std::deque<std::string> RLInterface::getBlacklist(std::string filter)
- {
- std::deque<std::string> list, res;
- list = parse(sBlackList, ",");
- res.clear();
- size_t size = list.size();
- for (size_t i = 0; i < size; ++i)
- {
- if (filter.empty() || list[i].find(filter) != std::string::npos)
- {
- res.emplace_back(list[i]);
- }
- }
- return res;
- }
- std::string RLInterface::getRlvRestrictions(const std::string& filter)
- {
- LLUUID id;
- std::string res = "\n################ RLV RESTRICTIONS ################";
- std::string object_name, old_object_name;
- for (rl_map_it_t it = mSpecialObjectBehaviours.begin(),
- end = mSpecialObjectBehaviours.end();
- it != end; ++it)
- {
- id.set(it->first);
- LLInventoryItem* item = getItem(id);
- if (item)
- {
- object_name = item->getName();
- }
- if (filter.empty() || object_name.find(filter) != std::string::npos)
- {
- if (object_name.empty())
- {
- object_name = id.asString();
- }
- // print the name of the object
- if (object_name != old_object_name)
- {
- res += "\nObject: " + object_name;
- }
- res += "\n - " + it->second;
- }
- old_object_name = object_name;
- object_name.clear();
- }
- return res + "\n##################################################";
- }
- bool RLInterface::forceDetach(const std::string& attachpt)
- {
- bool res = false;
- if (!isAgentAvatarValid()) return res;
- std::string name;
- for (LLVOAvatar::attachment_map_t::iterator
- iter = gAgentAvatarp->mAttachmentPoints.begin(),
- end = gAgentAvatarp->mAttachmentPoints.end();
- iter != end; ++iter)
- {
- LLViewerJointAttachment* attachment = iter->second;
- if (!attachment) continue; // Paranoia
- name = attachment->getName();
- if (name == "Avatar Center")
- {
- name = "Root";
- }
- LLStringUtil::toLower(name);
- LL_DEBUGS("RestrainedLove") << "trying <" << name << ">" << LL_ENDL;
- if (attachpt.empty() || attachpt == name)
- {
- LL_DEBUGS("RestrainedLove") << "found => detaching" << LL_ENDL;
- detachAllObjectsFromAttachment(attachment);
- res = true;
- }
- }
- return res;
- }
- bool RLInterface::forceDetachByUuid(const std::string& object_id)
- {
- bool res = false;
- if (!isAgentAvatarValid()) return res;
- LLViewerObject* object = gObjectList.findObject(LLUUID(object_id));
- if (object)
- {
- object = object->getRootEdit();
- for (LLVOAvatar::attachment_map_t::iterator
- iter = gAgentAvatarp->mAttachmentPoints.begin(),
- end = gAgentAvatarp->mAttachmentPoints.end();
- iter != end; ++iter)
- {
- LLViewerJointAttachment* attachment = iter->second;
- if (attachment && attachment->isObjectAttached(object))
- {
- detachObject(object);
- res = true;
- }
- }
- }
- return res;
- }
- bool RLInterface::hasLockedHuds()
- {
- if (!isAgentAvatarValid()) return false;
- for (S32 i = 0, count = gAgentAvatarp->mAttachedObjectsVector.size();
- i < count; ++i)
- {
- LLViewerObject* objp = gAgentAvatarp->mAttachedObjectsVector[i].first;
- if (objp && objp->isHUDAttachment() && !canDetach(objp))
- {
- return true;
- }
- }
- return false;
- }
- std::deque<LLInventoryItem*> RLInterface::getListOfLockedItems(LLInventoryCategory* root)
- {
- std::deque<LLInventoryItem*> res;
- std::deque<LLInventoryItem*> tmp;
- if (root && isAgentAvatarValid())
- {
- LLInventoryModel::cat_array_t* cats;
- LLInventoryModel::item_array_t* items;
- gInventory.getDirectDescendentsOf(root->getUUID(), cats, items);
- // Try to find locked items in the current category
- std::string attach_point_name;
- for (S32 i = 0, count = items->size(); i < count; ++i)
- {
- LLInventoryItem* item = (*items)[i];
- // If this is an object, add it if it is worn and locked, or worn
- // and its attach point is locked
- if (item && item->getType() == LLAssetType::AT_OBJECT)
- {
- LLViewerObject* attached_object;
- attached_object = gAgentAvatarp->getWornAttachment(item->getUUID());
- if (attached_object)
- {
- attach_point_name = gAgentAvatarp->getAttachedPointName(item->getLinkedUUID());
- if (!canDetach(attached_object))
- {
- LL_DEBUGS("RestrainedLove") << "Found a locked object: "
- << item->getName()
- << " on "
- << attach_point_name
- << LL_ENDL;
- res.push_back(item);
- }
- }
- }
- // If this is a piece of clothing, add it if the avatar cannot
- // unwear clothes, or if this layer itself cannot be unworn
- else if (item && item->getType() == LLAssetType::AT_CLOTHING)
- {
- if (contains("remoutfit") || containsSubstr("remoutfit:"))
- {
- LL_DEBUGS("RestrainedLove") << "Found a locked clothing: "
- << item->getName() << LL_ENDL;
- res.push_back(item);
- }
- }
- }
- // We have all the locked objects contained directly in this folder,
- // now add all the ones contained in children folders recursively
- for (S32 i = 0, count = cats->size(); i < count; ++i)
- {
- LLInventoryCategory* cat = (*cats)[i];
- tmp = getListOfLockedItems(cat);
- for (S32 j = 0, count2 = tmp.size(); j < count2; ++j)
- {
- LLInventoryItem* item = tmp[j];
- if (item)
- {
- res.push_back(item);
- }
- }
- }
- LL_DEBUGS("RestrainedLove") << "Number of locked objects under "
- << root->getName() << " = " << res.size()
- << LL_ENDL;
- }
- return res;
- }
- std::deque<std::string> RLInterface::getListOfRestrictions(const LLUUID& obj_id,
- const std::string& rule)
- {
- std::deque<std::string> res;
- std::string name;
- rl_map_it_t it;
- if (obj_id.isNull())
- {
- it = mSpecialObjectBehaviours.begin();
- }
- else
- {
- it = mSpecialObjectBehaviours.find(obj_id.asString());
- }
- while (it != mSpecialObjectBehaviours.end() &&
- (obj_id.isNull() ||
- it != mSpecialObjectBehaviours.upper_bound(obj_id.asString())))
- {
- if (rule.empty() || it->second.find(rule) != std::string::npos)
- {
- res.emplace_back(it->second);
- }
- ++it;
- }
- return res;
- }
- std::string RLInterface::getInventoryList(const std::string& path,
- bool with_worn_info)
- {
- std::string res;
- LLInventoryModel::cat_array_t* cats;
- LLInventoryModel::item_array_t* items;
- LLInventoryCategory* root = NULL;
- if (path.empty())
- {
- root = getRlvShare();
- }
- else
- {
- root = getCategoryUnderRlvShare(path);
- }
- if (root)
- {
- gInventory.getDirectDescendentsOf(root->getUUID(), cats, items);
- if (cats)
- {
- bool found_one = false;
- if (with_worn_info)
- {
- std::string worn_items = getWornItems(root);
- res += "|";
- found_one = true;
- if (worn_items == "n")
- {
- res += "10";
- }
- else if (worn_items == "N")
- {
- res += "30";
- }
- else
- {
- res += worn_items;
- }
- }
- for (S32 i = 0, count = cats->size(); i < count; ++i)
- {
- LLInventoryCategory* cat = (*cats)[i];
- const std::string& name = cat->getName();
- if (!name.empty() && name[0] != '.' &&
- (!mHandleNoRelay ||
- name.find(RL_NORELAY_FOLDER_TAG) == std::string::npos))
- { // hidden folders => invisible to the list
- if (found_one)
- {
- res += ",";
- }
- res += name.c_str();
- if (with_worn_info)
- {
- std::string worn_items = getWornItems(cat);
- res += "|";
- found_one = true;
- if (worn_items == "n")
- {
- res += "10";
- }
- else if (worn_items == "N")
- {
- res += "30";
- }
- else
- {
- res += worn_items;
- }
- }
- found_one = true;
- }
- }
- }
- }
- return res;
- }
- std::string RLInterface::getWornItems(LLInventoryCategory* cat)
- {
- // Returns a string of 2 digits according to the proportion of worn items
- // in this folder and its children:
- // First digit is this folder, second digit is children folders
- // 0 : No item contained in the folder
- // 1 : Some items contained but none is worn
- // 2 : Some items contained and some of them are worn
- // 3 : Some items contained and all of them are worn
- S32 res = 0;
- S32 sub_res = 0;
- S32 prev_sub_res = 0;
- S32 nb_items = 0;
- S32 nb_worn = 0;
- bool no_mod = false;
- bool is_rlv_root = getRlvShare() == cat;
- // if cat exists, scan all the items inside it
- if (cat)
- {
- LLInventoryModel::cat_array_t* cats;
- LLInventoryModel::item_array_t* items;
- // Retrieve all the objects contained in this folder
- gInventory.getDirectDescendentsOf(cat->getUUID(), cats, items);
- if (!is_rlv_root && items) // Do not scan the shared root
- {
- // Scan them one by one
- LLViewerInventoryItem* item;
- for (S32 i = 0, count = items->size(); i < count; ++i)
- {
- item = (LLViewerInventoryItem*)(*items)[i];
- if (item)
- {
- if (item->getType() == LLAssetType::AT_OBJECT ||
- item->getType() == LLAssetType::AT_CLOTHING ||
- item->getType() == LLAssetType::AT_BODYPART)
- {
- ++nb_items;
- }
- if (gAgentWearables.isWearingItem(item->getUUID()) ||
- (isAgentAvatarValid() &&
- gAgentAvatarp->isWearingAttachment(item->getUUID())))
- {
- ++nb_worn;
- }
- // Special case: this item is no-mod, hence we need to check
- // its parent folder is correctly named, and that the item
- // is alone in its folder. If so, then the calling method
- // will have to deal with a special character instead of a
- // number
- if (count == 1 && item->getType() == LLAssetType::AT_OBJECT &&
- !item->getPermissions().allowModifyBy(gAgentID))
- {
- if (findAttachmentPointFromName(cat->getName()))
- {
- no_mod = true;
- }
- }
- }
- }
- }
- // Scan every subfolder of the folder we are scanning, recursively.
- // Note: in the case of no-mod items we should not have sub-folders,
- // so there is no need to check.
- if (cats && !no_mod)
- {
- for (S32 i = 0, count = cats->size(); i < count; ++i)
- {
- LLViewerInventoryCategory* childp =
- (LLViewerInventoryCategory*)(*cats)[i];
- if (childp)
- {
- std::string tmp = getWornItems(childp);
- // Translate the result for no-mod items into something the
- // upper levels can understand
- if (tmp == "N")
- {
- if (!is_rlv_root)
- {
- ++nb_worn;
- ++nb_items;
- sub_res = 3;
- }
- }
- else if (tmp == "n")
- {
- if (!is_rlv_root)
- {
- ++nb_items;
- sub_res = 1;
- }
- }
- else if (!childp->getName().empty() &&
- // We do not want to include invisible folders,
- // except the ones containing a no-mod item
- childp->getName()[0] != '.')
- {
- // This is an actual sub-folder with several items and
- // sub-folders inside, so retain its score to include
- // it into the current one. As it is a sub-folder, to
- // include it we need to reduce its score first
- // (consider "0" as "ignore")
- // "00" = 0, "01" = 1, "10" = 1, "30" = 3, "03" = 3,
- // "33" = 3, all the rest gives 2 (some worn, some not
- // worn)
- if (tmp == "00")
- {
- sub_res = 0;
- }
- else if (tmp == "11" || tmp == "01" || tmp == "10")
- {
- sub_res = 1;
- }
- else if (tmp == "33" || tmp == "03" || tmp == "30")
- {
- sub_res = 3;
- }
- else
- {
- sub_res = 2;
- }
- // Then we must combine with the previous sibling
- // sub-folders./ Same rule as above, set to 2 in all
- // cases except when prev_sub_res == sub_res or when
- // either == 0 (nothing present, ignore)
- if (prev_sub_res == 0 && sub_res == 0)
- {
- sub_res = 0;
- }
- else if (prev_sub_res == 0 && sub_res == 1)
- {
- sub_res = 1;
- }
- else if (prev_sub_res == 1 && sub_res == 0)
- {
- sub_res = 1;
- }
- else if (prev_sub_res == 1 && sub_res == 1)
- {
- sub_res = 1;
- }
- else if (prev_sub_res == 0 && sub_res == 3)
- {
- sub_res = 3;
- }
- else if (prev_sub_res == 3 && sub_res == 0)
- {
- sub_res = 3;
- }
- else if (prev_sub_res == 3 && sub_res == 3)
- {
- sub_res = 3;
- }
- else
- {
- sub_res = 2;
- }
- prev_sub_res = sub_res;
- }
- }
- }
- }
- }
- if (no_mod)
- {
- // The folder contains one no-mod object and is named from an
- // attachment point => return a special character that will be handled
- // by the calling method
- if (nb_worn > 0)
- {
- return "N";
- }
- else
- {
- return "n";
- }
- }
- else
- {
- if (is_rlv_root || nb_items == 0)
- {
- // Forcibly hide all items contained directly under #RLV
- res = 0;
- }
- else if (nb_worn >= nb_items)
- {
- res = 3;
- }
- else if (nb_worn > 0)
- {
- res = 2;
- }
- else
- {
- res = 1;
- }
- }
- std::stringstream str;
- str << res;
- str << sub_res;
- return str.str();
- }
- LLInventoryCategory* RLInterface::getRlvShare()
- {
- LLInventoryModel::cat_array_t* cats;
- LLInventoryModel::item_array_t* items;
- gInventory.getDirectDescendentsOf(gInventory.getRootFolderID(), cats,
- items);
- if (cats)
- {
- for (S32 i = 0, count = cats->size(); i < count; ++i)
- {
- LLInventoryCategory* cat = (*cats)[i];
- const std::string& name = cat->getName();
- if (name == RL_SHARED_FOLDER)
- {
- // LL_DEBUGS("RestrainedLove") << "found " << name << LL_ENDL;
- return cat;
- }
- }
- }
- return NULL;
- }
- bool RLInterface::isUnderRlvShare(LLInventoryItem* item)
- {
- if (!item) return false;
- const LLUUID& cat_id = item->getParentUUID();
- return isUnderFolder(getRlvShare(), gInventory.getCategory(cat_id));
- }
- bool RLInterface::isUnderRlvShare(LLInventoryCategory* cat)
- {
- return isUnderFolder(getRlvShare(), cat);
- }
- bool RLInterface::isUnderFolder(LLInventoryCategory* parentp,
- LLInventoryCategory* childp)
- {
- if (!parentp || !childp)
- {
- return false;
- }
- if (childp == parentp)
- {
- return true;
- }
- const LLUUID& root_id = gInventory.getRootFolderID();
- const LLUUID& cat_id = childp->getParentUUID();
- LLInventoryCategory* res = gInventory.getCategory(cat_id);
- while (res && res->getUUID() != root_id)
- {
- if (res == parentp)
- {
- return true;
- }
- const LLUUID& parent_id = res->getParentUUID();
- res = gInventory.getCategory(parent_id);
- }
- return false;
- }
- LLInventoryCategory* RLInterface::getCategoryUnderRlvShare(std::string cat_name,
- LLInventoryCategory* root)
- {
- if (!root)
- {
- root = getRlvShare();
- if (!root)
- {
- LL_DEBUGS("RestrainedLove") << "No " << RL_SHARED_FOLDER
- << " folder !" << LL_ENDL;
- return NULL;
- }
- }
- if (cat_name.empty())
- {
- return root;
- }
- LLStringUtil::toLower(cat_name);
- std::deque<std::string> tokens = parse(cat_name, "/");
- // Preliminary action: remove everything after pipes("|"), including pipes
- // themselves. This way we can feed the result of a @getinvworn command
- // directly into this method without having to clean up what is after the
- // pipes.
- for (S32 i = 0, count = tokens.size(); i < count; ++i)
- {
- std::string tok = tokens[i];
- size_t ind = tok.find('|');
- if (ind != std::string::npos)
- {
- tok = tok.substr(0, ind);
- tokens[i] = tok;
- }
- }
- LLInventoryModel::cat_array_t* cats;
- LLInventoryModel::item_array_t* items;
- gInventory.getDirectDescendentsOf(root->getUUID(), cats, items);
- if (!cats)
- {
- LL_DEBUGS("RestrainedLove") << "No sub-folder in "
- << RL_SHARED_FOLDER << LL_ENDL;
- return NULL;
- }
- // We first need to scan the folder tree and retain the best match
- bool exact_match = false;
- S32 max_size_index = -1;
- S32 max_size = 0;
- for (S32 i = 0, count = cats->size(); i < count; ++i)
- {
- LLInventoryCategory* cat = (*cats)[i];
- std::string name = cat->getName();
- if (!name.empty() && name[0] != '.') // Ignore invisible cats
- {
- LLStringUtil::toLower(name);
- S32 size = match(tokens, name, exact_match);
- if (size > max_size || (exact_match && size == max_size))
- {
- max_size = size;
- max_size_index = i;
- }
- }
- }
- if (max_size <= 0)
- {
- LL_DEBUGS("RestrainedLove") << "No matching category name found for "
- << cat_name << LL_ENDL;
- return NULL;
- }
- // Only now we can grab the best match and either continue deeper or return
- // it
- LLInventoryCategory* cat = (*cats)[max_size_index];
- if (max_size == (S32)tokens.size())
- {
- return cat;
- }
- // Recurse...
- std::string subcat = dumpList2String(getSubList(tokens, max_size), "/");
- return getCategoryUnderRlvShare(subcat, cat);
- }
- LLInventoryCategory* RLInterface::findCategoryUnderRlvShare(std::string cat_name,
- LLInventoryCategory* root)
- {
- if (!root)
- {
- root = getRlvShare();
- if (!root)
- {
- LL_DEBUGS("RestrainedLove") << "No " << RL_SHARED_FOLDER
- << " folder !" << LL_ENDL;
- return NULL;
- }
- }
- LLStringUtil::toLower(cat_name);
- std::deque<std::string> tokens = parse(cat_name, "&&");
- LLInventoryModel::cat_array_t* cats;
- LLInventoryModel::item_array_t* items;
- gInventory.getDirectDescendentsOf(root->getUUID(), cats, items);
- if (cats)
- {
- LLInventoryCategory* found;
- for (S32 i = 0, count = cats->size(); i < count; ++i)
- {
- LLInventoryCategory* cat = (*cats)[i];
- const std::string& name = cat->getName();
- // We cannot find invisible folders('.') and given folders('~')
- if (!name.empty() && name[0] != '.' && name[0] != '~')
- {
- // Search recursively deeper
- found = findCategoryUnderRlvShare(cat_name, cat);
- if (found)
- {
- return found;
- }
- }
- }
- }
- // Return this category if it matches
- std::string name = root->getName();
- LLStringUtil::toLower(name);
- // We cannot find invisible folders('.') and given folders('~')
- if (!name.empty() && name[0] != '.' && name[0] != '~' &&
- findMultiple(tokens, name))
- {
- return root;
- }
- return NULL; // We did not find anything
- }
- std::deque<LLInventoryCategory*> RLInterface::findCategoriesUnderRlvShare(std::string cat_name,
- LLInventoryCategory* root)
- {
- std::deque<LLInventoryCategory*> res;
- if (!root)
- {
- root = getRlvShare();
- if (!root)
- {
- LL_DEBUGS("RestrainedLove") << "No " << RL_SHARED_FOLDER
- << " folder !" << LL_ENDL;
- return res;
- }
- }
- LLStringUtil::toLower(cat_name);
- std::deque<std::string> tokens = parse(cat_name, "&&");
- LLInventoryModel::cat_array_t* cats;
- LLInventoryModel::item_array_t* items;
- gInventory.getDirectDescendentsOf(root->getUUID(), cats, items);
- if (cats)
- {
- std::deque<LLInventoryCategory*> found;
- for (S32 i = 0, count = cats->size(); i < count; ++i)
- {
- LLInventoryCategory* cat = (*cats)[i];
- const std::string& name = cat->getName();
- // We cannot find invisible folders('.') and given folders('~')
- if (!name.empty() && name[0] != '.' && name[0] != '~')
- {
- // Search recursively deeper
- found = findCategoriesUnderRlvShare(cat_name, cat);
- for (S32 i = 0, count2 = found.size(); i < count2; ++i)
- {
- res.push_back(found[i]);
- }
- }
- }
- }
- // Return this category if it matches
- std::string name = root->getName();
- LLStringUtil::toLower(name);
- // We cannot find invisible folders('.') and given folders('~')
- if (!name.empty() && name[0] != '.' && name[0] != '~' &&
- findMultiple(tokens, name))
- {
- res.push_back(root);
- }
- return res;
- }
- bool RLInterface::shouldMoveToSharedSubFolder(LLViewerInventoryCategory* catp)
- {
- // Note: we do not test for getRlvShare(), since it is time consuming; the
- // caller should test for it once and for all before doing repetitive calls
- // to this method.
- return catp->getName().compare(0, RL_HRLVST_LENGTH,
- RL_RLV_REDIR_FOLDER_PREFIX) == 0;
- }
- void RLInterface::moveToSharedSubFolder(LLViewerInventoryCategory* catp)
- {
- LLInventoryCategory* rlv_root_catp = getRlvShare();
- if (!rlv_root_catp)
- {
- return;
- }
- std::string folder_name = catp->getName();
- if (folder_name.compare(0, RL_HRLVST_LENGTH,
- RL_RLV_REDIR_FOLDER_PREFIX) != 0)
- {
- return;
- }
- // Remove #RLV/
- folder_name.erase(0, RL_HRLVS_LENGTH);
- // Sanitize the name
- LLInventoryObject::correctInventoryName(folder_name);
- // By default, we will put this folder under #RLV directly
- LLInventoryCategory* target_catp = rlv_root_catp;
- // We have received a "#RLV/~A/B/C" folder so we want to move it under our
- // #RLV/ root folder.
- // To avoid cluttering the #RLV folder with many sub-folders of the same
- // name, we try to unify the hierarchy like so:
- // - The last folder in the string must be created even if it already
- // exists so we do not pollute an existing folder with new items.
- // - All its parents must be unified with existing folders if possible,
- // created if not possible.
- std::deque<std::string> hierarchy = parse(folder_name, "/");
- S32 sub_folders = hierarchy.size();
- // For each parent folder in the name from left to right (if any, meaning
- // if there is at least one "/" in the name of the folder we have
- // received), unify or create that folder and make it the parent of the
- // folder on its right.
- for (S32 i = 0; i < sub_folders - 1; ++i)
- {
- const std::string& name = hierarchy[i];
- LLInventoryModel::cat_array_t* cats;
- LLInventoryModel::item_array_t* items;
- gInventory.getDirectDescendentsOf(target_catp->getUUID(), cats, items);
- // Try to find the first folder among the descendents which name
- // matches the one we are examining.
- LLInventoryCategory* found_catp = NULL;
- for (S32 j = 0, count = cats->size(); j < count; ++j)
- {
- LLInventoryCategory* old_catp = (*cats)[j];
- if (!LLStringUtil::compareInsensitive(old_catp->getName(), name))
- {
- // Found an existing folder with that name
- found_catp = old_catp;
- break;
- }
- }
- if (found_catp)
- {
- target_catp = found_catp;
- }
- else
- {
- LLUUID id = gInventory.createCategoryUDP(target_catp->getUUID(),
- LLFolderType::FT_NONE,
- name);
- gInventory.notifyObservers();
- if (id.notNull())
- {
- target_catp = gInventory.getCategory(id);
- }
- }
- }
- // Now, move the folder we have received (the one with all the items in
- // it) to our last created (deepest) folder.
- gInventory.changeCategoryParent(catp, target_catp->getUUID(), false);
- gInventory.notifyObservers();
- // And rename it using the last folder name in the path.
- rename_category(&gInventory, catp->getUUID(), hierarchy[sub_folders - 1]);
- }
- // This struct is meant to be used in RLInterface::findAttachmentPointFromName
- // below
- typedef struct
- {
- LLViewerJointAttachment* attachment;
- S32 length;
- S32 index;
- } Candidate;
- LLViewerJointAttachment* RLInterface::findAttachmentPointFromName(std::string obj_name,
- bool exact_name)
- {
- // For each possible attachment point, check whether its name appears in
- // the name of the item.
- // We are going to scan the whole list of attachments, but we would not
- // decide which one to take right away.
- // Instead, for each matching point, we will store in lists the following
- // results:
- // - length of its name
- // - right-most index where it is found in the name
- // - a pointer to that attachment point
- // When we have that list, choose the highest index, and in case of
- // ex-aequo choose the longest length.
- if (obj_name.length() < 3)
- {
- // No need to bother: the shorter attachment name is "Top" with 3
- // characters...
- return NULL;
- }
- if (!isAgentAvatarValid())
- {
- llwarns << "NULL avatar pointer. Aborting." << llendl;
- return NULL;
- }
- LL_DEBUGS("RestrainedLove") << "Searching attachment name with "
- << (exact_name ? "exact match"
- : "partial matches") << " in: "
- << obj_name << LL_ENDL;
- LLStringUtil::toLower(obj_name);
- std::string attach_name;
- bool found_one = false;
- std::vector<Candidate> candidates;
- for (LLVOAvatar::attachment_map_t::iterator
- iter = gAgentAvatarp->mAttachmentPoints.begin(),
- end = gAgentAvatarp->mAttachmentPoints.end();
- iter != end; ++iter)
- {
- LLViewerJointAttachment* attachment = iter->second;
- if (attachment)
- {
- attach_name = attachment->getName();
- if (attach_name == "Avatar Center")
- {
- attach_name = "Root";
- }
- LLStringUtil::toLower(attach_name);
- #if 0
- LL_DEBUGS("RestrainedLove") << "Trying attachment: " << attach_name
- << LL_ENDL;
- #endif
- if (exact_name)
- {
- if (obj_name == attach_name)
- {
- return attachment;
- }
- }
- else
- {
- size_t ind = obj_name.rfind(attach_name);
- if (ind != std::string::npos &&
- obj_name.substr(0, ind).find('(') != std::string::npos &&
- obj_name.substr(ind).find(')') != std::string::npos)
- {
- Candidate new_candidate;
- new_candidate.index = ind;
- new_candidate.length = attach_name.length();
- new_candidate.attachment = attachment;
- candidates.emplace_back(new_candidate);
- found_one = true;
- LL_DEBUGS("RestrainedLove") << "New candidate: '"
- << attach_name << "', index="
- << new_candidate.index
- << ", length="
- << new_candidate.length
- << LL_ENDL;
- }
- }
- }
- }
- if (!found_one)
- {
- LL_DEBUGS("RestrainedLove") << "No attachment found." << LL_ENDL;
- return NULL;
- }
- // Now that we have at least one candidate, we have to decide which one to
- // return
- LLViewerJointAttachment* res = NULL;
- Candidate candidate;
- S32 ind_res = -1;
- S32 max_index = -1;
- S32 max_length = -1;
- S32 count = candidates.size();
- // Find the highest index
- for (S32 i = 0; i < count; ++i)
- {
- candidate = candidates[i];
- if (candidate.index > max_index)
- {
- max_index = candidate.index;
- }
- }
- // Find the longest match among the ones found at that index
- for (S32 i = 0; i < count; ++i)
- {
- candidate = candidates[i];
- if (candidate.index == max_index)
- {
- if (candidate.length > max_length)
- {
- max_length = candidate.length;
- ind_res = i;
- }
- }
- }
- // Return this attachment point
- if (ind_res > -1)
- {
- candidate = candidates[ind_res];
- res = candidate.attachment;
- if (res)
- {
- LL_DEBUGS("RestrainedLove") << "Returning: '" << res->getName()
- << "'" << LL_ENDL;
- }
- }
- return res;
- }
- LLViewerJointAttachment* RLInterface::findAttachmentPointFromParentName(LLInventoryItem* item)
- {
- if (item)
- {
- // Look in parent folder(this could be a no-mod item), use its name to
- // find the target attach point
- const LLUUID& parent_id = item->getParentUUID();
- LLViewerInventoryCategory* cat = gInventory.getCategory(parent_id);
- if (cat)
- {
- return findAttachmentPointFromName(cat->getName());
- }
- }
- return NULL;
- }
- S32 RLInterface::findAttachmentPointNumber(LLViewerJointAttachment* attachment)
- {
- if (isAgentAvatarValid())
- {
- for (LLVOAvatar::attachment_map_t::iterator
- iter = gAgentAvatarp->mAttachmentPoints.begin(),
- end = gAgentAvatarp->mAttachmentPoints.end();
- iter != end; ++iter)
- {
- if (iter->second == attachment)
- {
- return iter->first;
- }
- }
- }
- return -1;
- }
- // When an inventory item in #RLV gets attached and does not contain any
- // attachment info in its name, rename it for later (truncate the name first if
- // needed). Mod-ok items are renamed, else their parent folder, when two level
- // deep or more in the tree and named "New Folder", gets renamed, else a new
- // folder bearing the joint name is created and the item moved inside it.
- // This is called only by LLVOAvatarSelf::attachObject() and must be followed
- // with a 'gInventory.notifyObservers()' call as soon as appropriate. HB
- void RLInterface::addAttachmentPointName(LLViewerObject* vobj)
- {
- static LLCachedControl<bool> rename(gSavedSettings,
- "RestrainedLoveAutomaticRenameItems");
- if (!isAgentAvatarValid() || !rename) return;
- LLViewerInventoryItem* item =
- gInventory.getItem(vobj->getAttachmentItemID());
- if (!item || !item->isFinished() || !isUnderRlvShare(item) ||
- findAttachmentPointFromName(item->getName()))
- {
- // Nothing to do.
- return;
- }
- const LLUUID& item_id = item->getUUID();
- std::string attach_name = gAgentAvatarp->getAttachedPointName(item_id);
- LLStringUtil::toLower(attach_name);
- if (item->getPermissions().allowModifyBy(gAgentID))
- {
- // Truncate the original inventory item name if too long
- size_t max_name_length = DB_INV_ITEM_NAME_STR_LEN - 3 -
- attach_name.size();
- std::string item_name = item->getName();
- if (item_name.length() >= max_name_length)
- {
- item_name = item_name.substr(0, max_name_length);
- }
- // Add the name of the attach point at the end of the name of the item.
- // Note: this code uses AIS whenever enabled/possible. HB
- LLSD updates;
- updates["name"] = item_name + " (" + attach_name + ")";
- update_inventory_item(item_id, updates);
- return;
- }
- // This is a no-mod item, so we have to rename its parent category instead,
- // provided it is at least 2 levels deep in the #RLV tree, or to move it
- // inside a newly created sub-folder bearing the proper joint name.
- LLInventoryCategory* rlv_share = getRlvShare();
- const LLUUID& parent_id = item->getParentUUID();
- LLViewerInventoryCategory* parentp = gInventory.getCategory(parent_id);
- if (!parentp || (LLInventoryCategory*)parentp == rlv_share)
- {
- // No parent (!) or just under #RLV/: do not rename the #RLV/ folder !
- return;
- }
- // Check to see the folder is already bearing the right attachment name.
- if (findAttachmentPointFromName(parentp->getName()))
- {
- // Yes, so nothing to do...
- return;
- }
- std::string new_name = ".(" + attach_name + ")";
- // Do not rename the folder if it is only 1 level under #RLV/ (i.e. it is
- // an outfit sub-folder) and do not rename it either if the user renamed it
- // themselves, or if another call to this method already renamed it for
- // another no-mod attachment. I.e. only allow to rename a freshly created
- // "New Folder". HB
- LLInventoryCategory* gparentp =
- (LLInventoryCategory*)gInventory.getCategory(parentp->getParentUUID());
- const std::string& default_name =
- LLViewerFolderType::lookupNewCategoryName(LLFolderType::FT_NONE);
- if (gparentp != rlv_share && parentp->getName() == default_name)
- {
- // Rename the category as ".(attachment name)".
- // Note: this code uses AIS whenever enabled/possible. HB
- LLSD updates;
- updates["name"] = new_name;
- update_inventory_category(parent_id, updates, NULL);
- }
- // Else, create a new category with the appropriate name, and move the
- // no-mod item inside it. HB
- else
- {
- LLUUID cat_id = gInventory.createCategoryUDP(parent_id,
- LLFolderType::FT_NONE,
- new_name);
- move_inventory_item(item_id, cat_id, item->getName());
- }
- }
- // Handles the detach message to the sim here, after a check
- void RLInterface::detachObject(LLViewerObject* object)
- {
- if (object && (!gRLenabled || canDetach(object)))
- {
- LLMessageSystem* msg = gMessageSystemp;
- msg->newMessage("ObjectDetach");
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
- msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
- msg->nextBlockFast(_PREHASH_ObjectData);
- msg->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID());
- msg->sendReliable(gAgent.getRegionHost());
- }
- }
- void RLInterface::detachAllObjectsFromAttachment(LLViewerJointAttachment* attachment)
- {
- if (!attachment) return;
- // We need to remove all the objects from attachment->mAttachedObjects, one
- // by one. To do this, and in order to avoid any race condition, we are
- // going to copy the list and iterate on the copy instead of the original
- // which changes everytime something is attached and detached, asynchronously.
- LLViewerJointAttachment::attachedobjs_vec_t attached_objects =
- attachment->mAttachedObjects;
- for (S32 i = 0, count = attached_objects.size(); i < count; ++i)
- {
- LLViewerObject* object = attached_objects[i];
- detachObject(object);
- }
- }
- bool RLInterface::canDetachAllObjectsFromAttachment(LLViewerJointAttachment* attachment)
- {
- if (!attachment) return false;
- for (U32 i = 0; i < attachment->mAttachedObjects.size(); ++i)
- {
- LLViewerObject* object = attachment->mAttachedObjects[i];
- if (!canDetach(object))
- {
- return false;
- }
- }
- return true;
- }
- void RLInterface::fetchInventory(LLInventoryCategory* root)
- {
- // do this only once on login
- if (mInventoryFetched) return;
- bool last_step = false;
- if (!root)
- {
- root = getRlvShare();
- last_step = true;
- }
- if (root)
- {
- LLViewerInventoryCategory* viewer_root = (LLViewerInventoryCategory*)root;
- viewer_root->fetch();
- LLInventoryModel::cat_array_t* cats;
- LLInventoryModel::item_array_t* items;
- // Retrieve all the shared folders
- gInventory.getDirectDescendentsOf(viewer_root->getUUID(), cats, items);
- if (cats)
- {
- for (S32 i = 0, count = cats->size(); i < count; ++i)
- {
- LLInventoryCategory* cat = (LLInventoryCategory*)(*cats)[i];
- fetchInventory(cat);
- }
- }
- }
- if (last_step)
- {
- mInventoryFetched = true;
- }
- }
- // Note: 'recursive' is true in the case of an attachall command
- void RLInterface::forceAttach(const std::string& category, bool recursive,
- EAttachMethod how)
- {
- if (category.empty())
- {
- return;
- }
- // Find the category under RLV shared folder
- LLInventoryCategory* cat = getCategoryUnderRlvShare(category);
- if (!cat)
- {
- // No such category. Skip.
- return;
- }
- // We are replacing for now, but the name of the category could decide
- // otherwise
- bool replacing = how == AttachReplace || how == AttachOverOrReplace;
- // If the name of the category begins with a "+", then we force to stack
- // instead of replacing
- if (how == AttachOverOrReplace)
- {
- const std::string& name = cat->getName();
- if (!name.empty() && name[0] == '+')
- {
- replacing = false;
- }
- }
- // Retrieve all the objects contained in this folder
- LLInventoryModel::cat_array_t* cats;
- LLInventoryModel::item_array_t* items;
- gInventory.getDirectDescendentsOf(cat->getUUID(), cats, items);
- bool is_rlv_root = getRlvShare() == cat;
- if (!is_rlv_root && items)
- {
- // Wear them one by one
- for (S32 i = 0, count = items->size(); i < count; ++i)
- {
- LLViewerInventoryItem* item = (LLViewerInventoryItem*)(*items)[i];
- LL_DEBUGS("RestrainedLove") << "Trying to attach "
- << item->getName() << LL_ENDL;
- // This is an object to attach somewhere
- if (item && item->getType() == LLAssetType::AT_OBJECT)
- {
- LLViewerJointAttachment* attachpt =
- findAttachmentPointFromName(item->getName());
- if (attachpt)
- {
- LL_DEBUGS("RestrainedLove") << "Attaching item to "
- << attachpt->getName()
- << LL_ENDL;
- if (replacing)
- {
- // We are replacing => mimick rezAttachment without
- // confirmation dialog
- S32 number = findAttachmentPointNumber(attachpt);
- if (canDetach(attachpt->getName()) && canAttach(item))
- {
- attachObjectByUUID(item->getLinkedUUID(), number,
- true);
- }
- }
- else
- {
- // We are stacking => call rezAttachment directly
- gAppearanceMgr.rezAttachment(item, attachpt, false);
- }
- }
- else
- {
- // Attachment point is not in the name => stack
- gAppearanceMgr.rezAttachment(item, attachpt, false);
- }
- }
- // This is a piece of clothing
- else if (item->getType() == LLAssetType::AT_CLOTHING ||
- item->getType() == LLAssetType::AT_BODYPART)
- {
- gAppearanceMgr.wearInventoryItemOnAvatar(item, replacing);
- }
- // This is a gesture: activate
- else if (item->getType() == LLAssetType::AT_GESTURE)
- {
- if (!gGestureManager.isGestureActive(item->getLinkedUUID()))
- {
- gGestureManager.activateGesture(item->getLinkedUUID());
- }
- }
- // This is an environment setting: activate
- else if (item->getType() == LLAssetType::AT_SETTINGS)
- {
- if (!mContainsSetenv && !sRLNoSetEnv)
- {
- gEnvironment.setEnvironment(LLEnvironment::ENV_LOCAL,
- item->getAssetUUID());
- gEnvironment.setSelectedEnvironment(LLEnvironment::ENV_LOCAL,
- LLEnvironment::TRANSITION_INSTANT);
- }
- }
- }
- }
- if (!cats)
- {
- // No sub-folder, we are done !
- return;
- }
- // Not taken into account, we (possibly) recurse instead:
- LLInventoryModel::cat_array_t* subcats;
- // Actual no-mod item(s):
- LLInventoryModel::item_array_t* subcatitems;
- // Scan every sub-folder of the folder we are attaching, in order to attach
- // no-mod items. For each subfolder, attach the first item it contains
- // according to its name
- for (S32 i = 0, count = cats->size(); i < count; ++i)
- {
- LLViewerInventoryCategory* childp =
- (LLViewerInventoryCategory*)(*cats)[i];
- LLViewerJointAttachment* attachpt =
- findAttachmentPointFromName(childp->getName());
- if (!is_rlv_root && attachpt)
- {
- // This subfolder is properly named => attach the first item it
- // contains.
- gInventory.getDirectDescendentsOf(childp->getUUID(), subcats,
- subcatitems);
- if (subcatitems && subcatitems->size() == 1)
- {
- LLViewerInventoryItem* subcatitem =
- (LLViewerInventoryItem*)(*subcatitems)[0];
- if (subcatitem &&
- subcatitem->getType() == LLAssetType::AT_OBJECT &&
- !subcatitem->getPermissions().allowModifyBy(gAgentID) &&
- findAttachmentPointFromParentName(subcatitem))
- {
- // It is no-mod and its parent is named correctly: we use
- // the attach point from the name of the folder, not the
- // no-mod item
- if (replacing)
- {
- // Mimick rezAttachment without a confirmation dialog
- S32 number = findAttachmentPointNumber(attachpt);
- if (canDetach(attachpt->getName()) &&
- canAttach(subcatitem))
- {
- attachObjectByUUID(subcatitem->getLinkedUUID(),
- number, true);
- }
- }
- else
- {
- // We are stacking => call rezAttachment directly
- gAppearanceMgr.rezAttachment(subcatitem, attachpt,
- false);
- }
- }
- }
- }
- if (recursive)
- {
- const std::string& name = childp->getName();
- if (name.empty() || name[0] != '.')
- {
- // attachall and not invisible
- forceAttach(getFullPath(childp), recursive, how);
- }
- }
- }
- }
- bool RLInterface::forceDetachByName(const std::string& category,
- bool recursive)
- {
- if (!isAgentAvatarValid())
- {
- return false;
- }
- if (category.empty())
- {
- return true; // Nothing to do = success
- }
- // Find the category under RLV shared folder
- LLInventoryCategory* cat = getCategoryUnderRlvShare(category);
- if (!cat)
- {
- return true; // Nothing to do = success
- }
- bool is_rlv_root = getRlvShare() == cat;
- if (mHandleNoStrip)
- {
- std::string name = cat->getName();
- LLStringUtil::toLower(name);
- if (name.find(RL_PROTECTED_FOLDER_TAG) != std::string::npos)
- {
- return false; // Protected folder !
- }
- }
- // Retrieve all the objects contained in this folder
- LLInventoryModel::cat_array_t* cats;
- LLInventoryModel::item_array_t* items;
- gInventory.getDirectDescendentsOf(cat->getUUID(), cats, items);
- if (!is_rlv_root && items)
- {
- // Un-wear them one by one
- for (S32 i = 0, count = items->size(); i < count; ++i)
- {
- LLViewerInventoryItem* item = (LLViewerInventoryItem*)(*items)[i];
- LL_DEBUGS("RestrainedLove") << "Trying to detach "
- << item->getName() << LL_ENDL;
- if (item->getType() == LLAssetType::AT_OBJECT)
- {
- // This is an attached object, find the attachpoint from which
- // to detach
- for (LLVOAvatar::attachment_map_t::iterator
- iter = gAgentAvatarp->mAttachmentPoints.begin(),
- end = gAgentAvatarp->mAttachmentPoints.end();
- iter != end; ++iter)
- {
- LLViewerJointAttachment* attachment = iter->second;
- LLViewerObject* object =
- gAgentAvatarp->getWornAttachment(item->getUUID());
- if (object && attachment &&
- attachment->isObjectAttached(object))
- {
- detachObject(object);
- break;
- }
- }
- }
- else if (item->getType() == LLAssetType::AT_CLOTHING)
- {
- // This is a piece of clothing: remove
- if (canDetach(item))
- {
- removeWearableItemFromAvatar(item);
- }
- }
- else if (item->getType() == LLAssetType::AT_GESTURE)
- {
- // This is a gesture: deactivate
- if (gGestureManager.isGestureActive(item->getLinkedUUID()))
- {
- gGestureManager.deactivateGesture(item->getLinkedUUID());
- }
- }
- #if 0 // Do nothing because we do not know what to replace it with... HB
- // This is an environment setting: deactivate
- else if (item->getType() == LLAssetType::AT_SETTINGS)
- {
- if (!mContainsSetenv && !sRLNoSetEnv)
- {
- gEnvironment.clearEnvironment(LLEnvironment::ENV_LOCAL);
- gEnvironment.setSelectedEnvironment(LLEnvironment::ENV_LOCAL,
- LLEnvironment::TRANSITION_INSTANT);
- }
- }
- #endif
- }
- }
- if (!cats)
- {
- // No sub-folder, we are done !
- return true;
- }
- // Not taken into account, we (possibly) recurse instead:
- LLInventoryModel::cat_array_t* subcats;
- // Actual no-mod item(s):
- LLInventoryModel::item_array_t* subcatitems;
- // For each subfolder, detach the first item it contains (only for single
- // no-mod items contained in appropriately named folders)
- for (S32 i = 0, count = cats->size(); i < count; ++i)
- {
- LLViewerInventoryCategory* childp =
- (LLViewerInventoryCategory*)(*cats)[i];
- if (mHandleNoStrip)
- {
- std::string name = childp->getName();
- LLStringUtil::toLower(name);
- if (name.find(RL_PROTECTED_FOLDER_TAG) != std::string::npos)
- {
- continue; // Protected folder...
- }
- }
- gInventory.getDirectDescendentsOf(childp->getUUID(), subcats,
- subcatitems);
- if (!is_rlv_root && subcatitems && subcatitems->size() == 1)
- {
- // Only one item...
- LLViewerInventoryItem* subcatitem =
- (LLViewerInventoryItem*)(*subcatitems)[0];
- if (subcatitem &&
- subcatitem->getType() == LLAssetType::AT_OBJECT &&
- !subcatitem->getPermissions().allowModifyBy(gAgentID) &&
- findAttachmentPointFromParentName(subcatitem))
- {
- // ... and it is no-mod and its parent is named correctly
- // detach this object. Find the attachpoint from which to
- // detach.
- for (LLVOAvatar::attachment_map_t::iterator
- iter = gAgentAvatarp->mAttachmentPoints.begin(),
- end = gAgentAvatarp->mAttachmentPoints.end();
- iter != end; ++iter)
- {
- LLViewerJointAttachment* attachment = iter->second;
- LLViewerObject* object =
- gAgentAvatarp->getWornAttachment(subcatitem->getUUID());
- if (object && attachment &&
- attachment->isObjectAttached(object))
- {
- detachObject(object);
- break;
- }
- }
- }
- }
- if (recursive)
- {
- const std::string& name = childp->getName();
- if (name.empty() || name[0] != '.')
- {
- // detachall and not invisible
- forceDetachByName(getFullPath(childp), recursive);
- }
- }
- }
- return true;
- }
- #if LL_CLANG
- // Ignore the '°' encoding in separators below
- # pragma clang diagnostic ignored "-Winvalid-source-encoding"
- #endif
- std::string RLInterface::stringReplace(std::string s, std::string what_str,
- const std::string& by_str,
- bool case_sensitive)
- {
- if (what_str.empty() || what_str == " ")
- {
- return s; // Avoid an infinite loop
- }
- size_t len_by_str = by_str.length();
- if (len_by_str == 0)
- {
- len_by_str = 1; // Avoid an infinite loop
- }
- size_t len_what_str = what_str.length();
- size_t ind;
- while ((ind = s.find("%20")) != std::string::npos) // Unescape
- {
- s = s.replace(ind, 3, " ");
- }
- std::string lower = s;
- if (!case_sensitive)
- {
- LLStringUtil::toLower(lower);
- LLStringUtil::toLower(what_str);
- }
- static std::string separators = " .,:;!?'\"_()[]{}*/+-=°~&|@#%$`<>\\\t\n";
- size_t len_s = s.length();
- size_t old_ind = 0;
- while ((ind = lower.find(what_str, old_ind)) != std::string::npos)
- {
- char prec = ' ';
- if (ind > 0)
- {
- prec = s[ind - 1];
- }
- char succ = ' ';
- if (ind < len_s - len_what_str - 1)
- {
- succ = s[ind + len_what_str];
- }
- if (separators.find(prec) != std::string::npos &&
- separators.find(succ) != std::string::npos)
- {
- s = s.replace(ind, len_what_str, by_str);
- lower = s;
- if (!case_sensitive)
- {
- LLStringUtil::toLower(lower);
- }
- }
- old_ind = ind + len_by_str;
- }
- return s;
- }
- std::string RLInterface::getDummyName(std::string name,
- EChatAudible audible)
- {
- std::string res;
- size_t len = name.length();
- if (len == 0) return res;
- // We use mLaunchTimestamp in order to modify the scrambling when the
- // session restarts (it stays consistent during the session though). But in
- // crashy situations, let's not make it change at EVERY session, more like
- // once a day or so. A day is 86400 seconds, the closest power of two is
- // 65536, that is a 16 bits shift. Very lame hash function I know... but it
- // should be linear enough (the old length method was way too gaussian with
- // a peak at 11 to 16 characters)
- unsigned char hash = name[0] + name[len - 1] + len +
- (mLaunchTimestamp >> 16);
- unsigned char mod = hash % 28;
- switch (mod)
- {
- case 0:
- res = "A resident";
- break;
- case 1:
- res = "This resident";
- break;
- case 2:
- res = "That resident";
- break;
- case 3:
- res = "An individual";
- break;
- case 4:
- res = "This individual";
- break;
- case 5:
- res = "That individual";
- break;
- case 6:
- res = "A person";
- break;
- case 7:
- res = "This person";
- break;
- case 8:
- res = "That person";
- break;
- case 9:
- res = "A stranger";
- break;
- case 10:
- res = "This stranger";
- break;
- case 11:
- res = "That stranger";
- break;
- case 12:
- res = "A human being";
- break;
- case 13:
- res = "This human being";
- break;
- case 14:
- res = "That human being";
- break;
- case 15:
- res = "An agent";
- break;
- case 16:
- res = "This agent";
- break;
- case 17:
- res = "That agent";
- break;
- case 18:
- res = "A soul";
- break;
- case 19:
- res = "This soul";
- break;
- case 20:
- res = "That soul";
- break;
- case 21:
- res = "Somebody";
- break;
- case 22:
- res = "Anonymous one";
- break;
- case 23:
- res = "Someone";
- break;
- case 24:
- res = "Mysterious one";
- break;
- case 25:
- res = "An unknown being";
- break;
- case 26:
- res = "Unidentified one";
- break;
- default:
- res = "An unknown person";
- }
- if (audible == CHAT_AUDIBLE_BARELY)
- {
- res += " afar";
- }
- return res;
- }
- // Hides every occurrence of the name of anybody around (found in cache, so not
- // completely accurate neither completely immediate).
- std::string RLInterface::getCensoredMessage(std::string str)
- {
- uuid_vec_t avatar_ids;
- gWorld.getAvatars(avatar_ids);
- LLUUID avatar_id;
- std::string name, dummy_name;
- LLAvatarName avatar_name;
- for (U32 i = 0, count = avatar_ids.size(); i < count; ++i)
- {
- avatar_id = avatar_ids[i];
- // If listed in exceptions, skip this avatar
- if (mExceptions.count(avatar_id)) continue;
- if (gCacheNamep && gCacheNamep->getFullName(avatar_id, name))
- {
- dummy_name = getDummyName(name);
- str = stringReplace(str, name, dummy_name); // Legacy name
- size_t j = name.find(" Resident");
- if (j > 0)
- {
- name = name.substr(0, j);
- // legacy name, without " Resident"
- str = stringReplace(str, name, dummy_name);
- }
- }
- if (LLAvatarNameCache::get(avatar_id, &avatar_name))
- {
- if (!avatar_name.mIsDisplayNameDefault)
- {
- name = avatar_name.mDisplayName;
- dummy_name = getDummyName(name);
- str = stringReplace(str, name, dummy_name); // Display name
- }
- }
- }
- return str;
- }
- std::string RLInterface::getCensoredLocation(std::string str)
- {
- if (gAgent.getRegion())
- {
- // Hide every occurrence of the Parcel name
- str = stringReplace(str, mParcelName, "(Parcel hidden)");
- // Hide every occurrence of the Region name
- str = stringReplace(str, gAgent.getRegion()->getName(),
- "(Region hidden)");
- }
- return str;
- }
- bool RLInterface::forceEnvironment(std::string command, std::string option)
- {
- // Compatibility with RLVa
- LLStringUtil::replaceChar(option, '/', ';');
- // Reset this since we are going to change any loaded preset...
- mLastLoadedPreset.clear();
- // 'command' is "setenv_<something>"
- F32 val = (F32)atof(option.c_str());
- constexpr size_t length = 7; // Size of "setenv_"
- command = command.substr(length);
- LLSettingsSky::ptr_t skyp;
- if (gEnvironment.hasEnvironment(LLEnvironment::ENV_LOCAL))
- {
- if (gEnvironment.getEnvironmentDay(LLEnvironment::ENV_LOCAL))
- {
- // We have a full day cycle in the local environment: freeze
- // the sky.
- skyp = gEnvironment.getEnvironmentFixedSky(LLEnvironment::ENV_LOCAL)->buildClone();
- gEnvironment.setEnvironment(LLEnvironment::ENV_LOCAL, skyp, 0);
- }
- else
- {
- // Otherwise we can just use the local sky.
- skyp = gEnvironment.getEnvironmentFixedSky(LLEnvironment::ENV_LOCAL);
- }
- }
- else
- {
- // Use a copy of the parcel environment sky instead.
- skyp = gEnvironment.getEnvironmentFixedSky(LLEnvironment::ENV_PARCEL,
- true)->buildClone();
- gEnvironment.setEnvironment(LLEnvironment::ENV_LOCAL, skyp, 0);
- }
- gEnvironment.setSelectedEnvironment(LLEnvironment::ENV_LOCAL,
- LLEnvironment::TRANSITION_INSTANT);
- if (command == "daytime")
- {
- if (val > 1.f)
- {
- val = 1.f;
- }
- if (val >= 0.f)
- {
- gEnvironment.setFixedTimeOfDay(val);
- }
- else
- {
- gSavedSettings.setBool("UseParcelEnvironment", true);
- }
- }
- else if (command == "reset") // Synonym for "daytime:-1"
- {
- gEnvironment.clearEnvironment(LLEnvironment::ENV_LOCAL);
- gEnvironment.setSelectedEnvironment(LLEnvironment::ENV_LOCAL,
- LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "bluehorizonr")
- {
- LLColor3 bluehorizon = skyp->getBlueHorizon();
- bluehorizon.mV[0] = val * 2.f;
- skyp->setBlueHorizon(bluehorizon);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "bluehorizong")
- {
- LLColor3 bluehorizon = skyp->getBlueHorizon();
- bluehorizon.mV[1] = val * 2.f;
- skyp->setBlueHorizon(bluehorizon);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "bluehorizonb")
- {
- LLColor3 bluehorizon = skyp->getBlueHorizon();
- bluehorizon.mV[2] = val * 2.f;
- skyp->setBlueHorizon(bluehorizon);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "bluehorizoni")
- {
- LLColor3 bluehorizon = skyp->getBlueHorizon();
- F32 old_intensity = llmax(bluehorizon.mV[0], bluehorizon.mV[1],
- bluehorizon.mV[2]);
- if (val == 0.f || old_intensity == 0.f)
- {
- bluehorizon.mV[0] = bluehorizon.mV[1] =
- bluehorizon.mV[2] = val * 2.f;
- }
- else
- {
- F32 factor = val * 2.f / old_intensity;
- bluehorizon.mV[0] *= factor;
- bluehorizon.mV[1] *= factor;
- bluehorizon.mV[2] *= factor;
- }
- skyp->setBlueHorizon(bluehorizon);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "bluehorizon")
- {
- std::deque<std::string> tokens = parse(option, ";");
- F32 r = atof(tokens[0].c_str()) * 2.f;
- F32 g = atof(tokens[1].c_str()) * 2.f;
- F32 b = atof(tokens[2].c_str()) * 2.f;
- LLColor3 bluehorizon = skyp->getBlueHorizon();
- bluehorizon.mV[0] = r;
- bluehorizon.mV[1] = g;
- bluehorizon.mV[2] = b;
- skyp->setBlueHorizon(bluehorizon);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "bluedensityr")
- {
- LLColor3 bluedensity = skyp->getBlueDensity();
- bluedensity.mV[0] = val * 2.f;
- skyp->setBlueDensity(bluedensity);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "bluedensityg")
- {
- LLColor3 bluedensity = skyp->getBlueDensity();
- bluedensity.mV[1] = val * 2.f;
- skyp->setBlueDensity(bluedensity);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "bluedensityb")
- {
- LLColor3 bluedensity = skyp->getBlueDensity();
- bluedensity.mV[2] = val * 2.f;
- skyp->setBlueDensity(bluedensity);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "bluedensityi")
- {
- LLColor3 bluedensity = skyp->getBlueDensity();
- F32 old_intensity = llmax(bluedensity.mV[0], bluedensity.mV[1],
- bluedensity.mV[2]);
- if (val == 0.f || old_intensity == 0.f)
- {
- bluedensity.mV[0] = bluedensity.mV[1] =
- bluedensity.mV[2] = val * 2.f;
- }
- else
- {
- F32 factor = val * 2.f / old_intensity;
- bluedensity.mV[0] *= factor;
- bluedensity.mV[1] *= factor;
- bluedensity.mV[2] *= factor;
- }
- skyp->setBlueDensity(bluedensity);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "bluedensity")
- {
- std::deque<std::string> tokens = parse(option, ";");
- F32 r = atof(tokens[0].c_str()) * 2.f;
- F32 g = atof(tokens[1].c_str()) * 2.f;
- F32 b = atof(tokens[2].c_str()) * 2.f;
- LLColor3 bluedensity = skyp->getBlueDensity();
- bluedensity.mV[0] = r;
- bluedensity.mV[1] = g;
- bluedensity.mV[2] = b;
- skyp->setBlueDensity(bluedensity);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "hazehorizon")
- {
- skyp->setHazeHorizon(val);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "hazedensity")
- {
- skyp->setHazeDensity(val * 4.f);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "densitymultiplier")
- {
- skyp->setDensityMultiplier(val * 0.001f);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "distancemultiplier")
- {
- skyp->setDistanceMultiplier(val);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "maxaltitude")
- {
- skyp->setMaxY(val);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "sunmooncolorr" || command == "sunlightcolorr")
- {
- LLColor3 suncolour= skyp->getSunlightColor();
- suncolour.mV[0] = val * 3.f;
- skyp->setSunlightColor(suncolour);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "sunmooncolorg" || command == "sunlightcolorg")
- {
- LLColor3 suncolour= skyp->getSunlightColor();
- suncolour.mV[1] = val * 3.f;
- skyp->setSunlightColor(suncolour);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "sunmooncolorb" || command == "sunlightcolorb")
- {
- LLColor3 suncolour= skyp->getSunlightColor();
- suncolour.mV[2] = val * 3.f;
- skyp->setSunlightColor(suncolour);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "sunmooncolori" || command == "sunlightcolori")
- {
- LLColor3 suncolour= skyp->getSunlightColor();
- F32 old_intensity = llmax(suncolour.mV[0], suncolour.mV[1],
- suncolour.mV[2]);
- if (val == 0.f || old_intensity == 0.f)
- {
- suncolour.mV[0] = suncolour.mV[1] = suncolour.mV[2] = val * 3.f;
- }
- else
- {
- F32 factor = val * 3.f / old_intensity;
- suncolour.mV[0] *= factor;
- suncolour.mV[1] *= factor;
- suncolour.mV[2] *= factor;
- }
- skyp->setSunlightColor(suncolour);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "sunmooncolor" || command == "sunlightcolor")
- {
- std::deque<std::string> tokens = parse(option, ";");
- F32 r = atof(tokens[0].c_str()) * 3.f;
- F32 g = atof(tokens[1].c_str()) * 3.f;
- F32 b = atof(tokens[2].c_str()) * 3.f;
- LLColor3 suncolour = skyp->getSunlightColor();
- suncolour.mV[0] = r;
- suncolour.mV[1] = g;
- suncolour.mV[2] = b;
- skyp->setSunlightColor(suncolour);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "ambientr")
- {
- LLColor3 ambientcolor = skyp->getAmbientColor();
- ambientcolor.mV[0] = val * 3.f;
- skyp->setAmbientColor(ambientcolor);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "ambientg")
- {
- LLColor3 ambientcolor = skyp->getAmbientColor();
- ambientcolor.mV[1] = val * 3.f;
- skyp->setAmbientColor(ambientcolor);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "ambientb")
- {
- LLColor3 ambientcolor = skyp->getAmbientColor();
- ambientcolor.mV[2] = val * 3.f;
- skyp->setAmbientColor(ambientcolor);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "ambienti")
- {
- LLColor3 ambientcolor = skyp->getAmbientColor();
- F32 old_intensity = llmax(ambientcolor.mV[0], ambientcolor.mV[1],
- ambientcolor.mV[2]);
- if (val == 0.f || old_intensity == 0.f)
- {
- ambientcolor.mV[0] = ambientcolor.mV[1] = ambientcolor.mV[2] =
- val * 3.f;
- }
- else
- {
- F32 factor = val * 3.f / old_intensity;
- ambientcolor.mV[0] *= factor;
- ambientcolor.mV[1] *= factor;
- ambientcolor.mV[2] *= factor;
- }
- skyp->setAmbientColor(ambientcolor);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "ambient")
- {
- std::deque<std::string> tokens = parse(option, ";");
- F32 r = atof(tokens[0].c_str()) * 3.f;
- F32 g = atof(tokens[1].c_str()) * 3.f;
- F32 b = atof(tokens[2].c_str()) * 3.f;
- LLColor3 ambientcolor = skyp->getAmbientColor();
- ambientcolor.mV[0] = r;
- ambientcolor.mV[1] = g;
- ambientcolor.mV[2] = b;
- skyp->setAmbientColor(ambientcolor);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "sunglowfocus")
- {
- LLColor3 glow = skyp->getGlow();
- glow.mV[2] = val * -5.f;
- skyp->setGlow(glow);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "sunglowsize")
- {
- LLColor3 glow = skyp->getGlow();
- glow.mV[0] = val * 20.f;
- skyp->setGlow(glow);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "scenegamma")
- {
- skyp->setGamma(val);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "sunazim" || command == "sunazimuth")
- {
- val -= F_TWO_PI * floorf((val + F_PI) / F_TWO_PI);
- LLQuaternion orig_quat = skyp->getSunRotation();
- F32 roll, pitch, yaw;
- orig_quat.getEulerAngles(&roll, &pitch, &yaw);
- LLQuaternion rotation_world;
- rotation_world.setEulerAngles(0.f, 0.f, val - yaw);
- rotation_world.normalize();
- LLQuaternion new_quat = orig_quat * rotation_world;
- skyp->setSunRotation(new_quat);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "sunelev" || command == "sunelevation")
- {
- val = -llclamp(val, -F_PI_BY_TWO, F_PI_BY_TWO);
- LLQuaternion orig_quat = skyp->getSunRotation();
- F32 roll, pitch, yaw;
- orig_quat.getEulerAngles(&roll, &pitch, &yaw);
- LLQuaternion pitch_quat;
- pitch_quat.setAngleAxis(val, 0.f, 1.f, 0.f);
- LLQuaternion yaw_quat;
- yaw_quat.setAngleAxis(yaw, 0.f, 0.f, 1.f);
- LLQuaternion new_quat = pitch_quat * yaw_quat;
- skyp->setSunRotation(new_quat);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "moonazim" || command == "moonazimuth")
- {
- val -= F_TWO_PI * floorf((val + F_PI) / F_TWO_PI);
- LLQuaternion orig_quat = skyp->getMoonRotation();
- F32 roll, pitch, yaw;
- orig_quat.getEulerAngles(&roll, &pitch, &yaw);
- LLQuaternion rotation_world;
- rotation_world.setEulerAngles(0.f, 0.f, val - yaw);
- rotation_world.normalize();
- LLQuaternion new_quat = orig_quat * rotation_world;
- skyp->setMoonRotation(new_quat);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "moonelev" || command == "moonelevation")
- {
- val = -llclamp(val, -F_PI_BY_TWO, F_PI_BY_TWO);
- LLQuaternion orig_quat = skyp->getMoonRotation();
- F32 roll, pitch, yaw;
- orig_quat.getEulerAngles(&roll, &pitch, &yaw);
- LLQuaternion pitch_quat;
- pitch_quat.setAngleAxis(val, 0.f, 1.f, 0.f);
- LLQuaternion yaw_quat;
- yaw_quat.setAngleAxis(yaw, 0.f, 0.f, 1.f);
- LLQuaternion new_quat = pitch_quat * yaw_quat;
- skyp->setMoonRotation(new_quat);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- #if 0 // *TODO: implement the EE approximation
- else if (command == "sunmoonposition")
- {
- }
- else if (command == "eastangle")
- {
- }
- #endif
- else if (command == "starbrightness")
- {
- skyp->setStarBrightness(val);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "cloudcolorr")
- {
- LLColor3 cloudcolor = skyp->getCloudColor();
- cloudcolor.mV[0] = val;
- skyp->setCloudColor(cloudcolor);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "cloudcolorg")
- {
- LLColor3 cloudcolor = skyp->getCloudColor();
- cloudcolor.mV[1] = val;
- skyp->setCloudColor(cloudcolor);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "cloudcolorb")
- {
- LLColor3 cloudcolor = skyp->getCloudColor();
- cloudcolor.mV[2] = val;
- skyp->setCloudColor(cloudcolor);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "cloudcolori")
- {
- LLColor3 cloudcolor = skyp->getCloudColor();
- F32 old_intensity = llmax(cloudcolor.mV[0], cloudcolor.mV[1],
- cloudcolor.mV[2]);
- if (val == 0.f || old_intensity == 0.f)
- {
- cloudcolor.mV[0] = cloudcolor.mV[1] = cloudcolor.mV[2] = val;
- }
- else
- {
- F32 factor = val / old_intensity;
- cloudcolor.mV[0] *= factor;
- cloudcolor.mV[1] *= factor;
- cloudcolor.mV[2] *= factor;
- }
- skyp->setCloudColor(cloudcolor);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "cloudcolor")
- {
- std::deque<std::string> tokens = parse(option, ";");
- F32 r = atof(tokens[0].c_str());
- F32 g = atof(tokens[1].c_str());
- F32 b = atof(tokens[2].c_str());
- LLColor3 cloudcolor = skyp->getCloudColor();
- cloudcolor.mV[0] = r;
- cloudcolor.mV[1] = g;
- cloudcolor.mV[2] = b;
- skyp->setCloudColor(cloudcolor);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "cloudx" || command == "clouddensityx")
- {
- LLColor3 clouddetail = skyp->getCloudPosDensity1();
- clouddetail.mV[0] = val;
- skyp->setCloudPosDensity1(clouddetail);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "cloudy" || command == "clouddensityy")
- {
- LLColor3 clouddetail = skyp->getCloudPosDensity1();
- clouddetail.mV[1] = val;
- skyp->setCloudPosDensity1(clouddetail);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "cloudd" || command == "clouddensityd")
- {
- LLColor3 clouddetail = skyp->getCloudPosDensity1();
- clouddetail.mV[2] = val;
- skyp->setCloudPosDensity1(clouddetail);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "cloud" || command == "clouddensity")
- {
- std::deque<std::string> tokens = parse(option, ";");
- F32 r = atof(tokens[0].c_str());
- F32 g = atof(tokens[1].c_str());
- F32 b = atof(tokens[2].c_str());
- LLColor3 clouddetail = skyp->getCloudPosDensity1();
- clouddetail.mV[0] = r;
- clouddetail.mV[1] = g;
- clouddetail.mV[2] = b;
- skyp->setCloudPosDensity1(clouddetail);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "clouddetailx")
- {
- LLColor3 clouddetail = skyp->getCloudPosDensity2();
- clouddetail.mV[0] = val;
- skyp->setCloudPosDensity2(clouddetail);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "clouddetaily")
- {
- LLColor3 clouddetail = skyp->getCloudPosDensity2();
- clouddetail.mV[1] = val;
- skyp->setCloudPosDensity2(clouddetail);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "clouddetaild")
- {
- LLColor3 clouddetail = skyp->getCloudPosDensity2();
- clouddetail.mV[2] = val;
- skyp->setCloudPosDensity2(clouddetail);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "clouddetail")
- {
- std::deque<std::string> tokens = parse(option, ";");
- F32 r = atof(tokens[0].c_str());
- F32 g = atof(tokens[1].c_str());
- F32 b = atof(tokens[2].c_str());
- LLColor3 clouddetail = skyp->getCloudPosDensity2();
- clouddetail.mV[0] = r;
- clouddetail.mV[1] = g;
- clouddetail.mV[2] = b;
- skyp->setCloudPosDensity2(clouddetail);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "cloudcoverage")
- {
- skyp->setCloudShadow(val);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "cloudscale")
- {
- skyp->setCloudScale(val);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "cloudvariance")
- {
- skyp->setCloudVariance(val);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "cloudscrollx")
- {
- skyp->setCloudScrollRateX(val + 10.f);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "cloudscrolly")
- {
- skyp->setCloudScrollRateY(val + 10.f);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "cloudscroll")
- {
- std::deque<std::string> tokens = parse(option, ";");
- F32 x = atof(tokens[0].c_str()) + 10.f;
- F32 y = atof(tokens[1].c_str()) + 10.f;
- skyp->setCloudScrollRateX(x + 10.f);
- skyp->setCloudScrollRateY(y + 10.f);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "moisturelevel")
- {
- skyp->setSkyMoistureLevel(val);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "dropletradius")
- {
- skyp->setSkyDropletRadius(val);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "icelevel")
- {
- skyp->setSkyDropletRadius(val);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "sunscale")
- {
- skyp->setSunScale(val);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "moonscale")
- {
- skyp->setMoonScale(val);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "moonbrightness")
- {
- skyp->setMoonBrightness(val);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "sunimage" || command == "suntexture")
- {
- LLUUID id;
- id.set(option, false);
- skyp->setSunTextureId(id);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "moonimage" || command == "moontexture")
- {
- LLUUID id;
- id.set(option, false);
- skyp->setMoonTextureId(id);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "cloudimage" || command == "cloudtexture")
- {
- LLUUID id;
- id.set(option, false);
- skyp->setCloudNoiseTextureId(id);
- skyp->update();
- gEnvironment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT);
- }
- else if (command == "preset" || command == "asset")
- {
- // This is an extension to RLV's API, allowing to choose what type of
- // setting to search for: e.g. @setenv_preset:sky|blizzard=force will
- // search for "blizzard" in sky settings only. An especially useful
- // case is when a setting name is shared by all types, like "Default",
- // e.g. @setenv_preset:day|default=force will load the default day
- // setting.
- // The pipe ('|') was chosen as a separator, because it is an illegal
- // character for inventory assets names and file names.
- bool skies = true;
- bool days = true;
- bool waters = true;
- size_t i = option.find('|');
- if (i != std::string::npos && i < option.size() - 1)
- {
- std::string category = option.substr(0, i);
- option.erase(0, i);
- skies = category == "sky";
- days = category == "day";
- waters = category == "water";
- }
- // Apply any preset matching the name in 'option' (ignoring case), be
- // it an inventory setting, a Windlight setting, sky, day or water
- // setting (in this order of preferences). When successfully loaded,
- // the preset will be converted to EE settings and Windlight overriding
- // is enabled if it was not in force already.
- if ((skies && LLEnvSettingsSky::applyPresetByName(option, true)) ||
- (days && LLEnvSettingsDay::applyPresetByName(option, true)) ||
- (waters && LLEnvSettingsWater::applyPresetByName(option, true)))
- {
- mLastLoadedPreset = option;
- }
- }
- return true;
- }
- std::string RLInterface::getEnvironment(std::string command)
- {
- F32 res = 0.f;
- constexpr size_t length = 7; // Size of "getenv_"
- command = command.substr(length);
- const LLSettingsSky::ptr_t& skyp = gEnvironment.getCurrentSky();
- if (command == "daytime")
- {
- static LLCachedControl<bool> estate(gSavedSettings, "UseWLEstateTime");
- if (gSavedSettings.getBool("UseParcelEnvironment"))
- {
- res = -1.f;
- }
- else if (skyp->getIsSunUp())
- {
- res = 1.f;
- }
- }
- else if (command == "bluehorizonr")
- {
- res = skyp->getBlueHorizon().mV[0] * 0.5f;
- }
- else if (command == "bluehorizong")
- {
- res = skyp->getBlueHorizon().mV[1] * 0.5f;
- }
- else if (command == "bluehorizonb")
- {
- res = skyp->getBlueHorizon().mV[2] * 0.5f;
- }
- else if (command == "bluehorizoni")
- {
- LLColor3 bluehorizon = skyp->getBlueHorizon();
- res = llmax(bluehorizon.mV[0], bluehorizon.mV[1], bluehorizon.mV[2]) *
- 0.5f;
- }
- else if (command == "bluehorizon")
- {
- std::stringstream str;
- str << skyp->getBlueHorizon().mV[0] * 0.5f << ";";
- str << skyp->getBlueHorizon().mV[1] * 0.5f << ";";
- str << skyp->getBlueHorizon().mV[2] * 0.5f;
- return str.str();
- }
- else if (command == "bluedensityr")
- {
- res = skyp->getBlueDensity().mV[0] * 0.5f;
- }
- else if (command == "bluedensityg")
- {
- res = skyp->getBlueDensity().mV[1] * 0.5f;
- }
- else if (command == "bluedensityb")
- {
- res = skyp->getBlueDensity().mV[2] * 0.5f;
- }
- else if (command == "bluedensityi")
- {
- LLColor3 bluedensity = skyp->getBlueDensity();
- res = llmax(bluedensity.mV[0], bluedensity.mV[1], bluedensity.mV[2]) *
- 0.5f;
- }
- else if (command == "bluedensity")
- {
- std::stringstream str;
- str << skyp->getBlueDensity().mV[0] * 0.5f << ";";
- str << skyp->getBlueDensity().mV[1] * 0.5f << ";";
- str << skyp->getBlueDensity().mV[2] * 0.5f;
- return str.str();
- }
- else if (command == "hazehorizon")
- {
- res = skyp->getHazeHorizon();
- }
- else if (command == "hazedensity")
- {
- res = skyp->getHazeDensity() * 0.25f;
- }
- else if (command == "densitymultiplier")
- {
- res = skyp->getDensityMultiplier() * 1000.f;
- }
- else if (command == "distancemultiplier")
- {
- res = skyp->getDistanceMultiplier();
- }
- else if (command == "maxaltitude")
- {
- res = skyp->getMaxY();
- }
- else if (command == "sunmooncolorr")
- {
- res = skyp->getSunlightColor().mV[0] / 3.f;
- }
- else if (command == "sunmooncolorg")
- {
- res = skyp->getSunlightColor().mV[1] / 3.f;
- }
- else if (command == "sunmooncolorb")
- {
- res = skyp->getSunlightColor().mV[2] / 3.f;
- }
- else if (command == "sunmooncolori")
- {
- LLColor3 sunlightcolor = skyp->getSunlightColor();
- res = llmax(sunlightcolor.mV[0],sunlightcolor.mV[1],
- sunlightcolor.mV[2]) / 3.f;
- }
- else if (command == "sunmooncolor")
- {
- std::stringstream str;
- str << skyp->getSunlightColor().mV[0] / 3.f << ";";
- str << skyp->getSunlightColor().mV[1] / 3.f << ";";
- str << skyp->getSunlightColor().mV[2] / 3.f;
- return str.str();
- }
- else if (command == "ambientr")
- {
- res = skyp->getAmbientColor().mV[0] / 3.f;
- }
- else if (command == "ambientg")
- {
- res = skyp->getAmbientColor().mV[1] / 3.f;
- }
- else if (command == "ambientb")
- {
- res = skyp->getAmbientColor().mV[2] / 3.f;
- }
- else if (command == "ambienti")
- {
- LLColor3 ambientcolor = skyp->getAmbientColor();
- res = llmax(ambientcolor.mV[0], ambientcolor.mV[1],
- ambientcolor.mV[2]) / 3.f;
- }
- else if (command == "ambient")
- {
- std::stringstream str;
- str << skyp->getAmbientColor().mV[0] / 3.f << ";";
- str << skyp->getAmbientColor().mV[1] / 3.f << ";";
- str << skyp->getAmbientColor().mV[2] / 3.f;
- return str.str();
- }
- else if (command == "sunglowfocus")
- {
- res = -skyp->getGlow().mV[2] / 5.f;
- }
- else if (command == "sunglowsize")
- {
- res = 2.f - skyp->getGlow().mV[0] / 20.f;
- }
- else if (command == "scenegamma")
- {
- res = skyp->getGamma();
- }
- else if (command == "sunazim" || command == "sunazimuth")
- {
- LLQuaternion orig_quat = skyp->getSunRotation();
- F32 roll, pitch;
- orig_quat.getEulerAngles(&roll, &pitch, &res);
- }
- else if (command == "sunelev" || command == "sunelevation")
- {
- LLQuaternion orig_quat = skyp->getSunRotation();
- F32 roll, pitch, yaw;
- orig_quat.getEulerAngles(&roll, &pitch, &yaw);
- LLQuaternion rotation_world;
- rotation_world.setEulerAngles(0.f, 0.f, -yaw);
- rotation_world.normalize();
- LLQuaternion new_quat = orig_quat * rotation_world;
- new_quat.getEulerAngles(&roll, &pitch, &yaw);
- if (roll <= -F_PI_BY_TWO || roll >= F_PI_BY_TWO)
- {
- pitch = -pitch;
- }
- res = -pitch;
- }
- else if (command == "moonazim" || command == "moonazimuth")
- {
- LLQuaternion orig_quat = skyp->getMoonRotation();
- F32 roll, pitch;
- orig_quat.getEulerAngles(&roll, &pitch, &res);
- }
- else if (command == "moonelev" || command == "moonelevation")
- {
- LLQuaternion orig_quat = skyp->getMoonRotation();
- F32 roll, pitch, yaw;
- orig_quat.getEulerAngles(&roll, &pitch, &yaw);
- LLQuaternion rotation_world;
- rotation_world.setEulerAngles(0.f, 0.f, -yaw);
- rotation_world.normalize();
- LLQuaternion new_quat = orig_quat * rotation_world;
- new_quat.getEulerAngles(&roll, &pitch, &yaw);
- if (roll <= -F_PI_BY_TWO || roll >= F_PI_BY_TWO)
- {
- pitch = -pitch;
- }
- res = -pitch;
- }
- #if 0 // *TODO: implement the EE approximations
- else if (command == "sunmoonposition")
- {
- }
- else if (command == "eastangle")
- {
- }
- #endif
- else if (command == "starbrightness")
- {
- res = skyp->getStarBrightness();
- }
- else if (command == "cloudcolorr")
- {
- res = skyp->getCloudColor().mV[0];
- }
- else if (command == "cloudcolorg")
- {
- res = skyp->getCloudColor().mV[1];
- }
- else if (command == "cloudcolorb")
- {
- res = skyp->getCloudColor().mV[2];
- }
- else if (command == "cloudcolori")
- {
- LLColor3 cloudcolor = skyp->getCloudColor();
- res = llmax(cloudcolor.mV[0],cloudcolor.mV[1], cloudcolor.mV[2]);
- }
- else if (command == "cloudcolor")
- {
- std::stringstream str;
- str << skyp->getCloudColor().mV[0] << ";";
- str << skyp->getCloudColor().mV[1] << ";";
- str << skyp->getCloudColor().mV[2];
- return str.str();
- }
- else if (command == "cloudx")
- {
- res = skyp->getCloudPosDensity1().mV[0];
- }
- else if (command == "cloudy")
- {
- res = skyp->getCloudPosDensity1().mV[1];
- }
- else if (command == "cloudd")
- {
- res = skyp->getCloudPosDensity1().mV[2];
- }
- else if (command == "cloud")
- {
- std::stringstream str;
- str << skyp->getCloudPosDensity1().mV[0] << ";";
- str << skyp->getCloudPosDensity1().mV[1] << ";";
- str << skyp->getCloudPosDensity1().mV[2];
- return str.str();
- }
- else if (command == "clouddetailx")
- {
- res = skyp->getCloudPosDensity2().mV[0];
- }
- else if (command == "clouddetaily")
- {
- res = skyp->getCloudPosDensity2().mV[1];
- }
- else if (command == "clouddetaild")
- {
- res = skyp->getCloudPosDensity2().mV[2];
- }
- else if (command == "clouddetail")
- {
- std::stringstream str;
- str << skyp->getCloudPosDensity2().mV[0] << ";";
- str << skyp->getCloudPosDensity2().mV[1] << ";";
- str << skyp->getCloudPosDensity2().mV[2];
- return str.str();
- }
- else if (command == "cloudcoverage")
- {
- res = skyp->getCloudShadow();
- }
- else if (command == "cloudscale")
- {
- res = skyp->getCloudScale();
- }
- else if (command == "cloudvariance")
- {
- res = skyp->getCloudVariance();
- }
- else if (command == "cloudscrollx")
- {
- res = skyp->getCloudScrollRate().mV[0] - 10.f;
- }
- else if (command == "cloudscrolly")
- {
- res = skyp->getCloudScrollRate().mV[1] - 10.f;
- }
- else if (command == "cloudscroll")
- {
- std::stringstream str;
- str << skyp->getCloudScrollRate().mV[0] - 10.f << ";";
- str << skyp->getCloudScrollRate().mV[1] - 10.f;
- return str.str();
- }
- else if (command == "moisturelevel")
- {
- res = skyp->getSkyMoistureLevel();
- }
- else if (command == "dropletradius")
- {
- res = skyp->getSkyDropletRadius();
- }
- else if (command == "icelevel")
- {
- res = skyp->getSkyIceLevel();
- }
- else if (command == "sunscale")
- {
- res = skyp->getSunScale();
- }
- else if (command == "moonscale")
- {
- res = skyp->getMoonScale();
- }
- else if (command == "moonbrightness")
- {
- res = skyp->getMoonBrightness();
- }
- else if (command == "sunimage" || command == "suntexture")
- {
- return skyp->getSunTextureId().asString();
- }
- else if (command == "moonimage" || command == "moontexture")
- {
- return skyp->getMoonTextureId().asString();
- }
- else if (command == "cloudimage" || command == "cloudtexture")
- {
- return skyp->getCloudNoiseTextureId().asString();
- }
- else if (command == "preset" || command == "asset")
- {
- return mLastLoadedPreset;
- }
- std::stringstream str;
- str << res;
- return str.str();
- }
- // MK: As some debug settings are critical to the user's experience and others
- // are just useless/not used, we are following a whitelist approach: only allow
- // certain debug settings to be changed and not all.
- bool RLInterface::forceDebugSetting(std::string command, std::string option)
- {
- // Command is "setdebug_<something>"
- constexpr size_t length = 9; // Size of "setdebug_"
- command = command.substr(length); // Remove "setdebug_"
- LLStringUtil::toLower(command);
- // Find the index of the command in the list of allowed commands, ignoring
- // the case
- S32 ind = -1;
- std::string tmp;
- for (S32 i = 0, count = mAllowedSetDebug.size(); i < count; ++i)
- {
- tmp = mAllowedSetDebug[i];
- LLStringUtil::toLower(tmp);
- if (tmp == command)
- {
- ind = i;
- break;
- }
- }
- if (ind == -1)
- {
- return false;
- }
- tmp = mAllowedSetDebug[ind];
- LLControlVariable* control = gSavedSettings.getControl(tmp.c_str());
- if (!control)
- {
- llwarns << tmp
- << " is listed among the modifiable settings, but is was not found in the viewer settings !"
- << llendl;
- return false;
- }
- // Ensure the changed variable will not be saved on log off
- control->setPersist(false);
- switch (control->type())
- {
- case TYPE_U32:
- gSavedSettings.setU32(tmp.c_str(), atoi(option.c_str()));
- break;
- case TYPE_S32:
- gSavedSettings.setS32(tmp.c_str(), atoi(option.c_str()));
- break;
- case TYPE_F32:
- gSavedSettings.setF32(tmp.c_str(), atoi(option.c_str()));
- break;
- case TYPE_BOOLEAN:
- gSavedSettings.setBool(tmp.c_str(), atoi(option.c_str()));
- break;
- case TYPE_STRING:
- gSavedSettings.setString(tmp.c_str(), option);
- break;
- default:
- llwarns << tmp << " type is currently unsuported. Not set."
- << llendl;
- return false;
- }
- return true;
- }
- std::string RLInterface::getDebugSetting(std::string command)
- {
- // Command is "getdebug_<something>"
- constexpr size_t length = 9; // Size of "getdebug_"
- command = command.substr(length); // Remove "getdebug_"
- LLStringUtil::toLower(command);
- // Find the index of the command in the list of allowed commands, ignoring
- // the case
- S32 ind = -1;
- std::string tmp;
- for (S32 i = 0, count = mAllowedGetDebug.size(); i < count; ++i)
- {
- tmp = mAllowedGetDebug[i];
- LLStringUtil::toLower(tmp);
- if (tmp == command)
- {
- ind = i;
- break;
- }
- }
- if (ind == -1)
- {
- return "";
- }
- tmp = mAllowedGetDebug[ind];
- LLControlVariable* control = gSavedSettings.getControl(tmp.c_str());
- if (!control)
- {
- llwarns << tmp
- << " is listed among the modifiable settings, but is was not found in the viewer settings !"
- << llendl;
- return "";
- }
- std::stringstream res;
- switch (control->type())
- {
- case TYPE_U32:
- res << gSavedSettings.getU32(tmp.c_str());
- break;
- case TYPE_S32:
- res << gSavedSettings.getS32(tmp.c_str());
- break;
- case TYPE_F32:
- res << gSavedSettings.getF32(tmp.c_str());
- break;
- case TYPE_BOOLEAN:
- res << gSavedSettings.getBool(tmp.c_str());
- break;
- case TYPE_STRING:
- res << gSavedSettings.getString(tmp.c_str());
- break;
- case TYPE_RECT:
- res << gSavedSettings.getRect(tmp.c_str());
- break;
- case TYPE_COL3:
- res << gSavedSettings.getColor3(tmp.c_str());
- break;
- case TYPE_COL4:
- res << gSavedSettings.getColor4(tmp.c_str());
- break;
- case TYPE_COL4U:
- res << gSavedSettings.getColor4U(tmp.c_str());
- break;
- case TYPE_VEC3:
- res << gSavedSettings.getVector3(tmp.c_str());
- break;
- case TYPE_VEC3D:
- res << gSavedSettings.getVector3d(tmp.c_str());
- break;
- default:
- llwarns << tmp << " type is currently unsuported." << llendl;
- }
- return res.str();
- }
- std::string RLInterface::getFullPath(LLInventoryCategory* cat)
- {
- if (!cat) return "";
- LLInventoryCategory* rlv = getRlvShare();
- if (!rlv) return "";
- LLInventoryCategory* res = cat;
- std::deque<std::string> tokens;
- while (res && res != rlv)
- {
- tokens.push_front(res->getName());
- const LLUUID& parent_id = res->getParentUUID();
- res = gInventory.getCategory(parent_id);
- }
- return dumpList2String(tokens, "/");
- }
- std::string RLInterface::getFullPath(LLInventoryItem* item,
- const std::string& option, bool full_list)
- {
- LL_DEBUGS("RestrainedLove") << "Item: "
- << (item ? item->getName() : "NULL")
- << " - Option: " << option << " - full_list = "
- << full_list << LL_ENDL;
- // Returns the path from the shared root to this object, or to the object
- // worn at the attach point or clothing layer pointed by option if any
- if (!option.empty())
- {
- // An option is specified; we do not want to check the item that issued
- // the command, but something else that is currently worn (object or
- // clothing)
- item = NULL;
- if (LLUUID::validate(option))
- {
- // if option is an UUID, get the path of the viewer object which
- // bears this UUID
- LLUUID id;
- id.set(option, false);
- if (id.notNull())
- {
- // We want the viewer object from the UUID, not the inventory
- // object
- item = getItem(id);
- if (item && isUnderRlvShare(item))
- {
- // We have found the inventory item: add its path to the
- // list.
- // It looks like a recursive call but the recursion level
- // is only 2 for we would not execute this instruction
- // again in the called method since 'option' will be empty.
- std::deque<std::string> res;
- res.emplace_back(getFullPath(item, ""));
- return dumpList2String(res, ",");
- }
- }
- // UUID invalid, item not found, or not shared...
- return "";
- }
- LLWearableType::EType wearable_type;
- wearable_type = getOutfitLayerAsType(option);
- if (wearable_type != LLWearableType::WT_INVALID)
- {
- // this is a clothing layer; replace item with the piece clothing
- std::deque<std::string> res;
- for (U32 i = 0; i < LLAgentWearables::MAX_CLOTHING_LAYERS; ++i)
- {
- const LLUUID& id =
- gAgentWearables.getWearableItemID(wearable_type, i);
- if (id.notNull())
- {
- item = gInventory.getItem(id);
- // Security: we would return the path even if the item was
- // not shared otherwise
- if (item && isUnderRlvShare(item))
- {
- // We have found the inventory item => add its path to
- // the list.
- // It looks like a recursive call but the recursion
- // level is only 2 for we would not execute this
- // instruction again in the called method since
- // 'option' will be empty.
- res.emplace_back(getFullPath(item, ""));
- LL_DEBUGS("RestrainedLove") << "res = "
- << dumpList2String(res, ", ")
- << LL_ENDL;
- if (!full_list)
- {
- // old behaviour: we only return the first folder,
- // not a full list
- break;
- }
- }
- }
- }
- return dumpList2String(res, ",");
- }
- // This is not a clothing layer => it has to be an attachment point
- LLViewerJointAttachment* attach_point =
- findAttachmentPointFromName(option, true);
- if (attach_point)
- {
- std::deque<std::string> res;
- for (U32 i = 0; i < attach_point->mAttachedObjects.size(); ++i)
- {
- LLViewerObject* attached_object =
- attach_point->mAttachedObjects[i];
- if (attached_object)
- {
- item = getItemAux(attached_object, getRlvShare());
- if (item && !isUnderRlvShare(item))
- {
- // Otherwise, we would return the path even if the
- // item is not shared...
- item = NULL;
- }
- else
- {
- // We have found the inventory item => add its path
- // to the list.
- // It looks like a recursive call but the recursion
- // level is only 2 for we would not execute this
- // instruction again in the called method since
- // 'option' will be empty.
- res.emplace_back(getFullPath(item, ""));
- LL_DEBUGS("RestrainedLove") << "res="
- << dumpList2String(res, ", ")
- << LL_ENDL;
- // Old behaviour: we only return the first folder,
- // not a full list
- if (!full_list) break;
- }
- }
- }
- return dumpList2String(res, ",");
- }
- }
- if (!item || !isUnderRlvShare(item))
- {
- // Otherwise, we would return the path even if the item is not shared
- return "";
- }
- LLUUID parent_id = item->getParentUUID();
- LLInventoryCategory* parent_cat = gInventory.getCategory(parent_id);
- if (item->getType() == LLAssetType::AT_OBJECT &&
- !item->getPermissions().allowModifyBy(gAgentID))
- {
- if (findAttachmentPointFromName(parent_cat->getName()))
- {
- // This item is no-mod and its parent folder contains the name of
- // an attach point => probably we want the full path only to the
- // containing folder of that folder
- parent_id = parent_cat->getParentUUID();
- parent_cat = gInventory.getCategory(parent_id);
- return getFullPath(parent_cat);
- }
- }
- return getFullPath(parent_cat);
- }
- // Auxiliary function for getItem()
- LLInventoryItem* RLInterface::getItemAux(LLViewerObject* attached_object,
- LLInventoryCategory* root)
- {
- if (attached_object && root && isAgentAvatarValid())
- {
- LLInventoryModel::cat_array_t* cats;
- LLInventoryModel::item_array_t* items;
- gInventory.getDirectDescendentsOf(root->getUUID(), cats, items);
- // Try to find the item in the current category
- for (S32 i = 0, count = items->size(); i < count; ++i)
- {
- LLInventoryItem* item = (*items)[i];
- if (item &&
- (item->getType() == LLAssetType::AT_OBJECT ||
- item->getType() == LLAssetType::AT_CLOTHING) &&
- gAgentAvatarp->getWornAttachment(item->getUUID()) == attached_object)
- {
- // Found the item in the current category
- return item;
- }
- }
- // We did not find it here => browse the children categories
- for (S32 i = 0, count = cats->size(); i < count; ++i)
- {
- LLInventoryCategory* cat = (*cats)[i];
- LLInventoryItem* item = getItemAux(attached_object, cat);
- if (item)
- {
- return item;
- }
- }
- }
- return NULL;
- }
- // Returns the inventory item corresponding to the viewer object which UUID is
- // "worn_object_id", if any
- LLInventoryItem* RLInterface::getItem(const LLUUID& worn_object_id)
- {
- LLViewerObject* object = gObjectList.findObject(worn_object_id);
- if (object)
- {
- object = object->getRootEdit();
- if (object->isAttachment())
- {
- return gInventory.getItem(object->getAttachmentItemID());
- }
- }
- // This object is not worn => it has nothing to do with any inventory item
- return NULL;
- }
- // Beware: this method does NOT check that the target attach point is already
- // used by a locked item.
- void RLInterface::attachObjectByUUID(const LLUUID& asset_id, S32 attach_pt_num,
- bool kick)
- {
- if (!isAgentAvatarValid()) return;
- LLSD payload;
- payload["item_id"] = asset_id;
- if (!kick && gAgentAvatarp->canAttachMoreObjects())
- {
- payload["attachment_point"] = attach_pt_num | ATTACHMENT_ADD;
- }
- else
- {
- payload["attachment_point"] = attach_pt_num;
- }
- gNotifications.forceResponse(LLNotification::Params("ReplaceAttachment").payload(payload),
- 0 /*YES*/);
- }
- bool RLInterface::canDetachAllSelectedObjects()
- {
- for (LLObjectSelection::iterator iter = gSelectMgr.getSelection()->begin(),
- end = gSelectMgr.getSelection()->end();
- iter != end; ++iter)
- {
- LLViewerObject* object = (*iter)->getObject();
- if (object && !canDetach(object))
- {
- return false;
- }
- }
- return true;
- }
- bool RLInterface::isSittingOnAnySelectedObject()
- {
- if (!isAgentAvatarValid() || !gAgentAvatarp->mIsSitting)
- {
- return false;
- }
- for (LLObjectSelection::iterator iter = gSelectMgr.getSelection()->begin(),
- end = gSelectMgr.getSelection()->end();
- iter != end; ++iter)
- {
- LLViewerObject* object = (*iter)->getObject();
- if (object && object->isAgentSeat())
- {
- return true;
- }
- }
- return false;
- }
- // Returns false if :
- // - at least one object issued a @attachthis:folder restriction
- // - at least one item in this folder is to be worn on an
- // @attachthis:attachpt restriction
- // - at least one piece of clothing in this folder is to be worn on an
- // @attachthis:layer restriction
- // - any parent folder returns false with @attachallthis
- bool RLInterface::canAttachCategory(LLInventoryCategory* folder,
- bool with_exceptions)
- {
- if (!folder || !isAgentAvatarValid()) return true;
- #if RL_ALLOW_ATTACH_DETACH_RECENTLY_RECEIVED_ITEMS
- if (isInventoryFolderNew(folder)) return true;
- #endif
- bool shared = isUnderRlvShare(folder);
- if (!shared || !getRlvShare())
- {
- return !contains("unsharedwear");
- }
- else if (contains("sharedwear"))
- {
- return false;
- }
- return canAttachCategoryAux(folder, false, false, with_exceptions);
- }
- bool RLInterface::canAttachCategoryAux(LLInventoryCategory* folder,
- bool in_parent, bool in_no_mod,
- bool with_exceptions)
- {
- if (!isAgentAvatarValid()) return true;
- EFolderLock folder_lock = FolderNotLocked;
- if (folder)
- {
- // Check @attachthis:folder in all restrictions
- std::string restriction = "attachthis";
- if (in_parent)
- {
- restriction = "attachallthis";
- }
- folder_lock = isFolderLockedWithoutException(folder, "attach");
- if (folder_lock == FolderLockedNoException)
- {
- return false;
- }
- if (!with_exceptions && folder_lock == FolderLockedWithException)
- {
- return false;
- }
- #if 0
- LLInventoryCategory* restricted_cat;
- std::string path_to_check;
- while (it != mSpecialObjectBehaviours.end())
- {
- if (it->second.find(restriction + ":") == 0)
- {
- // Remove ":" as well:
- path_to_check = it->second.substr(restriction.length() + 1);
- restricted_cat = getCategoryUnderRlvShare(path_to_check);
- if (restricted_cat == folder)
- {
- return false;
- }
- }
- ++it;
- }
- #endif
- LLInventoryModel::cat_array_t* cats;
- LLInventoryModel::item_array_t* items;
- gInventory.getDirectDescendentsOf(folder->getUUID(), cats, items);
- // Try to find the item in the current category
- for (S32 i = 0, count = items->size(); i < count; ++i)
- {
- LLInventoryItem* item = (*items)[i];
- if (item)
- {
- if (item->getType() == LLAssetType::AT_OBJECT)
- {
- LLViewerJointAttachment* attachpt = NULL;
- if (in_no_mod)
- {
- if (count > 1 ||
- item->getPermissions().allowModifyBy(gAgentID))
- {
- return true;
- }
- LLInventoryCategory* parent =
- gInventory.getCategory(folder->getParentUUID());
- attachpt = findAttachmentPointFromName(parent->getName());
- }
- else
- {
- attachpt = findAttachmentPointFromName(item->getName());
- }
- if (attachpt &&
- contains(restriction + ":" + attachpt->getName()))
- {
- return false;
- }
- }
- else if (item->getType() == LLAssetType::AT_CLOTHING ||
- item->getType() == LLAssetType::AT_BODYPART)
- {
- LLViewerWearable* wearable =
- gAgentWearables.getWearableFromItemID(item->getLinkedUUID());
- if (wearable &&
- contains(restriction + ":" +
- getOutfitLayerAsString(wearable->getType())))
- {
- return false;
- }
- }
- }
- }
- // Now check all no-mod items => look at the sub-categories and return
- // false if any of them returns false on a call to
- // canAttachCategoryAux()
- for (S32 i = 0, count = cats->size(); i < count; ++i)
- {
- LLInventoryCategory* cat = (*cats)[i];
- if (cat)
- {
- const std::string& name = cat->getName();
- if (!name.empty() && name[0] == '.' &&
- findAttachmentPointFromName(name))
- {
- if (!canAttachCategoryAux(cat, false, true,
- with_exceptions))
- {
- return false;
- }
- }
- }
- }
- }
- if (folder == getRlvShare()) return true;
- if (!in_no_mod && folder_lock == FolderNotLocked)
- {
- // Check for @attachallthis in the parent
- return canAttachCategoryAux(gInventory.getCategory(folder->getParentUUID()),
- true, false, with_exceptions);
- }
- return true;
- }
- // Returns false if:
- // - at least one object contained in this folder issued a @detachthis
- // restriction
- // - at least one object issued a @detachthis:folder restriction
- // - at least one worn attachment in this folder is worn on a
- // @detachthis:attachpt restriction
- // - at least one worn piece of clothing in this folder is worn on a
- // @detachthis:layer restriction
- // - any parent folder returns false with @detachallthis
- bool RLInterface::canDetachCategory(LLInventoryCategory* folder,
- bool with_exceptions)
- {
- if (!folder || !isAgentAvatarValid()) return true;
- if (mHandleNoStrip)
- {
- std::string name = folder->getName();
- LLStringUtil::toLower(name);
- if (name.find(RL_PROTECTED_FOLDER_TAG) != std::string::npos)
- {
- return false;
- }
- }
- #if RL_ALLOW_ATTACH_DETACH_RECENTLY_RECEIVED_ITEMS
- if (isInventoryFolderNew(folder)) return true;
- #endif
- bool shared = isUnderRlvShare(folder);
- if (!shared || !getRlvShare())
- {
- return !contains("unsharedunwear");
- }
- else if (contains("sharedunwear"))
- {
- return false;
- }
- return canDetachCategoryAux(folder, false, false, with_exceptions);
- }
- bool RLInterface::canDetachCategoryAux(LLInventoryCategory* folder,
- bool in_parent, bool in_no_mod,
- bool with_exceptions)
- {
- if (!isAgentAvatarValid()) return true;
- EFolderLock folder_lock = FolderNotLocked;
- if (folder)
- {
- // check @detachthis:folder in all restrictions
- std::string path_to_check;
- std::string restriction = "detachthis";
- if (in_parent)
- {
- restriction = "detachallthis";
- }
- folder_lock = isFolderLockedWithoutException(folder, "detach");
- if (folder_lock == FolderLockedNoException)
- {
- return false;
- }
- if (!with_exceptions && folder_lock == FolderLockedWithException)
- {
- return false;
- }
- #if 0
- LLInventoryCategory* restricted_cat;
- while (it != mSpecialObjectBehaviours.end())
- {
- if (it->second.find(restriction + ":") == 0)
- {
- // remove ":" as well:
- path_to_check = it->second.substr(restriction.length()+1);
- restricted_cat = getCategoryUnderRlvShare(path_to_check);
- if (restricted_cat == folder) return false;
- }
- ++it;
- }
- #endif
- LLInventoryModel::cat_array_t* cats;
- LLInventoryModel::item_array_t* items;
- gInventory.getDirectDescendentsOf(folder->getUUID(), cats, items);
- // Try to find the item in the current category
- for (S32 i = 0, count = items->size(); i < count; ++i)
- {
- LLInventoryItem* item = (*items)[i];
- if (item)
- {
- if (item->getType() == LLAssetType::AT_OBJECT)
- {
- if (in_no_mod)
- {
- if (count > 1 ||
- item->getPermissions().allowModifyBy(gAgentID))
- {
- return true;
- }
- }
- LLViewerObject* attached_object;
- attached_object = gAgentAvatarp->getWornAttachment(item->getLinkedUUID());
- if (attached_object)
- {
- if (!isAllowed(attached_object->getRootEdit()->getID(),
- restriction))
- {
- return false;
- }
- if (!in_parent &&
- !isAllowed(attached_object->getRootEdit()->getID(),
- "detachallthis"))
- {
- // special case for objects contained into this
- // folder and that issued a @detachallthis command
- // without any parameter without issuing a
- // @detachthis command along with it
- return false;
- }
- if (contains(restriction + ":" +
- gAgentAvatarp->getAttachedPointName(item->getLinkedUUID())))
- {
- return false;
- }
- }
- }
- else if (item->getType() == LLAssetType::AT_CLOTHING ||
- item->getType() == LLAssetType::AT_BODYPART)
- {
- LLViewerWearable* wearable;
- wearable = gAgentWearables.getWearableFromItemID(item->getLinkedUUID());
- if (wearable &&
- contains(restriction + ":" +
- getOutfitLayerAsString(wearable->getType())))
- {
- return false;
- }
- }
- }
- }
- // Now check all no-mod items => look at the sub-categories and return
- // false if any of them returns false on a call to
- // canDetachCategoryAux()
- for (S32 i = 0, count = cats->size(); i < count; ++i)
- {
- LLInventoryCategory* cat = (*cats)[i];
- if (cat)
- {
- const std::string& name = cat->getName();
- if (!name.empty() && name[0] == '.' &&
- findAttachmentPointFromName(name))
- {
- if (!canDetachCategoryAux(cat, false, true)) return false;
- }
- }
- }
- }
- if (folder == getRlvShare()) return true;
- if (!in_no_mod && folder_lock == FolderNotLocked)
- {
- // check for @detachallthis in the parent
- return canDetachCategoryAux(gInventory.getCategory(folder->getParentUUID()),
- true, false, with_exceptions);
- }
- return true;
- }
- bool RLInterface::isRestoringOutfit()
- {
- return !gRLenabled || mRestoringOutfit || !isAgentAvatarValid() ||
- gAgentAvatarp->getIsCloud();
- }
- bool RLInterface::canUnwear(LLViewerInventoryItem* item)
- {
- if (item && !isRestoringOutfit())
- {
- if (item->getType() == LLAssetType::AT_OBJECT)
- {
- return canDetach(item);
- }
- if (item->getType() == LLAssetType::AT_CLOTHING ||
- item->getType() == LLAssetType::AT_BODYPART)
- {
- if (!canUnwear(item->getWearableType()))
- {
- return false;
- }
- LLInventoryCategory* parent;
- parent = gInventory.getCategory(item->getParentUUID());
- if (!canDetachCategory(parent))
- {
- return false;
- }
- }
- }
- return true;
- }
- bool RLInterface::canUnwear(LLWearableType::EType type)
- {
- if (!isRestoringOutfit())
- {
- if (contains("remoutfit"))
- {
- return false;
- }
- if (contains("remoutfit:" + getOutfitLayerAsString(type)))
- {
- return false;
- }
- }
- return true;
- }
- bool RLInterface::canWear(LLViewerInventoryItem* item)
- {
- if (item && !isRestoringOutfit())
- {
- #if RL_ALLOW_ATTACH_DETACH_RECENTLY_RECEIVED_ITEMS
- if (isInventoryItemNew(item)) return true;
- #endif
- LLInventoryCategory* parent =
- gInventory.getCategory(item->getParentUUID());
- if (item->getType() == LLAssetType::AT_OBJECT)
- {
- LLViewerJointAttachment* attachpt;
- attachpt = findAttachmentPointFromName(item->getName());
- if (attachpt && !canAttach(NULL, attachpt->getName()))
- {
- return false;
- }
- return canAttachCategory(parent);
- }
- if (item->getType() == LLAssetType::AT_CLOTHING ||
- item->getType() == LLAssetType::AT_BODYPART)
- {
- if (!canWear(item->getWearableType()) ||
- !canAttachCategory(parent))
- {
- return false;
- }
- }
- }
- return true;
- }
- bool RLInterface::canWear(LLWearableType::EType type)
- {
- if (!isRestoringOutfit())
- {
- if (contains("addoutfit"))
- {
- return false;
- }
- if (contains("addoutfit:" + getOutfitLayerAsString(type)))
- {
- return false;
- }
- }
- return true;
- }
- bool RLInterface::canDetach(LLViewerInventoryItem* item)
- {
- if (!item || isRestoringOutfit()) return true;
- if (mHandleNoStrip)
- {
- std::string name = item->getName();
- LLStringUtil::toLower(name);
- if (name.find(RL_PROTECTED_FOLDER_TAG) != std::string::npos)
- {
- return false;
- }
- }
- if (item->getType() == LLAssetType::AT_OBJECT)
- {
- // We will check canDetachCategory() inside this function
- return canDetach(gAgentAvatarp->getWornAttachment(item->getLinkedUUID()));
- }
- else if (item->getType() == LLAssetType::AT_CLOTHING)
- {
- LLInventoryCategory* parentp =
- gInventory.getCategory(item->getParentUUID());
- if (parentp && !canDetachCategory(parentp))
- {
- return false;
- }
- const LLViewerWearable* wearable =
- gAgentWearables.getWearableFromItemID(item->getUUID());
- if (wearable)
- {
- return canUnwear(wearable->getType());
- }
- }
- return true;
- }
- bool RLInterface::canDetach(LLViewerObject* attached_object)
- {
- if (!attached_object || isRestoringOutfit()) return true;
- LLViewerObject* root = attached_object->getRootEdit();
- if (!root) return true;
- // Check all the current restrictions, if "detach" is issued from a child
- // prim of the root prim of attached_object, then the whole object is
- // undetachable
- for (rl_map_it_t it = mSpecialObjectBehaviours.begin(),
- end = mSpecialObjectBehaviours.end();
- it != end; ++it)
- {
- if (it->second == "detach")
- {
- LLViewerObject* this_prim =
- gObjectList.findObject(LLUUID(it->first));
- if (this_prim && this_prim->getRootEdit() == root)
- {
- return false;
- }
- }
- }
- const LLUUID& obj_id = attached_object->getID();
- if (!isAllowed(obj_id, "detach", false) ||
- !isAllowed(obj_id, "detachthis", false) ||
- !isAllowed(obj_id, "detachallthis", false))
- {
- return false;
- }
- LLInventoryItem* item = getItem(root->getID());
- if (item)
- {
- if (mHandleNoStrip)
- {
- std::string name = item->getName();
- LLStringUtil::toLower(name);
- if (name.find(RL_PROTECTED_FOLDER_TAG) != std::string::npos)
- {
- return false;
- }
- }
- #if RL_ALLOW_ATTACH_DETACH_RECENTLY_RECEIVED_ITEMS
- if (isInventoryItemNew(item)) return true;
- #endif
- LLInventoryCategory* parentp =
- gInventory.getCategory(item->getParentUUID());
- if (parentp && !canDetachCategory(parentp)) return false;
- std::string attachpt;
- attachpt = gAgentAvatarp->getAttachedPointName(item->getLinkedUUID());
- if (contains("detach:" + attachpt)) return false;
- if (contains("remattach")) return false;
- if (contains("remattach:" + attachpt)) return false;
- }
- return true;
- }
- bool RLInterface::canDetach(std::string attachpt)
- {
- if (isRestoringOutfit()) return true;
- LLStringUtil::toLower(attachpt);
- if (contains("detach:" + attachpt)) return false;
- if (contains("remattach")) return false;
- if (contains("remattach:" + attachpt)) return false;
- LLViewerJointAttachment* attachment;
- attachment = findAttachmentPointFromName(attachpt, true);
- return canDetachAllObjectsFromAttachment(attachment);
- }
- // Beware: this function does not check if we are replacing and there is a
- // locked object already present on the attachment point
- bool RLInterface::canAttach(LLViewerObject* object_to_attach,
- std::string attachpt)
- {
- if (isRestoringOutfit())
- {
- return true;
- }
- LLStringUtil::toLower(attachpt);
- if (contains("addattach") || contains("addattach:" + attachpt))
- {
- return false;
- }
- if (object_to_attach)
- {
- LLInventoryItem* item =
- getItem(object_to_attach->getRootEdit()->getID());
- if (item)
- {
- #if RL_ALLOW_ATTACH_DETACH_RECENTLY_RECEIVED_ITEMS
- if (isInventoryItemNew(item)) return true;
- #endif
- LLInventoryCategory* parentp =
- gInventory.getCategory(item->getParentUUID());
- if (parentp && !canAttachCategory(parentp))
- {
- return false;
- }
- }
- }
- return true;
- }
- bool RLInterface::canAttach(LLViewerInventoryItem* item)
- {
- if (!item || isRestoringOutfit()) return true;
- #if RL_ALLOW_ATTACH_DETACH_RECENTLY_RECEIVED_ITEMS
- if (isInventoryItemNew(item)) return true;
- #endif
- if (contains("addattach")) return false;
- LLViewerJointAttachment* attachpt;
- attachpt = findAttachmentPointFromName(item->getName());
- if (attachpt && contains("addattach:" + attachpt->getName())) return false;
- LLInventoryCategory* parentp =
- gInventory.getCategory(item->getParentUUID());
- return !parentp || canAttachCategory(parentp);
- }
- bool RLInterface::canStartIM(const LLUUID& to_id)
- {
- std::string id_str = to_id.asString();
- return !contains("startimto:" + id_str) &&
- !containsWithoutException("startim", id_str);
- }
- bool RLInterface::canSendIM(const LLUUID& to_id)
- {
- std::string id_str = to_id.asString();
- return !contains("sendimto:" + id_str) &&
- !containsWithoutException("sendim", id_str);
- }
- bool RLInterface::canReceiveIM(const LLUUID& from_id)
- {
- std::string id_str = from_id.asString();
- return !contains("recvimfrom:" + id_str) &&
- !containsWithoutException("recvim", id_str);
- }
- bool RLInterface::canSendGroupIM(std::string group_name)
- {
- // Remove any separators from the group name
- LLStringUtil::replaceString(group_name, ",", "");
- LLStringUtil::replaceString(group_name, ";", "");
- return !((contains("sendimto:allgroups") &&
- contains("sendimto:" + group_name)) ||
- containsWithoutException("sendim", "allgroups") ||
- containsWithoutException("sendim", group_name));
- }
- bool RLInterface::canReceiveGroupIM(std::string group_name)
- {
- // Remove any separators from the group name
- LLStringUtil::replaceString(group_name, ",", "");
- LLStringUtil::replaceString(group_name, ";", "");
- return !((contains("recvimfrom:allgroups") &&
- contains("recvimfrom:" + group_name)) ||
- containsWithoutException("recvim", "allgroups") ||
- containsWithoutException("recvim", group_name));
- }
- bool RLInterface::canEdit(LLViewerObject* object)
- {
- if (!object) return false;
- LLViewerObject* root = object->getRootEdit();
- if (!root) return false;
- if (!mContainsEdit)
- {
- return true;
- }
- if (containsWithoutException("edit", root->getID().asString()))
- {
- return false;
- }
- bool is_attachment = object->isAttachment();
- if (is_attachment && contains("editworld"))
- {
- return false;
- }
- if (!is_attachment && contains("editattach"))
- {
- return false;
- }
- if (contains("editobj:" + root->getID().asString()))
- {
- return false;
- }
- return !mContainsInteract || object->isHUDAttachment();
- }
- bool RLInterface::canTouch(LLViewerObject* object,
- LLVector3 pick_intersection)
- {
- if (!object)
- {
- return true;
- }
- LLViewerObject* root = object->getRootEdit();
- if (!root)
- {
- return true;
- }
- // To check the presence of "touchme" on this object, which means that we
- // can touch it
- if (!isAllowed(root->getID(), "touchme"))
- {
- return true;
- }
- bool is_hud = root->isHUDAttachment();
- if (!is_hud && contains("touchall"))
- {
- return false;
- }
- #if 0 // Not implemented
- if (!is_hud && contains("touchallnonhud"))
- {
- return false;
- }
- #endif
- if (is_hud &&
- containsWithoutException("touchhud",
- object->getRootEdit()->getID().asString()))
- {
- return false;
- }
- if (contains("touchthis:" + root->getID().asString()))
- {
- return false;
- }
- if (!canTouchFar(object, pick_intersection))
- {
- return false;
- }
- if (root->isAttachment())
- {
- if (!is_hud)
- {
- if (contains("touchattach")) return false;
- LLInventoryItem* inv_item = getItem(root->getID());
- if (inv_item)
- {
- // This attachment is in my inv => it belongs to me
- if (contains("touchattachself"))
- {
- return false;
- }
- }
- else
- {
- // This attachment is not in my inv => it does not belong to me
- if (contains("touchattachother"))
- {
- return false;
- }
- LLVOAvatar* av = root->getAvatar();
- if (!av ||
- contains("touchattachother:" + av->getID().asString()))
- {
- return false;
- }
- }
- }
- }
- else if (containsWithoutException("touchworld", root->getID().asString()))
- {
- return false;
- }
- return true;
- }
- bool RLInterface::canTouchFar(LLViewerObject* object,
- LLVector3 pick_intersection)
- {
- if (!object || object->isHUDAttachment()) return true;
- if (mContainsInteract) return false;
- LLVector3 pos = object->getPositionRegion();
- if (pick_intersection != LLVector3::zero)
- {
- pos = pick_intersection;
- }
- pos -= gAgent.getPositionAgent();
- F32 dist = pos.length();
- #if 0 // Lift this restriction for now, as there may be cases where we want the
- // avatar to touch something that is beyond their vision range.
- return dist <= mFartouchMax && dist <= mCamDistDrawMax;
- #else
- return dist <= mFartouchMax;
- #endif
- }
- #if RL_ALLOW_ATTACH_DETACH_RECENTLY_RECEIVED_ITEMS
- bool RLInterface::isInventoryFolderNew(LLInventoryCategory* folder)
- {
- return folder && mReceivedInventoryFolders.count(folder->getName()) != 0;
- }
- bool RLInterface::isInventoryItemNew(LLInventoryItem* item)
- {
- if (!item) return false;
- const LLUUID& parent_id = item->getParentUUID();
- LLInventoryCategory* parent = gInventory.getCategory(parent_id);
- return parent && mReceivedInventoryFolders.count(parent->getName()) != 0;
- }
- #endif
- // Updates the min and max values not related to camera and vision restrictions
- void RLInterface::updateLimits()
- {
- mFartouchMax = llmin(getMin("fartouch", EXTREMUM),
- getMin("touchfar", EXTREMUM));
- mSittpMax = getMin("sittp", EXTREMUM);
- mTplocalMax = getMin("tplocal", EXTREMUM);
- }
- // Checks that we are within the imposed limits, forces the camera back into
- // the limits and returns false when not, returns true when the camera is ok.
- bool RLInterface::checkCameraLimits(bool and_correct)
- {
- if (!gAgent.mInitialized)
- {
- return true;
- }
- if (mCamDistMax <= 0.f && !gAgent.cameraMouselook())
- {
- if (and_correct)
- {
- gAgent.changeCameraToMouselook();
- }
- return false;
- }
- else if (mCamDistMin > 0.f && gAgent.cameraMouselook())
- {
- if (and_correct)
- {
- gAgent.changeCameraToDefault();
- }
- return false;
- }
- return true;
- }
- bool RLInterface::updateCameraLimits()
- {
- // Update the min and max
- mShowavsDistMax = getMin("camavdist", EXTREMUM);
- if (mShowavsDistMax < EXTREMUM)
- {
- LLVOAvatar::sUseImpostors = true;
- LLVOAvatar::updateSettings();
- }
- else if (LLStartUp::isLoggedIn())
- {
- LLVOAvatar::updateSettings();
- }
- F32 old_dist_min = mCamDistDrawMin;
- F32 old_dist_max = mCamDistDrawMax;
- F32 old_alpha_min = mCamDistDrawAlphaMin;
- F32 old_alpha_max = mCamDistDrawAlphaMax;
- mCamZoomMax = getMin("camzoommax", EXTREMUM);
- if (mCamZoomMax == 0.f) mCamZoomMax = EXTREMUM;
- mCamZoomMin = getMax("camzoommin", -EXTREMUM);
- if (mCamZoomMin == 0.f) mCamZoomMin = -EXTREMUM;
- // setcam_fovmin and setcam_fovmax set the FOV, i.e. 60°/multiplier;
- // in other words, they are equivalent to camzoommin and camzoommax.
- F32 fovmin = getMax("setcam_fovmin", 0.001f);
- if (fovmin != 0.f && fovmin != 0.001f)
- {
- F32 zoommax_from_fovmin = DEFAULT_FIELD_OF_VIEW / fovmin;
- if (zoommax_from_fovmin < mCamZoomMax)
- {
- mCamZoomMax = zoommax_from_fovmin;
- }
- }
- F32 fovmax = getMin("setcam_fovmax", EXTREMUM);
- if (fovmax != 0.f && fovmax != EXTREMUM)
- {
- F32 zoommin_from_fovmax = DEFAULT_FIELD_OF_VIEW / fovmax;
- if (zoommin_from_fovmax > mCamZoomMin)
- {
- mCamZoomMin = zoommin_from_fovmax;
- }
- }
- mCamDistMax = getMin("camdistmax,setcam_avdistmax", EXTREMUM);
- mCamDistMin = getMax("camdistmin,setcam_avdistmin", -EXTREMUM);
- mCamDistDrawMax = getMin("camdrawmax", EXTREMUM);
- mCamDistDrawMin = getMin("camdrawmin", EXTREMUM);
- mCamDistDrawAlphaMin = getMax("camdrawalphamin", 0.f);
- mCamDistDrawAlphaMax = getMax("camdrawalphamax", 1.f);
- mCamDistDrawColor = getMixedColors("camdrawcolor", LLColor3::black);
- if (mCamDistDrawMin <= 0.4f)
- {
- // So we are sure to render the spheres even when restricted to
- // mouselook
- mCamDistDrawMin = 0.4f;
- }
- if (mCamDistDrawMax < mCamDistDrawMin)
- {
- // Sort the two limits in order
- if (mCamDistDrawMin < EXTREMUM)
- {
- mCamDistDrawMax = mCamDistDrawMin;
- }
- else
- {
- mCamDistDrawMin = mCamDistDrawMax;
- }
- }
- if (mCamDistMax >= mCamDistDrawMin && mCamDistDrawMin < EXTREMUM)
- {
- // Make sure we cannot move the camera outside the minimum render limit
- mCamDistMax = mCamDistDrawMin * 0.75f;
- }
- if (mCamDistMax >= mCamDistDrawMax && mCamDistDrawMax < EXTREMUM)
- {
- // Make sure we cannot move the camera outside the maximum render limit
- mCamDistMax = mCamDistDrawMax * 0.75f;
- }
- if (mCamDistDrawAlphaMax < mCamDistDrawAlphaMin)
- {
- // Make sure the "fog" goes in the right direction
- mCamDistDrawAlphaMax = mCamDistDrawAlphaMin;
- }
- if (mCamZoomMin > mCamZoomMax)
- {
- mCamZoomMin = mCamZoomMax;
- }
- if (mCamDistMin > mCamDistMax)
- {
- mCamDistMin = mCamDistMax;
- }
- if (old_dist_min != mCamDistDrawMin || old_dist_max != mCamDistDrawMax ||
- old_alpha_min != mCamDistDrawAlphaMin ||
- old_alpha_max != mCamDistDrawAlphaMax)
- {
- // Force all the rendering types back to true (and we would not be able
- // to switch them off while the vision is restricted)
- if (mCamDistDrawMin < EXTREMUM || mCamDistDrawMax < EXTREMUM)
- {
- gSavedSettings.setBool("BeaconAlwaysOn", false);
- gPipeline.setAllRenderTypes();
- }
- // Silly hack, but we need to force all textures in world to be updated
- mNeedsVisibilityRefresh = true;
- }
- // Limit the number of gradients to 10 per meter, with 2 as the minimum
- // and 40 as the maximum.
- mCamDistNbGradients =
- llclamp((U32)((mCamDistDrawMax - mCamDistDrawMin) * 10.f), 2U, 40U);
- mVisionRestricted = mCamDistDrawMin < EXTREMUM ||
- mCamDistDrawMax < EXTREMUM;
- // And check the camera is still within the limits
- return checkCameraLimits(true);
- }
- #define UPPER_ALPHA_LIMIT 0.999999f
- // This function returns the effective alpha to set to each step when going
- // from 0.0 to "desired_alpha", so that everything seen through the last layer
- // will be obscured as if it were behind only one layer of desired_alpha,
- // regardless of nb_layers If we have N layers and want a transparency T
- // (T = 1-A), we want to find X so that X**N = T (because combined
- // transparencies multiply), in other words, X = T**(1/N). The problem with
- // this formula is that with a target transparency of 0 (alpha = 1), we would
- // not get any gradient at all so we need to limit the alpha to a maximum that
- // is lower than 1.
- F32 calculateDesiredAlphaPerStep(F32 desired_alpha, S32 nb_layers)
- {
- if (desired_alpha > UPPER_ALPHA_LIMIT)
- {
- desired_alpha = UPPER_ALPHA_LIMIT;
- }
- F64 desired_trans = (F64)(1.f - desired_alpha);
- F64 trans_at_this_step = pow(desired_trans, 1.0 / (F64)nb_layers);
- return (F32)(1.0 - trans_at_this_step);
- }
- // This method draws several big black spheres around the avatar, with various
- // alphas. Alpha goes from mCamDistDrawAlphaMin to mCamDistDrawAlphaMax.
- // Things to remember :
- // - There are two render limits in RLV: min and max (min is a sphere with a
- // variable alpha and max is an opaque sphere).
- // - Render limit min <= render limit max.
- // - If a render limit is <= 1.0, make it 1.0 because we will be forced into
- // mouselook anyway, so it would be better to render the sphere
- // - If a render limit is unspecified (i.e. equal to EXTREMUM), do not render
- // it.
- // - If both render limits are specified and different, render both and several
- // in-between at regular intervals, with a linear interpolation for alpha
- // between mCamDistDrawAlphaMin and mCamDistDrawAlphaMax for each sphere.
- // - There are not too many spheres to render, because stacking alphas make the
- // video card complain.
- void RLInterface::drawRenderLimit(bool force_opaque)
- {
- if (!mVisionRestricted)
- {
- return;
- }
- gGL.setColorMask(true, false);
- gUIProgram.bind();
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- gGL.matrixMode(LLRender::MM_MODELVIEW);
- gPipeline.disableLights();
- // Calculate the center of the spheres
- LLJoint* ref_joint = getCamDistDrawFromJoint();
- LLVector3 center = ref_joint ? ref_joint->getWorldPosition()
- : gAgent.getPositionAgent();
- static LLCachedControl<U32> policy(gSavedSettings,
- "RenderHighlightSelectionsPolicy");
- // If the inner sphere is opaque, just render it and no other
- // Also make the inner sphere opaque if we are highlighting invisible
- // surfaces or if anything is highlighted by a selection (edit, select or
- // drag and drop).
- if (force_opaque || mCamDistDrawAlphaMin >= UPPER_ALPHA_LIMIT ||
- LLDrawPoolAlpha::sShowDebugAlpha ||
- (policy > 0 && (!gSelectMgr.getSelection()->isEmpty() ||
- gToolDragAndDrop.getCargoCount())))
- {
- drawSphere(center, mCamDistDrawMin, mCamDistDrawColor, 1.f);
- }
- else
- {
- // If the outer sphere is opaque, render it now before switching to
- // blend mode
- bool outer_opaque = mCamDistDrawAlphaMax >= UPPER_ALPHA_LIMIT;
- if (outer_opaque)
- {
- drawSphere(center, mCamDistDrawMax, mCamDistDrawColor, 1.f);
- }
- // Switch to blend mode now
- LLGLEnable gls_blend(GL_BLEND);
- LLGLEnable gls_cull(GL_CULL_FACE);
- LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
- gGL.setColorMask(true, false);
- F32 alpha_step = calculateDesiredAlphaPerStep(mCamDistDrawAlphaMax,
- mCamDistNbGradients);
- // If the outer sphere is not opaque, render it now since we have not
- // before switching to blend mode.
- if (!outer_opaque)
- {
- drawSphere(center, mCamDistDrawMax, mCamDistDrawColor, alpha_step);
- }
- F32 lerp_factor = 1.f / (F32)mCamDistNbGradients;
- for (S32 i = mCamDistNbGradients - 1; i > 0; --i)
- {
- drawSphere(center,
- lerp(mCamDistDrawMin, mCamDistDrawMax,
- (F32)i * lerp_factor),
- mCamDistDrawColor, alpha_step);
- }
- }
- gGL.flush();
- gGL.setColorMask(true, false);
- gUIProgram.unbind();
- mRenderLimitRenderedThisFrame = true;
- }
- void RLInterface::drawSphere(const LLVector3& center, F32 scale,
- const LLColor3& color, F32 alpha)
- {
- if (alpha < 0.001f)
- {
- return; // Sphere is almost invisible, so...
- }
- gGL.pushMatrix();
- gGL.translatef(center[0], center[1], center[2]);
- gGL.scalef(scale, scale, scale);
- LLColor4 color_alpha(color, alpha);
- gGL.color4fv(color_alpha.mV);
- // Render inside only (the camera is not supposed to go outside anyway)
- glCullFace(GL_FRONT);
- gSphere.render();
- glCullFace(GL_BACK);
- gGL.popMatrix();
- }
- LLJoint* RLInterface::getCamDistDrawFromJoint()
- {
- if (!isAgentAvatarValid())
- {
- return NULL;
- }
- if (!mCamDistDrawFromJoint ||
- gAgent.getCameraMode() == CAMERA_MODE_MOUSELOOK)
- {
- return gAgentAvatarp->mHeadp;
- }
- return mCamDistDrawFromJoint;
- }
- S32 RLInterface::avatarVisibility(LLVOAvatar* avatarp)
- {
- // Fastest tests first.
- if (!avatarp)
- {
- return 0;
- }
- if ((mShowavsDistMax == EXTREMUM && mCamDistDrawMax == EXTREMUM) ||
- avatarp->isSelf() || avatarp->isUIAvatar())
- {
- return 1;
- }
- // Get the distance from our agent avatar
- LLVector3d dist_vec = gAgent.getPositionGlobal() -
- gAgent.getPosGlobalFromAgent(avatarp->getCharacterPosition()) -
- gAgent.getPositionGlobal();
- F32 squared_dist = dist_vec.lengthSquared();
- // For camavdist, we always jelly-dollify avatars beyond its distance.
- if (mShowavsDistMax < EXTREMUM &&
- squared_dist > mShowavsDistMax * mShowavsDistMax)
- {
- return -1;
- }
- // For camdrawmax, when the avatar is beyond this distance and the outer
- // sphere is opaque, we do not bother rendering it at all. When the outer
- // sphere is not opaque but ALM is off, we jelly-dollify any avatar beyond
- // this distance since legacy avatars are unaffected by the spheres. HB
- if (mCamDistDrawMax < EXTREMUM &&
- squared_dist > mCamDistDrawMax * mCamDistDrawMax)
- {
- if (mCamDistDrawAlphaMax >= 0.999f)
- {
- return 0;
- }
- return LLPipeline::sRenderDeferred ? 1 : -1;
- }
- return 1;
- }
|