LSL_Api.cs 748 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987139881398913990139911399213993139941399513996139971399813999140001400114002140031400414005140061400714008140091401014011140121401314014140151401614017140181401914020140211402214023140241402514026140271402814029140301403114032140331403414035140361403714038140391404014041140421404314044140451404614047140481404914050140511405214053140541405514056140571405814059140601406114062140631406414065140661406714068140691407014071140721407314074140751407614077140781407914080140811408214083140841408514086140871408814089140901409114092140931409414095140961409714098140991410014101141021410314104141051410614107141081410914110141111411214113141141411514116141171411814119141201412114122141231412414125141261412714128141291413014131141321413314134141351413614137141381413914140141411414214143141441414514146141471414814149141501415114152141531415414155141561415714158141591416014161141621416314164141651416614167141681416914170141711417214173141741417514176141771417814179141801418114182141831418414185141861418714188141891419014191141921419314194141951419614197141981419914200142011420214203142041420514206142071420814209142101421114212142131421414215142161421714218142191422014221142221422314224142251422614227142281422914230142311423214233142341423514236142371423814239142401424114242142431424414245142461424714248142491425014251142521425314254142551425614257142581425914260142611426214263142641426514266142671426814269142701427114272142731427414275142761427714278142791428014281142821428314284142851428614287142881428914290142911429214293142941429514296142971429814299143001430114302143031430414305143061430714308143091431014311143121431314314143151431614317143181431914320143211432214323143241432514326143271432814329143301433114332143331433414335143361433714338143391434014341143421434314344143451434614347143481434914350143511435214353143541435514356143571435814359143601436114362143631436414365143661436714368143691437014371143721437314374143751437614377143781437914380143811438214383143841438514386143871438814389143901439114392143931439414395143961439714398143991440014401144021440314404144051440614407144081440914410144111441214413144141441514416144171441814419144201442114422144231442414425144261442714428144291443014431144321443314434144351443614437144381443914440144411444214443144441444514446144471444814449144501445114452144531445414455144561445714458144591446014461144621446314464144651446614467144681446914470144711447214473144741447514476144771447814479144801448114482144831448414485144861448714488144891449014491144921449314494144951449614497144981449914500145011450214503145041450514506145071450814509145101451114512145131451414515145161451714518145191452014521145221452314524145251452614527145281452914530145311453214533145341453514536145371453814539145401454114542145431454414545145461454714548145491455014551145521455314554145551455614557145581455914560145611456214563145641456514566145671456814569145701457114572145731457414575145761457714578145791458014581145821458314584145851458614587145881458914590145911459214593145941459514596145971459814599146001460114602146031460414605146061460714608146091461014611146121461314614146151461614617146181461914620146211462214623146241462514626146271462814629146301463114632146331463414635146361463714638146391464014641146421464314644146451464614647146481464914650146511465214653146541465514656146571465814659146601466114662146631466414665146661466714668146691467014671146721467314674146751467614677146781467914680146811468214683146841468514686146871468814689146901469114692146931469414695146961469714698146991470014701147021470314704147051470614707147081470914710147111471214713147141471514716147171471814719147201472114722147231472414725147261472714728147291473014731147321473314734147351473614737147381473914740147411474214743147441474514746147471474814749147501475114752147531475414755147561475714758147591476014761147621476314764147651476614767147681476914770147711477214773147741477514776147771477814779147801478114782147831478414785147861478714788147891479014791147921479314794147951479614797147981479914800148011480214803148041480514806148071480814809148101481114812148131481414815148161481714818148191482014821148221482314824148251482614827148281482914830148311483214833148341483514836148371483814839148401484114842148431484414845148461484714848148491485014851148521485314854148551485614857148581485914860148611486214863148641486514866148671486814869148701487114872148731487414875148761487714878148791488014881148821488314884148851488614887148881488914890148911489214893148941489514896148971489814899149001490114902149031490414905149061490714908149091491014911149121491314914149151491614917149181491914920149211492214923149241492514926149271492814929149301493114932149331493414935149361493714938149391494014941149421494314944149451494614947149481494914950149511495214953149541495514956149571495814959149601496114962149631496414965149661496714968149691497014971149721497314974149751497614977149781497914980149811498214983149841498514986149871498814989149901499114992149931499414995149961499714998149991500015001150021500315004150051500615007150081500915010150111501215013150141501515016150171501815019150201502115022150231502415025150261502715028150291503015031150321503315034150351503615037150381503915040150411504215043150441504515046150471504815049150501505115052150531505415055150561505715058150591506015061150621506315064150651506615067150681506915070150711507215073150741507515076150771507815079150801508115082150831508415085150861508715088150891509015091150921509315094150951509615097150981509915100151011510215103151041510515106151071510815109151101511115112151131511415115151161511715118151191512015121151221512315124151251512615127151281512915130151311513215133151341513515136151371513815139151401514115142151431514415145151461514715148151491515015151151521515315154151551515615157151581515915160151611516215163151641516515166151671516815169151701517115172151731517415175151761517715178151791518015181151821518315184151851518615187151881518915190151911519215193151941519515196151971519815199152001520115202152031520415205152061520715208152091521015211152121521315214152151521615217152181521915220152211522215223152241522515226152271522815229152301523115232152331523415235152361523715238152391524015241152421524315244152451524615247152481524915250152511525215253152541525515256152571525815259152601526115262152631526415265152661526715268152691527015271152721527315274152751527615277152781527915280152811528215283152841528515286152871528815289152901529115292152931529415295152961529715298152991530015301153021530315304153051530615307153081530915310153111531215313153141531515316153171531815319153201532115322153231532415325153261532715328153291533015331153321533315334153351533615337153381533915340153411534215343153441534515346153471534815349153501535115352153531535415355153561535715358153591536015361153621536315364153651536615367153681536915370153711537215373153741537515376153771537815379153801538115382153831538415385153861538715388153891539015391153921539315394153951539615397153981539915400154011540215403154041540515406154071540815409154101541115412154131541415415154161541715418154191542015421154221542315424154251542615427154281542915430154311543215433154341543515436154371543815439154401544115442154431544415445154461544715448154491545015451154521545315454154551545615457154581545915460154611546215463154641546515466154671546815469154701547115472154731547415475154761547715478154791548015481154821548315484154851548615487154881548915490154911549215493154941549515496154971549815499155001550115502155031550415505155061550715508155091551015511155121551315514155151551615517155181551915520155211552215523155241552515526155271552815529155301553115532155331553415535155361553715538155391554015541155421554315544155451554615547155481554915550155511555215553155541555515556155571555815559155601556115562155631556415565155661556715568155691557015571155721557315574155751557615577155781557915580155811558215583155841558515586155871558815589155901559115592155931559415595155961559715598155991560015601156021560315604156051560615607156081560915610156111561215613156141561515616156171561815619156201562115622156231562415625156261562715628156291563015631156321563315634156351563615637156381563915640156411564215643156441564515646156471564815649156501565115652156531565415655156561565715658156591566015661156621566315664156651566615667156681566915670156711567215673156741567515676156771567815679156801568115682156831568415685156861568715688156891569015691156921569315694156951569615697156981569915700157011570215703157041570515706157071570815709157101571115712157131571415715157161571715718157191572015721157221572315724157251572615727157281572915730157311573215733157341573515736157371573815739157401574115742157431574415745157461574715748157491575015751157521575315754157551575615757157581575915760157611576215763157641576515766157671576815769157701577115772157731577415775157761577715778157791578015781157821578315784157851578615787157881578915790157911579215793157941579515796157971579815799158001580115802158031580415805158061580715808158091581015811158121581315814158151581615817158181581915820158211582215823158241582515826158271582815829158301583115832158331583415835158361583715838158391584015841158421584315844158451584615847158481584915850158511585215853158541585515856158571585815859158601586115862158631586415865158661586715868158691587015871158721587315874158751587615877158781587915880158811588215883158841588515886158871588815889158901589115892158931589415895158961589715898158991590015901159021590315904159051590615907159081590915910159111591215913159141591515916159171591815919159201592115922159231592415925159261592715928159291593015931159321593315934159351593615937159381593915940159411594215943159441594515946159471594815949159501595115952159531595415955159561595715958159591596015961159621596315964159651596615967159681596915970159711597215973159741597515976159771597815979159801598115982159831598415985159861598715988159891599015991159921599315994159951599615997159981599916000160011600216003160041600516006160071600816009160101601116012160131601416015160161601716018160191602016021160221602316024160251602616027160281602916030160311603216033160341603516036160371603816039160401604116042160431604416045160461604716048160491605016051160521605316054160551605616057160581605916060160611606216063160641606516066160671606816069160701607116072160731607416075160761607716078160791608016081160821608316084160851608616087160881608916090160911609216093160941609516096160971609816099161001610116102161031610416105161061610716108161091611016111161121611316114161151611616117161181611916120161211612216123161241612516126161271612816129161301613116132161331613416135161361613716138161391614016141161421614316144161451614616147161481614916150161511615216153161541615516156161571615816159161601616116162161631616416165161661616716168161691617016171161721617316174161751617616177161781617916180161811618216183161841618516186161871618816189161901619116192161931619416195161961619716198161991620016201162021620316204162051620616207162081620916210162111621216213162141621516216162171621816219162201622116222162231622416225162261622716228162291623016231162321623316234162351623616237162381623916240162411624216243162441624516246162471624816249162501625116252162531625416255162561625716258162591626016261162621626316264162651626616267162681626916270162711627216273162741627516276162771627816279162801628116282162831628416285162861628716288162891629016291162921629316294162951629616297162981629916300163011630216303163041630516306163071630816309163101631116312163131631416315163161631716318163191632016321163221632316324163251632616327163281632916330163311633216333163341633516336163371633816339163401634116342163431634416345163461634716348163491635016351163521635316354163551635616357163581635916360163611636216363163641636516366163671636816369163701637116372163731637416375163761637716378163791638016381163821638316384163851638616387163881638916390163911639216393163941639516396163971639816399164001640116402164031640416405164061640716408164091641016411164121641316414164151641616417164181641916420164211642216423164241642516426164271642816429164301643116432164331643416435164361643716438164391644016441164421644316444164451644616447164481644916450164511645216453164541645516456164571645816459164601646116462164631646416465164661646716468164691647016471164721647316474164751647616477164781647916480164811648216483164841648516486164871648816489164901649116492164931649416495164961649716498164991650016501165021650316504165051650616507165081650916510165111651216513165141651516516165171651816519165201652116522165231652416525165261652716528165291653016531165321653316534165351653616537165381653916540165411654216543165441654516546165471654816549165501655116552165531655416555165561655716558165591656016561165621656316564165651656616567165681656916570165711657216573165741657516576165771657816579165801658116582165831658416585165861658716588165891659016591165921659316594165951659616597165981659916600166011660216603166041660516606166071660816609166101661116612166131661416615166161661716618166191662016621166221662316624166251662616627166281662916630166311663216633166341663516636166371663816639166401664116642166431664416645166461664716648166491665016651166521665316654166551665616657166581665916660166611666216663166641666516666166671666816669166701667116672166731667416675166761667716678166791668016681166821668316684166851668616687166881668916690166911669216693166941669516696166971669816699167001670116702167031670416705167061670716708167091671016711167121671316714167151671616717167181671916720167211672216723167241672516726167271672816729167301673116732167331673416735167361673716738167391674016741167421674316744167451674616747167481674916750167511675216753167541675516756167571675816759167601676116762167631676416765167661676716768167691677016771167721677316774167751677616777167781677916780167811678216783167841678516786167871678816789167901679116792167931679416795167961679716798167991680016801168021680316804168051680616807168081680916810168111681216813168141681516816168171681816819168201682116822168231682416825168261682716828168291683016831168321683316834168351683616837168381683916840168411684216843168441684516846168471684816849168501685116852168531685416855168561685716858168591686016861168621686316864168651686616867168681686916870168711687216873168741687516876168771687816879168801688116882168831688416885168861688716888168891689016891168921689316894168951689616897168981689916900169011690216903169041690516906169071690816909169101691116912169131691416915169161691716918169191692016921169221692316924169251692616927169281692916930169311693216933169341693516936169371693816939169401694116942169431694416945169461694716948169491695016951169521695316954169551695616957169581695916960169611696216963169641696516966169671696816969169701697116972169731697416975169761697716978169791698016981169821698316984169851698616987169881698916990169911699216993169941699516996169971699816999170001700117002170031700417005170061700717008170091701017011170121701317014170151701617017170181701917020170211702217023170241702517026170271702817029170301703117032170331703417035170361703717038170391704017041170421704317044170451704617047170481704917050170511705217053170541705517056170571705817059170601706117062170631706417065170661706717068170691707017071170721707317074170751707617077170781707917080170811708217083170841708517086170871708817089170901709117092170931709417095170961709717098170991710017101171021710317104171051710617107171081710917110171111711217113171141711517116171171711817119171201712117122171231712417125171261712717128171291713017131171321713317134171351713617137171381713917140171411714217143171441714517146171471714817149171501715117152171531715417155171561715717158171591716017161171621716317164171651716617167171681716917170171711717217173171741717517176171771717817179171801718117182171831718417185171861718717188171891719017191171921719317194171951719617197171981719917200172011720217203172041720517206172071720817209172101721117212172131721417215172161721717218172191722017221172221722317224172251722617227172281722917230172311723217233172341723517236172371723817239172401724117242172431724417245172461724717248172491725017251172521725317254172551725617257172581725917260172611726217263172641726517266172671726817269172701727117272172731727417275172761727717278172791728017281172821728317284172851728617287172881728917290172911729217293172941729517296172971729817299173001730117302173031730417305173061730717308173091731017311173121731317314173151731617317173181731917320173211732217323173241732517326173271732817329173301733117332173331733417335173361733717338173391734017341173421734317344173451734617347173481734917350173511735217353173541735517356173571735817359173601736117362173631736417365173661736717368173691737017371173721737317374173751737617377173781737917380173811738217383173841738517386173871738817389173901739117392173931739417395173961739717398173991740017401174021740317404174051740617407174081740917410174111741217413174141741517416174171741817419174201742117422174231742417425174261742717428174291743017431174321743317434174351743617437174381743917440174411744217443174441744517446174471744817449174501745117452174531745417455174561745717458174591746017461174621746317464174651746617467174681746917470174711747217473174741747517476174771747817479174801748117482174831748417485174861748717488174891749017491174921749317494174951749617497174981749917500175011750217503175041750517506175071750817509175101751117512175131751417515175161751717518175191752017521175221752317524175251752617527175281752917530175311753217533175341753517536175371753817539175401754117542175431754417545175461754717548175491755017551175521755317554175551755617557175581755917560175611756217563175641756517566175671756817569175701757117572175731757417575175761757717578175791758017581175821758317584175851758617587175881758917590175911759217593175941759517596175971759817599176001760117602176031760417605176061760717608176091761017611176121761317614176151761617617176181761917620176211762217623176241762517626176271762817629176301763117632176331763417635176361763717638176391764017641176421764317644176451764617647176481764917650176511765217653176541765517656176571765817659176601766117662176631766417665176661766717668176691767017671176721767317674176751767617677176781767917680176811768217683176841768517686176871768817689176901769117692176931769417695176961769717698176991770017701177021770317704177051770617707177081770917710177111771217713177141771517716177171771817719177201772117722177231772417725177261772717728177291773017731177321773317734177351773617737177381773917740177411774217743177441774517746177471774817749177501775117752177531775417755177561775717758177591776017761177621776317764177651776617767177681776917770177711777217773177741777517776177771777817779177801778117782177831778417785177861778717788177891779017791177921779317794177951779617797177981779917800178011780217803178041780517806178071780817809178101781117812178131781417815178161781717818178191782017821178221782317824178251782617827178281782917830178311783217833178341783517836178371783817839178401784117842178431784417845178461784717848178491785017851178521785317854178551785617857178581785917860178611786217863178641786517866178671786817869178701787117872178731787417875178761787717878178791788017881178821788317884178851788617887178881788917890178911789217893178941789517896178971789817899179001790117902179031790417905179061790717908179091791017911179121791317914179151791617917179181791917920179211792217923179241792517926179271792817929179301793117932179331793417935179361793717938179391794017941179421794317944179451794617947179481794917950179511795217953179541795517956179571795817959179601796117962179631796417965179661796717968179691797017971179721797317974179751797617977179781797917980179811798217983179841798517986179871798817989179901799117992179931799417995179961799717998179991800018001180021800318004180051800618007180081800918010180111801218013180141801518016180171801818019180201802118022180231802418025180261802718028180291803018031180321803318034180351803618037180381803918040180411804218043180441804518046180471804818049180501805118052180531805418055180561805718058180591806018061180621806318064180651806618067180681806918070180711807218073180741807518076180771807818079180801808118082180831808418085180861808718088180891809018091180921809318094180951809618097180981809918100181011810218103181041810518106181071810818109181101811118112181131811418115181161811718118181191812018121181221812318124181251812618127181281812918130181311813218133181341813518136181371813818139181401814118142181431814418145181461814718148181491815018151181521815318154181551815618157181581815918160181611816218163181641816518166181671816818169181701817118172181731817418175181761817718178181791818018181181821818318184181851818618187181881818918190181911819218193181941819518196181971819818199182001820118202182031820418205182061820718208182091821018211182121821318214182151821618217182181821918220182211822218223182241822518226182271822818229182301823118232182331823418235182361823718238182391824018241182421824318244182451824618247182481824918250182511825218253182541825518256182571825818259182601826118262182631826418265182661826718268182691827018271182721827318274182751827618277182781827918280182811828218283182841828518286182871828818289182901829118292182931829418295182961829718298182991830018301183021830318304183051830618307183081830918310183111831218313183141831518316183171831818319183201832118322183231832418325183261832718328183291833018331183321833318334183351833618337183381833918340183411834218343183441834518346183471834818349183501835118352183531835418355183561835718358183591836018361183621836318364183651836618367183681836918370183711837218373183741837518376183771837818379183801838118382183831838418385183861838718388183891839018391183921839318394183951839618397183981839918400184011840218403184041840518406184071840818409184101841118412184131841418415184161841718418184191842018421184221842318424184251842618427184281842918430184311843218433184341843518436184371843818439184401844118442184431844418445184461844718448184491845018451184521845318454184551845618457184581845918460184611846218463184641846518466184671846818469184701847118472184731847418475184761847718478184791848018481184821848318484184851848618487184881848918490184911849218493184941849518496184971849818499185001850118502185031850418505185061850718508185091851018511185121851318514185151851618517185181851918520185211852218523185241852518526185271852818529185301853118532185331853418535185361853718538185391854018541185421854318544185451854618547185481854918550185511855218553185541855518556185571855818559185601856118562185631856418565185661856718568185691857018571185721857318574185751857618577185781857918580185811858218583185841858518586185871858818589185901859118592185931859418595185961859718598185991860018601186021860318604186051860618607186081860918610186111861218613186141861518616186171861818619186201862118622186231862418625186261862718628186291863018631186321863318634186351863618637186381863918640186411864218643186441864518646186471864818649186501865118652186531865418655186561865718658186591866018661186621866318664186651866618667186681866918670186711867218673186741867518676186771867818679186801868118682186831868418685186861868718688186891869018691186921869318694186951869618697186981869918700187011870218703187041870518706187071870818709187101871118712187131871418715187161871718718187191872018721187221872318724187251872618727187281872918730187311873218733187341873518736187371873818739187401874118742187431874418745187461874718748187491875018751187521875318754187551875618757187581875918760187611876218763187641876518766187671876818769187701877118772187731877418775187761877718778187791878018781187821878318784187851878618787187881878918790187911879218793187941879518796187971879818799188001880118802188031880418805188061880718808188091881018811188121881318814188151881618817188181881918820188211882218823188241882518826188271882818829188301883118832188331883418835188361883718838188391884018841188421884318844188451884618847188481884918850188511885218853188541885518856188571885818859188601886118862188631886418865188661886718868188691887018871188721887318874188751887618877188781887918880188811888218883188841888518886188871888818889188901889118892188931889418895188961889718898188991890018901
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSimulator Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. using log4net;
  28. using Nini.Config;
  29. using OpenMetaverse;
  30. using OpenMetaverse.Assets;
  31. using OpenMetaverse.Packets;
  32. using OpenMetaverse.Rendering;
  33. using OpenSim.Framework;
  34. using OpenSim.Region.CoreModules.World.Land;
  35. using OpenSim.Region.Framework.Interfaces;
  36. using OpenSim.Region.Framework.Scenes;
  37. using OpenSim.Region.Framework.Scenes.Animation;
  38. using OpenSim.Region.Framework.Scenes.Scripting;
  39. using OpenSim.Region.Framework.Scenes.Serialization;
  40. using OpenSim.Region.PhysicsModules.SharedBase;
  41. using OpenSim.Region.ScriptEngine.Interfaces;
  42. using OpenSim.Region.ScriptEngine.Shared.Api.Interfaces;
  43. using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
  44. using OpenSim.Services.Interfaces;
  45. using OpenSim.Services.Connectors.Hypergrid;
  46. using System;
  47. using System.Collections;
  48. using System.Collections.Generic;
  49. using System.Collections.Specialized;
  50. using System.Diagnostics;
  51. using System.Drawing;
  52. using System.Globalization;
  53. using System.Reflection;
  54. using System.Security.Cryptography;
  55. using System.Text;
  56. using System.Text.RegularExpressions;
  57. using System.Threading;
  58. using AssetLandmark = OpenSim.Framework.AssetLandmark;
  59. using GridRegion = OpenSim.Services.Interfaces.GridRegion;
  60. using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
  61. using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
  62. using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
  63. using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
  64. using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
  65. using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
  66. using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
  67. using PermissionMask = OpenSim.Framework.PermissionMask;
  68. using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo;
  69. using PrimType = OpenSim.Region.Framework.Scenes.PrimType;
  70. using RegionFlags = OpenSim.Framework.RegionFlags;
  71. using RegionInfo = OpenSim.Framework.RegionInfo;
  72. using System.Runtime.CompilerServices;
  73. #pragma warning disable IDE1006
  74. namespace OpenSim.Region.ScriptEngine.Shared.Api
  75. {
  76. /// <summary>
  77. /// Contains all LSL ll-functions. This class will be in Default AppDomain.
  78. /// </summary>
  79. public class LSL_Api : ILSL_Api, IScriptApi
  80. {
  81. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  82. private int m_llRequestAgentDataCacheTimeout;
  83. public int LlRequestAgentDataCacheTimeoutMs
  84. {
  85. get
  86. {
  87. return 1000 * m_llRequestAgentDataCacheTimeout;
  88. }
  89. set
  90. {
  91. m_llRequestAgentDataCacheTimeout = value / 1000;
  92. }
  93. }
  94. protected IScriptEngine m_ScriptEngine;
  95. public Scene World;
  96. protected SceneObjectPart m_host;
  97. protected UUID RegionScopeID = UUID.Zero;
  98. protected string m_regionName = String.Empty;
  99. /// <summary>
  100. /// The item that hosts this script
  101. /// </summary>
  102. protected TaskInventoryItem m_item;
  103. protected bool throwErrorOnNotImplemented = false;
  104. protected float m_ScriptDelayFactor = 1.0f;
  105. protected float m_Script10mDistance = 10.0f;
  106. protected float m_Script10mDistanceSquare = 100.0f;
  107. protected float m_MinTimerInterval = 0.5f;
  108. protected float m_recoilScaleFactor = 0.0f;
  109. protected bool m_AllowGodFunctions;
  110. protected double m_timer = Util.GetTimeStampMS();
  111. protected bool m_waitingForScriptAnswer = false;
  112. protected bool m_automaticLinkPermission = false;
  113. protected int m_notecardLineReadCharsMax = 255;
  114. protected int m_scriptConsoleChannel = 0;
  115. protected bool m_scriptConsoleChannelEnabled = false;
  116. protected bool m_debuggerSafe = false;
  117. protected AsyncCommandManager m_AsyncCommands = null;
  118. protected IUrlModule m_UrlModule = null;
  119. protected IMaterialsModule m_materialsModule = null;
  120. protected IEnvironmentModule m_envModule = null;
  121. protected IEmailModule m_emailModule = null;
  122. protected IUserAccountService m_userAccountService = null;
  123. protected IMessageTransferModule m_TransferModule = null;
  124. protected ExpiringCacheOS<UUID, PresenceInfo> m_PresenceInfoCache = new(10000);
  125. protected int EMAIL_PAUSE_TIME = 20; // documented delay value for smtp.
  126. protected int m_sleepMsOnSetTexture = 200;
  127. protected int m_sleepMsOnSetLinkTexture = 200;
  128. protected int m_sleepMsOnScaleTexture = 200;
  129. protected int m_sleepMsOnOffsetTexture = 200;
  130. protected int m_sleepMsOnRotateTexture = 200;
  131. protected int m_sleepMsOnSetPos = 200;
  132. protected int m_sleepMsOnSetRot = 200;
  133. protected int m_sleepMsOnSetLocalRot = 200;
  134. protected int m_sleepMsOnPreloadSound = 1000;
  135. protected int m_sleepMsOnMakeExplosion = 100;
  136. protected int m_sleepMsOnMakeFountain = 100;
  137. protected int m_sleepMsOnMakeSmoke = 100;
  138. protected int m_sleepMsOnMakeFire = 100;
  139. protected int m_sleepMsOnRezAtRoot = 100;
  140. protected int m_sleepMsOnInstantMessage = 2000;
  141. protected int m_sleepMsOnEmail = 30000;
  142. protected int m_sleepMsOnCreateLink = 1000;
  143. protected int m_sleepMsOnGiveInventory = 3000;
  144. protected int m_sleepMsOnRequestAgentData = 100;
  145. protected int m_sleepMsOnRequestInventoryData = 1000;
  146. protected int m_sleepMsOnSetDamage = 5000;
  147. protected int m_sleepMsOnTextBox = 1000;
  148. protected int m_sleepMsOnAdjustSoundVolume = 100;
  149. protected int m_sleepMsOnEjectFromLand = 1000;
  150. protected int m_sleepMsOnAddToLandPassList = 100;
  151. protected int m_sleepMsOnDialog = 1000;
  152. protected int m_sleepMsOnRemoteLoadScript = 3000;
  153. protected int m_sleepMsOnRemoteLoadScriptPin = 3000;
  154. protected int m_sleepMsOnOpenRemoteDataChannel = 1000;
  155. protected int m_sleepMsOnSendRemoteData = 3000;
  156. protected int m_sleepMsOnRemoteDataReply = 3000;
  157. protected int m_sleepMsOnCloseRemoteDataChannel = 1000;
  158. protected int m_sleepMsOnSetPrimitiveParams = 200;
  159. protected int m_sleepMsOnSetLinkPrimitiveParams = 200;
  160. protected int m_sleepMsOnXorBase64Strings = 300;
  161. protected int m_sleepMsOnSetParcelMusicURL = 2000;
  162. protected int m_sleepMsOnGetPrimMediaParams = 1000;
  163. protected int m_sleepMsOnGetLinkMedia = 1000;
  164. protected int m_sleepMsOnSetPrimMediaParams = 1000;
  165. protected int m_sleepMsOnSetLinkMedia = 1000;
  166. protected int m_sleepMsOnClearPrimMedia = 1000;
  167. protected int m_sleepMsOnClearLinkMedia = 1000;
  168. protected int m_sleepMsOnRequestSimulatorData = 1000;
  169. protected int m_sleepMsOnLoadURL = 1000;
  170. protected int m_sleepMsOnParcelMediaCommandList = 2000;
  171. protected int m_sleepMsOnParcelMediaQuery = 2000;
  172. protected int m_sleepMsOnModPow = 1000;
  173. protected int m_sleepMsOnSetPrimURL = 2000;
  174. protected int m_sleepMsOnRefreshPrimURL = 20000;
  175. protected int m_sleepMsOnMapDestination = 1000;
  176. protected int m_sleepMsOnAddToLandBanList = 100;
  177. protected int m_sleepMsOnRemoveFromLandPassList = 100;
  178. protected int m_sleepMsOnRemoveFromLandBanList = 100;
  179. protected int m_sleepMsOnResetLandBanList = 100;
  180. protected int m_sleepMsOnResetLandPassList = 100;
  181. protected int m_sleepMsOnGetParcelPrimOwners = 2000;
  182. protected int m_sleepMsOnGetNumberOfNotecardLines = 100;
  183. protected int m_sleepMsOnGetNotecardLine = 100;
  184. protected string m_internalObjectHost = "lsl.opensim.local";
  185. protected bool m_restrictEmail = false;
  186. protected ISoundModule m_SoundModule = null;
  187. protected float m_avatarHeightCorrection = 0.2f;
  188. protected bool m_useSimpleBoxesInGetBoundingBox = false;
  189. protected bool m_addStatsInGetBoundingBox = false;
  190. //LSL Avatar Bounding Box (lABB), lower (1) and upper (2),
  191. //standing (Std), Groundsitting (Grs), Sitting (Sit),
  192. //along X, Y and Z axes, constants (0) and coefficients (1)
  193. protected float m_lABB1StdX0 = -0.275f;
  194. protected float m_lABB2StdX0 = 0.275f;
  195. protected float m_lABB1StdY0 = -0.35f;
  196. protected float m_lABB2StdY0 = 0.35f;
  197. protected float m_lABB1StdZ0 = -0.1f;
  198. protected float m_lABB1StdZ1 = -0.5f;
  199. protected float m_lABB2StdZ0 = 0.1f;
  200. protected float m_lABB2StdZ1 = 0.5f;
  201. protected float m_lABB1GrsX0 = -0.3875f;
  202. protected float m_lABB2GrsX0 = 0.3875f;
  203. protected float m_lABB1GrsY0 = -0.5f;
  204. protected float m_lABB2GrsY0 = 0.5f;
  205. protected float m_lABB1GrsZ0 = -0.05f;
  206. protected float m_lABB1GrsZ1 = -0.375f;
  207. protected float m_lABB2GrsZ0 = 0.5f;
  208. protected float m_lABB2GrsZ1 = 0.0f;
  209. protected float m_lABB1SitX0 = -0.5875f;
  210. protected float m_lABB2SitX0 = 0.1875f;
  211. protected float m_lABB1SitY0 = -0.35f;
  212. protected float m_lABB2SitY0 = 0.35f;
  213. protected float m_lABB1SitZ0 = -0.35f;
  214. protected float m_lABB1SitZ1 = -0.375f;
  215. protected float m_lABB2SitZ0 = -0.25f;
  216. protected float m_lABB2SitZ1 = 0.25f;
  217. protected float m_primSafetyCoeffX = 2.414214f;
  218. protected float m_primSafetyCoeffY = 2.414214f;
  219. protected float m_primSafetyCoeffZ = 1.618034f;
  220. protected float m_floatToleranceInCastRay = 0.00001f;
  221. protected float m_floatTolerance2InCastRay = 0.001f;
  222. protected DetailLevel m_primLodInCastRay = DetailLevel.Medium;
  223. protected DetailLevel m_sculptLodInCastRay = DetailLevel.Medium;
  224. protected DetailLevel m_meshLodInCastRay = DetailLevel.Highest;
  225. protected DetailLevel m_avatarLodInCastRay = DetailLevel.Medium;
  226. protected int m_maxHitsInCastRay = 16;
  227. protected int m_maxHitsPerPrimInCastRay = 16;
  228. protected int m_maxHitsPerObjectInCastRay = 16;
  229. protected bool m_detectExitsInCastRay = false;
  230. protected bool m_doAttachmentsInCastRay = false;
  231. protected int m_msThrottleInCastRay = 200;
  232. protected int m_msPerRegionInCastRay = 40;
  233. protected int m_msPerAvatarInCastRay = 10;
  234. protected int m_msMinInCastRay = 2;
  235. protected int m_msMaxInCastRay = 40;
  236. protected static List<CastRayCall> m_castRayCalls = new();
  237. protected bool m_useMeshCacheInCastRay = true;
  238. protected static Dictionary<ulong, FacetedMesh> m_cachedMeshes = new();
  239. //protected Timer m_ShoutSayTimer;
  240. protected int m_SayShoutCount = 0;
  241. DateTime m_lastSayShoutCheck;
  242. private int m_whisperdistance = 10;
  243. private int m_saydistance = 20;
  244. private int m_shoutdistance = 100;
  245. bool m_disable_underground_movement = true;
  246. private string m_lsl_shard = "OpenSim";
  247. private string m_lsl_user_agent = string.Empty;
  248. private int m_linksetDataLimit = 32 * 1024;
  249. private static readonly Dictionary<string, string> MovementAnimationsForLSL = new(StringComparer.InvariantCultureIgnoreCase)
  250. {
  251. {"CROUCH", "Crouching"},
  252. {"CROUCHWALK", "CrouchWalking"},
  253. {"FALLDOWN", "Falling Down"},
  254. {"FLY", "Flying"},
  255. {"FLYSLOW", "FlyingSlow"},
  256. {"HOVER", "Hovering"},
  257. {"HOVER_UP", "Hovering Up"},
  258. {"HOVER_DOWN", "Hovering Down"},
  259. {"JUMP", "Jumping"},
  260. {"LAND", "Landing"},
  261. {"PREJUMP", "PreJumping"},
  262. {"RUN", "Running"},
  263. {"SIT","Sitting"},
  264. {"SITGROUND","Sitting on Ground"},
  265. {"STAND", "Standing"},
  266. {"STANDUP", "Standing Up"},
  267. {"STRIDE","Striding"},
  268. {"SOFT_LAND", "Soft Landing"},
  269. {"TURNLEFT", "Turning Left"},
  270. {"TURNRIGHT", "Turning Right"},
  271. {"WALK", "Walking"}
  272. };
  273. //llHTTPRequest custom headers use control
  274. // true means fatal error,
  275. // false means ignore,
  276. // missing means allowed
  277. private static readonly Dictionary<string,bool> HttpForbiddenHeaders = new(StringComparer.InvariantCultureIgnoreCase)
  278. {
  279. {"Accept", true},
  280. {"Accept-Charset", true},
  281. {"Accept-CH", false},
  282. {"Accept-CH-Lifetime", false},
  283. {"Access-Control-Request-Headers", false},
  284. {"Access-Control-Request-Method", false},
  285. {"Accept-Encoding", false},
  286. //{"Accept-Language", false},
  287. {"Accept-Patch", false}, // it is server side
  288. {"Accept-Post", false}, // it is server side
  289. {"Accept-Ranges", false}, // it is server side
  290. //{"Age", false},
  291. //{"Allow", false},
  292. //{"Authorization", false},
  293. {"Cache-Control", false},
  294. {"Connection", false},
  295. {"Content-Length", false},
  296. //{"Content-Encoding", false},
  297. //{"Content-Location", false},
  298. //{"Content-MD5", false},
  299. //{"Content-Range", false},
  300. {"Content-Type", true},
  301. {"Cookie", false},
  302. {"Cookie2", false},
  303. {"Date", false},
  304. {"Device-Memory", false},
  305. {"DTN", false},
  306. {"Early-Data", false},
  307. //{"ETag", false},
  308. {"Expect", false},
  309. //{"Expires", false},
  310. {"Feature-Policy", false},
  311. {"From", true},
  312. {"Host", true},
  313. {"Keep-Alive", false},
  314. {"If-Match", false},
  315. {"If-Modified-Since", false},
  316. {"If-None-Match", false},
  317. //{"If-Range", false},
  318. {"If-Unmodified-Since", false},
  319. //{"Last-Modified", false},
  320. //{"Location", false},
  321. {"Max-Forwards", false},
  322. {"Origin", false},
  323. {"Pragma", false},
  324. //{"Proxy-Authenticate", false},
  325. //{"Proxy-Authorization", false},
  326. //{"Range", false},
  327. {"Referer", true},
  328. //{"Retry-After", false},
  329. {"Server", false},
  330. {"Set-Cookie", false},
  331. {"Set-Cookie2", false},
  332. {"TE", true},
  333. {"Trailer", true},
  334. {"Transfer-Encoding", false},
  335. {"Upgrade", true},
  336. {"User-Agent", true},
  337. {"Vary", false},
  338. {"Via", true},
  339. {"Viewport-Width", false},
  340. {"Warning", false},
  341. {"Width", false},
  342. //{"WWW-Authenticate", false},
  343. {"X-Forwarded-For", false},
  344. {"X-Forwarded-Host", false},
  345. {"X-Forwarded-Proto", false},
  346. {"x-secondlife-shard", false},
  347. {"x-secondlife-object-name", false},
  348. {"x-secondlife-object-key", false},
  349. {"x-secondlife-region", false},
  350. {"x-secondlife-local-position", false},
  351. {"x-secondlife-local-velocity", false},
  352. {"x-secondlife-local-rotation", false},
  353. {"x-secondlife-owner-name", false},
  354. {"x-secondlife-owner-key", false},
  355. };
  356. private static readonly HashSet<string> HttpForbiddenInHeaders = new(StringComparer.InvariantCultureIgnoreCase)
  357. {
  358. "x-secondlife-shard", "x-secondlife-object-name", "x-secondlife-object-key",
  359. "x-secondlife-region", "x-secondlife-local-position", "x-secondlife-local-velocity",
  360. "x-secondlife-local-rotation", "x-secondlife-owner-name", "x-secondlife-owner-key",
  361. "connection", "content-length", "from", "host", "proxy-authorization",
  362. "referer", "trailer", "transfer-encoding", "via", "authorization"
  363. };
  364. public void Initialize(IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item)
  365. {
  366. m_lastSayShoutCheck = DateTime.UtcNow;
  367. m_ScriptEngine = scriptEngine;
  368. World = m_ScriptEngine.World;
  369. m_host = host;
  370. m_item = item;
  371. m_debuggerSafe = m_ScriptEngine.Config.GetBoolean("DebuggerSafe", false);
  372. LoadConfig();
  373. m_TransferModule = m_ScriptEngine.World.RequestModuleInterface<IMessageTransferModule>();
  374. m_UrlModule = m_ScriptEngine.World.RequestModuleInterface<IUrlModule>();
  375. m_SoundModule = m_ScriptEngine.World.RequestModuleInterface<ISoundModule>();
  376. m_materialsModule = m_ScriptEngine.World.RequestModuleInterface<IMaterialsModule>();
  377. m_emailModule = m_ScriptEngine.World.RequestModuleInterface<IEmailModule>();
  378. m_envModule = m_ScriptEngine.World.RequestModuleInterface< IEnvironmentModule>();
  379. m_AsyncCommands = new AsyncCommandManager(m_ScriptEngine);
  380. m_userAccountService = World.UserAccountService;
  381. if(World.RegionInfo != null)
  382. {
  383. RegionScopeID = World.RegionInfo.ScopeID;
  384. m_regionName = World.RegionInfo.RegionName;
  385. }
  386. }
  387. /// <summary>
  388. /// Load configuration items that affect script, object and run-time behavior. */
  389. /// </summary>
  390. private void LoadConfig()
  391. {
  392. LlRequestAgentDataCacheTimeoutMs = 20000;
  393. IConfig seConfig = m_ScriptEngine.Config;
  394. if (seConfig is not null)
  395. {
  396. float scriptDistanceFactor = seConfig.GetFloat("ScriptDistanceLimitFactor", 1.0f);
  397. m_Script10mDistance = 10.0f * scriptDistanceFactor;
  398. m_Script10mDistanceSquare = m_Script10mDistance * m_Script10mDistance;
  399. m_ScriptDelayFactor = seConfig.GetFloat("ScriptDelayFactor", m_ScriptDelayFactor);
  400. m_MinTimerInterval = seConfig.GetFloat("MinTimerInterval", m_MinTimerInterval);
  401. m_automaticLinkPermission = seConfig.GetBoolean("AutomaticLinkPermission", m_automaticLinkPermission);
  402. m_notecardLineReadCharsMax = seConfig.GetInt("NotecardLineReadCharsMax", m_notecardLineReadCharsMax);
  403. // Rezzing an object with a velocity can create recoil. This feature seems to have been
  404. // removed from recent versions of SL. The code computes recoil (vel*mass) and scales
  405. // it by this factor. May be zero to turn off recoil all together.
  406. m_recoilScaleFactor = seConfig.GetFloat("RecoilScaleFactor", m_recoilScaleFactor);
  407. m_AllowGodFunctions = seConfig.GetBoolean("AllowGodFunctions", false);
  408. m_disable_underground_movement = seConfig.GetBoolean("DisableUndergroundMovement", true);
  409. m_linksetDataLimit = seConfig.GetInt("LinksetDataLimit", m_linksetDataLimit);
  410. }
  411. if (m_notecardLineReadCharsMax > 65535)
  412. m_notecardLineReadCharsMax = 65535;
  413. // load limits for particular subsystems.
  414. IConfigSource seConfigSource = m_ScriptEngine.ConfigSource;
  415. if (seConfigSource != null)
  416. {
  417. IConfig netConfig = seConfigSource.Configs["Network"];
  418. if (netConfig != null)
  419. {
  420. m_lsl_shard = netConfig.GetString("shard", m_lsl_shard);
  421. m_lsl_user_agent = netConfig.GetString("user_agent", m_lsl_user_agent);
  422. }
  423. IConfig lslConfig = seConfigSource.Configs["LL-Functions"];
  424. if (lslConfig != null)
  425. {
  426. m_restrictEmail = lslConfig.GetBoolean("RestrictEmail", m_restrictEmail);
  427. m_avatarHeightCorrection = lslConfig.GetFloat("AvatarHeightCorrection", m_avatarHeightCorrection);
  428. m_useSimpleBoxesInGetBoundingBox = lslConfig.GetBoolean("UseSimpleBoxesInGetBoundingBox", m_useSimpleBoxesInGetBoundingBox);
  429. m_addStatsInGetBoundingBox = lslConfig.GetBoolean("AddStatsInGetBoundingBox", m_addStatsInGetBoundingBox);
  430. m_lABB1StdX0 = lslConfig.GetFloat("LowerAvatarBoundingBoxStandingXconst", m_lABB1StdX0);
  431. m_lABB2StdX0 = lslConfig.GetFloat("UpperAvatarBoundingBoxStandingXconst", m_lABB2StdX0);
  432. m_lABB1StdY0 = lslConfig.GetFloat("LowerAvatarBoundingBoxStandingYconst", m_lABB1StdY0);
  433. m_lABB2StdY0 = lslConfig.GetFloat("UpperAvatarBoundingBoxStandingYconst", m_lABB2StdY0);
  434. m_lABB1StdZ0 = lslConfig.GetFloat("LowerAvatarBoundingBoxStandingZconst", m_lABB1StdZ0);
  435. m_lABB1StdZ1 = lslConfig.GetFloat("LowerAvatarBoundingBoxStandingZcoeff", m_lABB1StdZ1);
  436. m_lABB2StdZ0 = lslConfig.GetFloat("UpperAvatarBoundingBoxStandingZconst", m_lABB2StdZ0);
  437. m_lABB2StdZ1 = lslConfig.GetFloat("UpperAvatarBoundingBoxStandingZcoeff", m_lABB2StdZ1);
  438. m_lABB1GrsX0 = lslConfig.GetFloat("LowerAvatarBoundingBoxGroundsittingXconst", m_lABB1GrsX0);
  439. m_lABB2GrsX0 = lslConfig.GetFloat("UpperAvatarBoundingBoxGroundsittingXconst", m_lABB2GrsX0);
  440. m_lABB1GrsY0 = lslConfig.GetFloat("LowerAvatarBoundingBoxGroundsittingYconst", m_lABB1GrsY0);
  441. m_lABB2GrsY0 = lslConfig.GetFloat("UpperAvatarBoundingBoxGroundsittingYconst", m_lABB2GrsY0);
  442. m_lABB1GrsZ0 = lslConfig.GetFloat("LowerAvatarBoundingBoxGroundsittingZconst", m_lABB1GrsZ0);
  443. m_lABB1GrsZ1 = lslConfig.GetFloat("LowerAvatarBoundingBoxGroundsittingZcoeff", m_lABB1GrsZ1);
  444. m_lABB2GrsZ0 = lslConfig.GetFloat("UpperAvatarBoundingBoxGroundsittingZconst", m_lABB2GrsZ0);
  445. m_lABB2GrsZ1 = lslConfig.GetFloat("UpperAvatarBoundingBoxGroundsittingZcoeff", m_lABB2GrsZ1);
  446. m_lABB1SitX0 = lslConfig.GetFloat("LowerAvatarBoundingBoxSittingXconst", m_lABB1SitX0);
  447. m_lABB2SitX0 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingXconst", m_lABB2SitX0);
  448. m_lABB1SitY0 = lslConfig.GetFloat("LowerAvatarBoundingBoxSittingYconst", m_lABB1SitY0);
  449. m_lABB2SitY0 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingYconst", m_lABB2SitY0);
  450. m_lABB1SitZ0 = lslConfig.GetFloat("LowerAvatarBoundingBoxSittingZconst", m_lABB1SitZ0);
  451. m_lABB1SitZ1 = lslConfig.GetFloat("LowerAvatarBoundingBoxSittingZcoeff", m_lABB1SitZ1);
  452. m_lABB2SitZ0 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingZconst", m_lABB2SitZ0);
  453. m_lABB2SitZ1 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingZcoeff", m_lABB2SitZ1);
  454. m_primSafetyCoeffX = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientX", m_primSafetyCoeffX);
  455. m_primSafetyCoeffY = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientY", m_primSafetyCoeffY);
  456. m_primSafetyCoeffZ = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientZ", m_primSafetyCoeffZ);
  457. m_floatToleranceInCastRay = lslConfig.GetFloat("FloatToleranceInLlCastRay", m_floatToleranceInCastRay);
  458. m_floatTolerance2InCastRay = lslConfig.GetFloat("FloatTolerance2InLlCastRay", m_floatTolerance2InCastRay);
  459. m_primLodInCastRay = (DetailLevel)lslConfig.GetInt("PrimDetailLevelInLlCastRay", (int)m_primLodInCastRay);
  460. m_sculptLodInCastRay = (DetailLevel)lslConfig.GetInt("SculptDetailLevelInLlCastRay", (int)m_sculptLodInCastRay);
  461. m_meshLodInCastRay = (DetailLevel)lslConfig.GetInt("MeshDetailLevelInLlCastRay", (int)m_meshLodInCastRay);
  462. m_avatarLodInCastRay = (DetailLevel)lslConfig.GetInt("AvatarDetailLevelInLlCastRay", (int)m_avatarLodInCastRay);
  463. m_maxHitsInCastRay = lslConfig.GetInt("MaxHitsInLlCastRay", m_maxHitsInCastRay);
  464. m_maxHitsPerPrimInCastRay = lslConfig.GetInt("MaxHitsPerPrimInLlCastRay", m_maxHitsPerPrimInCastRay);
  465. m_maxHitsPerObjectInCastRay = lslConfig.GetInt("MaxHitsPerObjectInLlCastRay", m_maxHitsPerObjectInCastRay);
  466. m_detectExitsInCastRay = lslConfig.GetBoolean("DetectExitHitsInLlCastRay", m_detectExitsInCastRay);
  467. m_doAttachmentsInCastRay = lslConfig.GetBoolean("DoAttachmentsInLlCastRay", m_doAttachmentsInCastRay);
  468. m_msThrottleInCastRay = lslConfig.GetInt("ThrottleTimeInMsInLlCastRay", m_msThrottleInCastRay);
  469. m_msPerRegionInCastRay = lslConfig.GetInt("AvailableTimeInMsPerRegionInLlCastRay", m_msPerRegionInCastRay);
  470. m_msPerAvatarInCastRay = lslConfig.GetInt("AvailableTimeInMsPerAvatarInLlCastRay", m_msPerAvatarInCastRay);
  471. m_msMinInCastRay = lslConfig.GetInt("RequiredAvailableTimeInMsInLlCastRay", m_msMinInCastRay);
  472. m_msMaxInCastRay = lslConfig.GetInt("MaximumAvailableTimeInMsInLlCastRay", m_msMaxInCastRay);
  473. m_useMeshCacheInCastRay = lslConfig.GetBoolean("UseMeshCacheInLlCastRay", m_useMeshCacheInCastRay);
  474. }
  475. IConfig smtpConfig = seConfigSource.Configs["SMTP"];
  476. if (smtpConfig != null)
  477. {
  478. // there's an smtp config, so load in the snooze time.
  479. EMAIL_PAUSE_TIME = smtpConfig.GetInt("email_pause_time", EMAIL_PAUSE_TIME);
  480. m_internalObjectHost = smtpConfig.GetString("internal_object_host", m_internalObjectHost);
  481. }
  482. IConfig chatConfig = seConfigSource.Configs["SMTP"];
  483. if(chatConfig != null)
  484. {
  485. m_whisperdistance = chatConfig.GetInt("whisper_distance", m_whisperdistance);
  486. m_saydistance = chatConfig.GetInt("say_distance", m_saydistance);
  487. m_shoutdistance = chatConfig.GetInt("shout_distance", m_shoutdistance);
  488. }
  489. }
  490. m_sleepMsOnEmail = EMAIL_PAUSE_TIME * 1000;
  491. }
  492. protected SceneObjectPart MonitoringObject()
  493. {
  494. UUID m = m_host.ParentGroup.MonitoringObject;
  495. if (m.IsZero())
  496. return null;
  497. SceneObjectPart p = m_ScriptEngine.World.GetSceneObjectPart(m);
  498. if (p == null)
  499. m_host.ParentGroup.MonitoringObject = UUID.Zero;
  500. return p;
  501. }
  502. protected virtual void ScriptSleep(int delay)
  503. {
  504. delay = (int)(delay * m_ScriptDelayFactor);
  505. if (delay < 10)
  506. return;
  507. Sleep(delay);
  508. }
  509. protected virtual void Sleep(int delay)
  510. {
  511. if (m_item == null) // Some unit tests don't set this
  512. Thread.Sleep(delay);
  513. else
  514. m_ScriptEngine.SleepScript(m_item.ItemID, delay);
  515. }
  516. [DebuggerNonUserCode]
  517. public void state(string newState)
  518. {
  519. m_ScriptEngine.SetState(m_item.ItemID, newState);
  520. }
  521. /// <summary>
  522. /// Reset the named script. The script must be present
  523. /// in the same prim.
  524. /// </summary>
  525. [DebuggerNonUserCode]
  526. public void llResetScript()
  527. {
  528. // We need to tell the URL module, if we hav one, to release
  529. // the allocated URLs
  530. m_UrlModule?.ScriptRemoved(m_item.ItemID);
  531. m_ScriptEngine.ApiResetScript(m_item.ItemID);
  532. }
  533. public void llResetOtherScript(string name)
  534. {
  535. UUID item = GetScriptByName(name);
  536. if (item.IsZero())
  537. {
  538. Error("llResetOtherScript", "Can't find script '" + name + "'");
  539. return;
  540. }
  541. if(item.Equals(m_item.ItemID))
  542. llResetScript();
  543. else
  544. {
  545. m_ScriptEngine.ResetScript(item);
  546. }
  547. }
  548. public LSL_Integer llGetScriptState(string name)
  549. {
  550. UUID item = GetScriptByName(name);
  551. if (!item.IsZero())
  552. {
  553. return m_ScriptEngine.GetScriptState(item) ?1:0;
  554. }
  555. Error("llGetScriptState", "Can't find script '" + name + "'");
  556. // If we didn't find it, then it's safe to
  557. // assume it is not running.
  558. return 0;
  559. }
  560. public void llSetScriptState(string name, int run)
  561. {
  562. UUID item = GetScriptByName(name);
  563. // These functions are supposed to be robust,
  564. // so get the state one step at a time.
  565. if (!item.IsZero())
  566. {
  567. m_ScriptEngine.SetScriptState(item, run != 0, item.Equals(m_item.ItemID));
  568. }
  569. else
  570. {
  571. Error("llSetScriptState", "Can't find script '" + name + "'");
  572. }
  573. }
  574. public List<ScenePresence> GetLinkAvatars(int linkType)
  575. {
  576. if (m_host is null)
  577. return new List<ScenePresence>();
  578. return GetLinkAvatars(linkType, m_host.ParentGroup);
  579. }
  580. public static List<ScenePresence> GetLinkAvatars(int linkType, SceneObjectGroup sog)
  581. {
  582. List<ScenePresence> ret = new();
  583. if (sog is null || sog.IsDeleted)
  584. return ret;
  585. List<ScenePresence> avs = sog.GetSittingAvatars();
  586. switch (linkType)
  587. {
  588. case ScriptBaseClass.LINK_SET:
  589. return avs;
  590. case ScriptBaseClass.LINK_ROOT:
  591. return ret;
  592. case ScriptBaseClass.LINK_ALL_OTHERS:
  593. return avs;
  594. case ScriptBaseClass.LINK_ALL_CHILDREN:
  595. return avs;
  596. case ScriptBaseClass.LINK_THIS:
  597. return ret;
  598. default:
  599. if (linkType < 0)
  600. return ret;
  601. int partCount = sog.GetPartCount();
  602. linkType -= partCount;
  603. if (linkType <= 0)
  604. {
  605. return ret;
  606. }
  607. else
  608. {
  609. if (linkType > avs.Count)
  610. {
  611. return ret;
  612. }
  613. else
  614. {
  615. ret.Add(avs[linkType - 1]);
  616. return ret;
  617. }
  618. }
  619. }
  620. }
  621. /// <summary>
  622. /// Get a given link entity from a linkset (linked objects and any sitting avatars).
  623. /// </summary>
  624. /// <remarks>
  625. /// If there are any ScenePresence's in the linkset (i.e. because they are sat upon one of the prims), then
  626. /// these are counted as extra entities that correspond to linknums beyond the number of prims in the linkset.
  627. /// The ScenePresences receive linknums in the order in which they sat.
  628. /// </remarks>
  629. /// <returns>
  630. /// The link entity. null if not found.
  631. /// </returns>
  632. /// <param name='part'></param>
  633. /// <param name='linknum'>
  634. /// Can be either a non-negative integer or ScriptBaseClass.LINK_THIS (-4).
  635. /// If ScriptBaseClass.LINK_THIS then the entity containing the script is returned.
  636. /// If the linkset has one entity and a linknum of zero is given, then the single entity is returned. If any
  637. /// positive integer is given in this case then null is returned.
  638. /// If the linkset has more than one entity and a linknum greater than zero but equal to or less than the number
  639. /// of entities, then the entity which corresponds to that linknum is returned.
  640. /// Otherwise, if a positive linknum is given which is greater than the number of entities in the linkset, then
  641. /// null is returned.
  642. /// </param>
  643. public static ISceneEntity GetLinkEntity(SceneObjectPart part, int linknum)
  644. {
  645. if (linknum == ScriptBaseClass.LINK_THIS)
  646. return part;
  647. if (linknum <= part.ParentGroup.PrimCount)
  648. return part.ParentGroup.GetLinkNumPart(linknum);
  649. return part.ParentGroup.GetLinkSitingAvatar(linknum);
  650. }
  651. public List<SceneObjectPart> GetLinkParts(int linkType)
  652. {
  653. return GetLinkParts(m_host, linkType);
  654. }
  655. public static List<SceneObjectPart> GetLinkParts(SceneObjectPart part, int linkType)
  656. {
  657. if (part is null || part.ParentGroup is null || part.ParentGroup.IsDeleted)
  658. return new List<SceneObjectPart>();
  659. List<SceneObjectPart> ret;
  660. switch (linkType)
  661. {
  662. case ScriptBaseClass.LINK_SET:
  663. return new List<SceneObjectPart>(part.ParentGroup.Parts);
  664. case ScriptBaseClass.LINK_ROOT:
  665. return new List<SceneObjectPart> { part.ParentGroup.RootPart };
  666. case ScriptBaseClass.LINK_ALL_OTHERS:
  667. ret = new List<SceneObjectPart>(part.ParentGroup.Parts);
  668. ret.Remove(part);
  669. return ret;
  670. case ScriptBaseClass.LINK_ALL_CHILDREN:
  671. ret = new List<SceneObjectPart>(part.ParentGroup.Parts);
  672. ret.Remove(part.ParentGroup.RootPart);
  673. return ret;
  674. case ScriptBaseClass.LINK_THIS:
  675. return new List<SceneObjectPart> { part };
  676. default:
  677. SceneObjectPart target = part.ParentGroup.GetLinkNumPart(linkType);
  678. if (target is not null)
  679. return new List<SceneObjectPart> { target };
  680. return new List<SceneObjectPart>();
  681. }
  682. }
  683. public List<ISceneEntity> GetLinkEntities(int linkType)
  684. {
  685. return GetLinkEntities(m_host, linkType);
  686. }
  687. public static List<ISceneEntity> GetLinkEntities(SceneObjectPart part, int linkType)
  688. {
  689. List<ISceneEntity> ret;
  690. switch (linkType)
  691. {
  692. case ScriptBaseClass.LINK_SET:
  693. return new List<ISceneEntity>(part.ParentGroup.Parts);
  694. case ScriptBaseClass.LINK_ROOT:
  695. return new List<ISceneEntity>() { part.ParentGroup.RootPart };
  696. case ScriptBaseClass.LINK_ALL_OTHERS:
  697. ret = new List<ISceneEntity>(part.ParentGroup.Parts);
  698. ret.Remove(part);
  699. return ret;
  700. case ScriptBaseClass.LINK_ALL_CHILDREN:
  701. ret = new List<ISceneEntity>(part.ParentGroup.Parts);
  702. ret.Remove(part.ParentGroup.RootPart);
  703. List<ScenePresence> avs = part.ParentGroup.GetSittingAvatars();
  704. if(avs is not null && avs.Count > 0)
  705. ret.AddRange(avs);
  706. return ret;
  707. case ScriptBaseClass.LINK_THIS:
  708. return new List<ISceneEntity>() { part };
  709. default:
  710. if (linkType < 0)
  711. return new List<ISceneEntity>();
  712. ISceneEntity target = GetLinkEntity(part, linkType);
  713. if (target is null)
  714. return new List<ISceneEntity>();
  715. return new List<ISceneEntity>() { target };
  716. }
  717. }
  718. //These are the implementations of the various ll-functions used by the LSL scripts.
  719. public LSL_Float llSin(double f)
  720. {
  721. return Math.Sin(f);
  722. }
  723. public LSL_Float llCos(double f)
  724. {
  725. return Math.Cos(f);
  726. }
  727. public LSL_Float llTan(double f)
  728. {
  729. return Math.Tan(f);
  730. }
  731. public LSL_Float llAtan2(LSL_Float y, LSL_Float x)
  732. {
  733. return Math.Atan2(y, x);
  734. }
  735. public LSL_Float llSqrt(double f)
  736. {
  737. return Math.Sqrt(f);
  738. }
  739. public LSL_Float llPow(double fbase, double fexponent)
  740. {
  741. return (double)Math.Pow(fbase, fexponent);
  742. }
  743. public LSL_Integer llAbs(LSL_Integer i)
  744. {
  745. // changed to replicate LSL behaviour whereby minimum int value is returned untouched.
  746. if (i == Int32.MinValue)
  747. return i;
  748. else
  749. return Math.Abs(i);
  750. }
  751. public LSL_Float llFabs(double f)
  752. {
  753. return (double)Math.Abs(f);
  754. }
  755. public LSL_Float llFrand(double mag)
  756. {
  757. return Random.Shared.NextDouble() * mag;
  758. }
  759. public LSL_Integer llFloor(double f)
  760. {
  761. return (int)Math.Floor(f);
  762. }
  763. public LSL_Integer llCeil(double f)
  764. {
  765. return (int)Math.Ceiling(f);
  766. }
  767. // Xantor 01/May/2008 fixed midpointrounding (2.5 becomes 3.0 instead of 2.0, default = ToEven)
  768. public LSL_Integer llRound(double f)
  769. {
  770. return (int)Math.Round(f, MidpointRounding.AwayFromZero);
  771. }
  772. //This next group are vector operations involving squaring and square root. ckrinke
  773. public LSL_Float llVecMag(LSL_Vector v)
  774. {
  775. return LSL_Vector.Mag(v);
  776. }
  777. public LSL_Vector llVecNorm(LSL_Vector v)
  778. {
  779. return LSL_Vector.Norm(v);
  780. }
  781. private static double VecDist(LSL_Vector a, LSL_Vector b)
  782. {
  783. double dx = a.x - b.x;
  784. double dy = a.y - b.y;
  785. double dz = a.z - b.z;
  786. return Math.Sqrt(dx * dx + dy * dy + dz * dz);
  787. }
  788. private static double VecDistSquare(LSL_Vector a, LSL_Vector b)
  789. {
  790. double dx = a.x - b.x;
  791. double dy = a.y - b.y;
  792. double dz = a.z - b.z;
  793. return dx * dx + dy * dy + dz * dz;
  794. }
  795. public LSL_Float llVecDist(LSL_Vector a, LSL_Vector b)
  796. {
  797. return VecDist(a, b);
  798. }
  799. public LSL_Vector llRot2Euler(LSL_Rotation q1)
  800. {
  801. double sqw = q1.s * q1.s;
  802. double sqx = q1.x * q1.x;
  803. double sqy = q1.z * q1.z;
  804. double sqz = q1.y * q1.y;
  805. double norm = sqx + sqy + sqz + sqw; // if normalised is one, otherwise is correction factor
  806. double halfnorm = 0.49999 * norm;
  807. double test = q1.x * q1.z + q1.y * q1.s;
  808. if (test > halfnorm) // singularity at north pole
  809. {
  810. return new LSL_Vector(
  811. 0,
  812. Math.PI / 2,
  813. 2 * Math.Atan2(q1.x, q1.s)
  814. );
  815. }
  816. if (test < -halfnorm) // singularity at south pole
  817. {
  818. return new LSL_Vector(
  819. 0,
  820. -Math.PI / 2,
  821. -2 * Math.Atan2(q1.x, q1.s)
  822. );
  823. }
  824. return new LSL_Vector(
  825. Math.Atan2(2 * q1.x * q1.s - 2 * q1.z * q1.y , -sqx + sqy - sqz + sqw),
  826. Math.Asin( 2 * test / norm),
  827. Math.Atan2(2 * q1.z * q1.s - 2 * q1.x * q1.y, sqx - sqy - sqz + sqw)
  828. );
  829. }
  830. public LSL_Rotation llEuler2Rot(LSL_Vector v)
  831. {
  832. double a = v.x * 0.5;
  833. double s1 = Math.Sin(a);
  834. double c1 = Math.Cos(a);
  835. a = v.y * 0.5;
  836. double s2 = Math.Sin(a);
  837. double c2 = Math.Cos(a);
  838. a = v.z * 0.5;
  839. double s3 = Math.Sin(a);
  840. double c3 = Math.Cos(a);
  841. return new LSL_Rotation(
  842. s1 * c2 * c3 + c1 * s2 * s3,
  843. c1 * s2 * c3 - s1 * c2 * s3,
  844. s1 * s2 * c3 + c1 * c2 * s3,
  845. c1 * c2 * c3 - s1 * s2 * s3
  846. );
  847. }
  848. public LSL_Rotation llAxes2Rot(LSL_Vector fwd, LSL_Vector left, LSL_Vector up)
  849. {
  850. double s;
  851. double tr = fwd.x + left.y + up.z + 1.0;
  852. if (tr >= 1.0)
  853. {
  854. s = 0.5 / Math.Sqrt(tr);
  855. return new LSL_Rotation(
  856. (left.z - up.y) * s,
  857. (up.x - fwd.z) * s,
  858. (fwd.y - left.x) * s,
  859. 0.25 / s);
  860. }
  861. else
  862. {
  863. double max = (left.y > up.z) ? left.y : up.z;
  864. if (max < fwd.x)
  865. {
  866. s = Math.Sqrt(fwd.x - (left.y + up.z) + 1.0);
  867. double x = s * 0.5;
  868. s = 0.5 / s;
  869. return new LSL_Rotation(
  870. x,
  871. (fwd.y + left.x) * s,
  872. (up.x + fwd.z) * s,
  873. (left.z - up.y) * s);
  874. }
  875. else if (max == left.y)
  876. {
  877. s = Math.Sqrt(left.y - (up.z + fwd.x) + 1.0);
  878. double y = s * 0.5;
  879. s = 0.5 / s;
  880. return new LSL_Rotation(
  881. (fwd.y + left.x) * s,
  882. y,
  883. (left.z + up.y) * s,
  884. (up.x - fwd.z) * s);
  885. }
  886. else
  887. {
  888. s = Math.Sqrt(up.z - (fwd.x + left.y) + 1.0);
  889. double z = s * 0.5;
  890. s = 0.5 / s;
  891. return new LSL_Rotation(
  892. (up.x + fwd.z) * s,
  893. (left.z + up.y) * s,
  894. z,
  895. (fwd.y - left.x) * s);
  896. }
  897. }
  898. }
  899. public LSL_Vector llRot2Fwd(LSL_Rotation r)
  900. {
  901. double m = r.x * r.x + r.y * r.y + r.z * r.z + r.s * r.s;
  902. if (Math.Abs(1.0 - m) > 0.000001)
  903. {
  904. m = 1.0 / Math.Sqrt(m);
  905. r.x *= m;
  906. r.y *= m;
  907. r.z *= m;
  908. r.s *= m;
  909. }
  910. return new LSL_Vector(
  911. r.x * r.x - r.y * r.y - r.z * r.z + r.s * r.s,
  912. 2 * (r.x * r.y + r.z * r.s),
  913. 2 * (r.x * r.z - r.y * r.s)
  914. );
  915. }
  916. public LSL_Vector llRot2Left(LSL_Rotation r)
  917. {
  918. double m = r.x * r.x + r.y * r.y + r.z * r.z + r.s * r.s;
  919. if (Math.Abs(1.0 - m) > 0.000001) // allow a little slop here for calculation precision
  920. {
  921. m = 1.0 / Math.Sqrt(m);
  922. r.x *= m;
  923. r.y *= m;
  924. r.z *= m;
  925. r.s *= m;
  926. }
  927. return new LSL_Vector(
  928. 2 * (r.x * r.y - r.z * r.s),
  929. -r.x * r.x + r.y * r.y - r.z * r.z + r.s * r.s,
  930. 2 * (r.x * r.s + r.y * r.z)
  931. );
  932. }
  933. public LSL_Vector llRot2Up(LSL_Rotation r)
  934. {
  935. double m = r.x * r.x + r.y * r.y + r.z * r.z + r.s * r.s;
  936. if (Math.Abs(1.0 - m) > 0.000001) // allow a little slop here for calculation precision
  937. {
  938. m = 1.0 / Math.Sqrt(m);
  939. r.x *= m;
  940. r.y *= m;
  941. r.z *= m;
  942. r.s *= m;
  943. }
  944. return new LSL_Vector(
  945. 2 * (r.x * r.z + r.y * r.s),
  946. 2 * (-r.x * r.s + r.y * r.z),
  947. -r.x * r.x - r.y * r.y + r.z * r.z + r.s * r.s
  948. );
  949. }
  950. public LSL_Rotation llRotBetween(LSL_Vector a, LSL_Vector b)
  951. {
  952. //A and B should both be normalized
  953. // This method mimics the 180 errors found in SL
  954. // See www.euclideanspace.com... angleBetween
  955. // Eliminate zero length
  956. LSL_Float vec_a_mag = LSL_Vector.MagSquare(a);
  957. LSL_Float vec_b_mag = LSL_Vector.MagSquare(b);
  958. if (vec_a_mag < 1e-12 ||
  959. vec_b_mag < 1e-12)
  960. {
  961. return new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f);
  962. }
  963. // Normalize
  964. a = llVecNorm(a);
  965. b = llVecNorm(b);
  966. // Calculate axis and rotation angle
  967. LSL_Vector axis = a % b;
  968. LSL_Float cos_theta = a * b;
  969. // Check if parallel
  970. if (cos_theta > 0.99999)
  971. {
  972. return new LSL_Rotation(0.0f, 0.0f, 0.0f, 1.0f);
  973. }
  974. // Check if anti-parallel
  975. else if (cos_theta < -0.99999)
  976. {
  977. LSL_Vector orthog_axis = new LSL_Vector(1.0, 0.0, 0.0) - (a.x / (a * a) * a);
  978. if (LSL_Vector.MagSquare(orthog_axis) < 1e-12)
  979. orthog_axis = new LSL_Vector(0.0, 0.0, 1.0);
  980. return new LSL_Rotation((float)orthog_axis.x, (float)orthog_axis.y, (float)orthog_axis.z, 0.0);
  981. }
  982. else // other rotation
  983. {
  984. LSL_Float theta = (LSL_Float)Math.Acos(cos_theta) * 0.5f;
  985. axis = llVecNorm(axis);
  986. double x, y, z, s, t;
  987. s = Math.Cos(theta);
  988. t = Math.Sin(theta);
  989. x = axis.x * t;
  990. y = axis.y * t;
  991. z = axis.z * t;
  992. return new LSL_Rotation(x,y,z,s);
  993. }
  994. }
  995. public void llWhisper(int channelID, string text)
  996. {
  997. byte[] binText = Utils.StringToBytesNoTerm(text, 1023);
  998. World.SimChat(binText,
  999. ChatTypeEnum.Whisper, channelID, m_host.AbsolutePosition, m_host.Name, m_host.UUID, false);
  1000. IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
  1001. wComm?.DeliverMessage(ChatTypeEnum.Whisper, channelID, m_host.Name, m_host.UUID, Util.UTF8.GetString(binText), m_host.AbsolutePosition);
  1002. }
  1003. private void CheckSayShoutTime()
  1004. {
  1005. DateTime now = DateTime.UtcNow;
  1006. if ((now - m_lastSayShoutCheck).Ticks > 10000000) // 1sec
  1007. {
  1008. m_lastSayShoutCheck = now;
  1009. m_SayShoutCount = 0;
  1010. }
  1011. else
  1012. m_SayShoutCount++;
  1013. }
  1014. public void ThrottleSay(int channelID, int timeMs)
  1015. {
  1016. if (channelID == 0)
  1017. CheckSayShoutTime();
  1018. if (m_SayShoutCount >= 11)
  1019. ScriptSleep(timeMs);
  1020. }
  1021. public void llSay(int channelID, string text)
  1022. {
  1023. if (channelID == 0)
  1024. // m_SayShoutCount++;
  1025. CheckSayShoutTime();
  1026. if (m_SayShoutCount >= 11)
  1027. ScriptSleep(2000);
  1028. if (m_scriptConsoleChannelEnabled && (channelID == m_scriptConsoleChannel))
  1029. {
  1030. Console.WriteLine(text);
  1031. }
  1032. else
  1033. {
  1034. byte[] binText = Utils.StringToBytesNoTerm(text, 1023);
  1035. World.SimChat(binText,
  1036. ChatTypeEnum.Say, channelID, m_host.AbsolutePosition, m_host.Name, m_host.UUID, false);
  1037. IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
  1038. wComm?.DeliverMessage(ChatTypeEnum.Say, channelID, m_host.Name, m_host.UUID, Util.UTF8.GetString(binText), m_host.AbsolutePosition);
  1039. }
  1040. }
  1041. public void llShout(int channelID, string text)
  1042. {
  1043. if (channelID == 0)
  1044. // m_SayShoutCount++;
  1045. CheckSayShoutTime();
  1046. if (m_SayShoutCount >= 11)
  1047. ScriptSleep(2000);
  1048. byte[] binText = Utils.StringToBytesNoTerm(text, 1023);
  1049. World.SimChat(binText,
  1050. ChatTypeEnum.Shout, channelID, m_host.AbsolutePosition, m_host.Name, m_host.UUID, true);
  1051. IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
  1052. wComm?.DeliverMessage(ChatTypeEnum.Shout, channelID, m_host.Name, m_host.UUID, Util.UTF8.GetString(binText), m_host.AbsolutePosition);
  1053. }
  1054. public void llRegionSay(int channelID, string text)
  1055. {
  1056. if (channelID == 0)
  1057. {
  1058. Error("llRegionSay", "Cannot use on channel 0");
  1059. return;
  1060. }
  1061. byte[] binText = Utils.StringToBytesNoTerm(text, 1023);
  1062. // debug channel is also sent to avatars
  1063. if (channelID == ScriptBaseClass.DEBUG_CHANNEL)
  1064. {
  1065. World.SimChat(binText,
  1066. ChatTypeEnum.Shout, channelID, m_host.ParentGroup.RootPart.AbsolutePosition, m_host.Name, m_host.UUID, true);
  1067. }
  1068. IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
  1069. wComm?.DeliverMessage(ChatTypeEnum.Region, channelID, m_host.Name, m_host.UUID, Util.UTF8.GetString(binText));
  1070. }
  1071. public void llRegionSayTo(string target, int channel, string msg)
  1072. {
  1073. if (channel == ScriptBaseClass.DEBUG_CHANNEL)
  1074. return;
  1075. if(UUID.TryParse(target, out UUID TargetID) && TargetID.IsNotZero())
  1076. {
  1077. IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
  1078. if (wComm != null)
  1079. {
  1080. if (msg.Length > 1023)
  1081. msg = msg[..1023];
  1082. wComm.DeliverMessageTo(TargetID, channel, m_host.AbsolutePosition, m_host.Name, m_host.UUID, msg);
  1083. }
  1084. }
  1085. }
  1086. public LSL_Integer llListen(int channelID, string name, string ID, string msg)
  1087. {
  1088. IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
  1089. if (wComm is not null)
  1090. {
  1091. _ = UUID.TryParse(ID, out UUID keyID);
  1092. return wComm.Listen(m_item.ItemID, m_host.UUID, channelID, name, keyID, msg);
  1093. }
  1094. return -1;
  1095. }
  1096. public void llListenControl(int number, int active)
  1097. {
  1098. IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
  1099. wComm?.ListenControl(m_item.ItemID, number, active);
  1100. }
  1101. public void llListenRemove(int number)
  1102. {
  1103. IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
  1104. wComm?.ListenRemove(m_item.ItemID, number);
  1105. }
  1106. public void llSensor(string name, string id, int type, double range, double arc)
  1107. {
  1108. _ = UUID.TryParse(id, out UUID keyID);
  1109. m_AsyncCommands.SensorRepeatPlugin.SenseOnce(m_host.LocalId, m_item.ItemID, name, keyID, type, range, arc, m_host);
  1110. }
  1111. public void llSensorRepeat(string name, string id, int type, double range, double arc, double rate)
  1112. {
  1113. _ = UUID.TryParse(id, out UUID keyID);
  1114. m_AsyncCommands.SensorRepeatPlugin.SetSenseRepeatEvent(m_host.LocalId, m_item.ItemID, name, keyID, type, range, arc, rate, m_host);
  1115. }
  1116. public void llSensorRemove()
  1117. {
  1118. m_AsyncCommands.SensorRepeatPlugin.UnSetSenseRepeaterEvents(m_host.LocalId, m_item.ItemID);
  1119. }
  1120. public string resolveName(UUID objecUUID)
  1121. {
  1122. // try avatar username surname
  1123. UserAccount account = m_userAccountService.GetUserAccount(RegionScopeID, objecUUID);
  1124. if (account is not null)
  1125. {
  1126. string avatarname = account.Name;
  1127. return avatarname;
  1128. }
  1129. // try an scene object
  1130. SceneObjectPart SOP = World.GetSceneObjectPart(objecUUID);
  1131. if (SOP is not null)
  1132. {
  1133. string objectname = SOP.Name;
  1134. return objectname;
  1135. }
  1136. World.Entities.TryGetValue(objecUUID, out EntityBase SensedObject);
  1137. if (SensedObject is null)
  1138. {
  1139. IGroupsModule groups = World.RequestModuleInterface<IGroupsModule>();
  1140. if (groups is not null)
  1141. {
  1142. GroupRecord gr = groups.GetGroupRecord(objecUUID);
  1143. if (gr is not null)
  1144. return gr.GroupName;
  1145. }
  1146. return String.Empty;
  1147. }
  1148. return SensedObject.Name;
  1149. }
  1150. public LSL_String llDetectedName(int number)
  1151. {
  1152. DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
  1153. return detectedParams is null ? LSL_String.Empty : detectedParams.Name;
  1154. }
  1155. public LSL_Key llDetectedKey(int number)
  1156. {
  1157. DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
  1158. return detectedParams is null ? LSL_String.Empty : detectedParams.Key.ToString();
  1159. }
  1160. public LSL_Key llDetectedOwner(int number)
  1161. {
  1162. DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
  1163. return detectedParams is null ? LSL_String.Empty : detectedParams.Owner.ToString();
  1164. }
  1165. public LSL_Integer llDetectedType(int number)
  1166. {
  1167. DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
  1168. return detectedParams is null ? 0 : new LSL_Integer(detectedParams.Type);
  1169. }
  1170. public LSL_Vector llDetectedPos(int number)
  1171. {
  1172. DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
  1173. return detectedParams is null ? new LSL_Vector() : detectedParams.Position;
  1174. }
  1175. public LSL_Vector llDetectedVel(int number)
  1176. {
  1177. DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
  1178. return detectedParams == null ? new LSL_Vector() : detectedParams.Velocity;
  1179. }
  1180. public LSL_Vector llDetectedGrab(int number)
  1181. {
  1182. DetectParams parms = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
  1183. return parms is null ? new LSL_Vector() : parms.OffsetPos;
  1184. }
  1185. public LSL_Rotation llDetectedRot(int number)
  1186. {
  1187. DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
  1188. return detectedParams is null ? new LSL_Rotation() : detectedParams.Rotation;
  1189. }
  1190. public LSL_Integer llDetectedGroup(int number)
  1191. {
  1192. DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
  1193. if (detectedParams is null)
  1194. return new LSL_Integer(0);
  1195. if (m_host.GroupID.Equals(detectedParams.Group))
  1196. return new LSL_Integer(1);
  1197. return new LSL_Integer(0);
  1198. }
  1199. public LSL_Integer llDetectedLinkNumber(int number)
  1200. {
  1201. DetectParams parms = m_ScriptEngine.GetDetectParams(m_item.ItemID, number);
  1202. return parms is null ? new LSL_Integer() : new LSL_Integer(parms.LinkNum);
  1203. }
  1204. /// <summary>
  1205. /// See http://wiki.secondlife.com/wiki/LlDetectedTouchBinormal for details
  1206. /// </summary>
  1207. public LSL_Vector llDetectedTouchBinormal(int index)
  1208. {
  1209. DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, index);
  1210. return detectedParams is null ? new LSL_Vector() : detectedParams.TouchBinormal;
  1211. }
  1212. /// <summary>
  1213. /// See http://wiki.secondlife.com/wiki/LlDetectedTouchFace for details
  1214. /// </summary>
  1215. public LSL_Integer llDetectedTouchFace(int index)
  1216. {
  1217. DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, index);
  1218. return detectedParams is null ? new LSL_Integer(-1) : new LSL_Integer(detectedParams.TouchFace);
  1219. }
  1220. /// <summary>
  1221. /// See http://wiki.secondlife.com/wiki/LlDetectedTouchNormal for details
  1222. /// </summary>
  1223. public LSL_Vector llDetectedTouchNormal(int index)
  1224. {
  1225. DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, index);
  1226. return detectedParams is null ? new LSL_Vector() : detectedParams.TouchNormal;
  1227. }
  1228. /// <summary>
  1229. /// See http://wiki.secondlife.com/wiki/LlDetectedTouchPos for details
  1230. /// </summary>
  1231. public LSL_Vector llDetectedTouchPos(int index)
  1232. {
  1233. DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, index);
  1234. return detectedParams is null ? new LSL_Vector() : detectedParams.TouchPos;
  1235. }
  1236. /// <summary>
  1237. /// See http://wiki.secondlife.com/wiki/LlDetectedTouchST for details
  1238. /// </summary>
  1239. public LSL_Vector llDetectedTouchST(int index)
  1240. {
  1241. DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, index);
  1242. return detectedParams is null ? new LSL_Vector(-1.0, -1.0, 0.0) : detectedParams.TouchST;
  1243. }
  1244. /// <summary>
  1245. /// See http://wiki.secondlife.com/wiki/LlDetectedTouchUV for details
  1246. /// </summary>
  1247. public LSL_Vector llDetectedTouchUV(int index)
  1248. {
  1249. DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, index);
  1250. return detectedParams is null ? new LSL_Vector(-1.0, -1.0, 0.0) : detectedParams.TouchUV;
  1251. }
  1252. [DebuggerNonUserCode]
  1253. public virtual void llDie()
  1254. {
  1255. if (!m_host.ParentGroup.IsAttachment) throw new SelfDeleteException();
  1256. }
  1257. public LSL_Float llGround(LSL_Vector offset)
  1258. {
  1259. Vector3 pos = m_host.GetWorldPosition();
  1260. pos.X += (float)offset.x;
  1261. pos.Y += (float)offset.y;
  1262. return World.GetGroundHeight(pos.X, pos.Y);
  1263. }
  1264. public LSL_Float llCloud(LSL_Vector offset)
  1265. {
  1266. return 0;
  1267. }
  1268. public LSL_Vector llWind(LSL_Vector offset)
  1269. {
  1270. LSL_Vector wind = new();
  1271. IWindModule module = World.RequestModuleInterface<IWindModule>();
  1272. if (module is not null)
  1273. {
  1274. Vector3 pos = m_host.GetWorldPosition();
  1275. int x = (int)(pos.X + offset.x);
  1276. int y = (int)(pos.Y + offset.y);
  1277. Vector3 windSpeed = module.WindSpeed(x, y, 0);
  1278. wind.x = windSpeed.X;
  1279. wind.y = windSpeed.Y;
  1280. }
  1281. return wind;
  1282. }
  1283. public void llSetStatus(int status, int value)
  1284. {
  1285. if (m_host is null || m_host.ParentGroup is null || m_host.ParentGroup.IsDeleted)
  1286. return;
  1287. if ((status & ScriptBaseClass.STATUS_CAST_SHADOWS) != 0)
  1288. m_host.AddFlag(PrimFlags.CastShadows);
  1289. if ((status & ScriptBaseClass.STATUS_BLOCK_GRAB) != 0)
  1290. m_host.BlockGrab = value != 0;
  1291. if ((status & ScriptBaseClass.STATUS_BLOCK_GRAB_OBJECT) != 0)
  1292. m_host.ParentGroup.BlockGrabOverride = value != 0;
  1293. if ((status & ScriptBaseClass.STATUS_DIE_AT_EDGE) != 0)
  1294. m_host.SetDieAtEdge(value != 0);
  1295. if ((status & ScriptBaseClass.STATUS_RETURN_AT_EDGE) != 0)
  1296. m_host.SetReturnAtEdge(value != 0);
  1297. if ((status & ScriptBaseClass.STATUS_SANDBOX) != 0)
  1298. m_host.SetStatusSandbox(value != 0);
  1299. int statusrotationaxis = status & (ScriptBaseClass.STATUS_ROTATE_X | ScriptBaseClass.STATUS_ROTATE_Y | ScriptBaseClass.STATUS_ROTATE_Z);
  1300. if (statusrotationaxis != 0)
  1301. m_host.ParentGroup.SetAxisRotation(statusrotationaxis, value);
  1302. if ((status & ScriptBaseClass.STATUS_PHANTOM) != 0)
  1303. m_host.ParentGroup.ScriptSetPhantomStatus(value != 0);
  1304. if ((status & ScriptBaseClass.STATUS_PHYSICS) != 0)
  1305. {
  1306. if (value != 0)
  1307. {
  1308. SceneObjectGroup group = m_host.ParentGroup;
  1309. if (group.RootPart.PhysActor is null || !group.RootPart.PhysActor.IsPhysical)
  1310. {
  1311. bool allow = true;
  1312. int maxprims = World.m_linksetPhysCapacity;
  1313. bool checkShape = (maxprims > 0 && group.PrimCount > maxprims);
  1314. foreach (SceneObjectPart part in group.Parts)
  1315. {
  1316. if (part.PhysicsShapeType == (byte)PhysicsShapeType.None)
  1317. continue;
  1318. if (checkShape)
  1319. {
  1320. if (--maxprims < 0)
  1321. {
  1322. allow = false;
  1323. break;
  1324. }
  1325. }
  1326. if (part.Scale.X > World.m_maxPhys || part.Scale.Y > World.m_maxPhys || part.Scale.Z > World.m_maxPhys)
  1327. {
  1328. allow = false;
  1329. break;
  1330. }
  1331. }
  1332. if (allow)
  1333. m_host.ScriptSetPhysicsStatus(true);
  1334. }
  1335. }
  1336. else
  1337. {
  1338. m_host.ScriptSetPhysicsStatus(false);
  1339. }
  1340. }
  1341. }
  1342. private bool IsPhysical()
  1343. {
  1344. return ((m_host.GetEffectiveObjectFlags() & (uint)PrimFlags.Physics) != 0);
  1345. }
  1346. public LSL_Integer llGetStatus(int status)
  1347. {
  1348. // m_log.Debug(m_host.ToString() + " status is " + m_host.GetEffectiveObjectFlags().ToString());
  1349. return status switch
  1350. {
  1351. ScriptBaseClass.STATUS_PHYSICS => (LSL_Integer)(IsPhysical() ? 1 : 0),
  1352. ScriptBaseClass.STATUS_PHANTOM => (LSL_Integer)((m_host.GetEffectiveObjectFlags() & (uint)PrimFlags.Phantom) != 0 ? 1 : 0),
  1353. ScriptBaseClass.STATUS_CAST_SHADOWS => (LSL_Integer)((m_host.GetEffectiveObjectFlags() & (uint)PrimFlags.CastShadows) != 0 ? 1 : 0),
  1354. ScriptBaseClass.STATUS_BLOCK_GRAB => (LSL_Integer)(m_host.BlockGrab ? 1 : 0),
  1355. ScriptBaseClass.STATUS_BLOCK_GRAB_OBJECT => (LSL_Integer)(m_host.ParentGroup.BlockGrabOverride ? 1 : 0),
  1356. ScriptBaseClass.STATUS_DIE_AT_EDGE => (LSL_Integer)(m_host.GetDieAtEdge() ? 1 : 0),
  1357. ScriptBaseClass.STATUS_RETURN_AT_EDGE => (LSL_Integer)(m_host.GetReturnAtEdge() ? 1 : 0),
  1358. ScriptBaseClass.STATUS_ROTATE_X => (LSL_Integer)(m_host.GetAxisRotation((int)SceneObjectGroup.axisSelect.STATUS_ROTATE_X) != 0 ? 1 : 0),
  1359. ScriptBaseClass.STATUS_ROTATE_Y => (LSL_Integer)(m_host.GetAxisRotation((int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Y) != 0 ? 1 : 0),
  1360. ScriptBaseClass.STATUS_ROTATE_Z => (LSL_Integer)(m_host.GetAxisRotation((int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Z) != 0 ? 1 : 0),
  1361. ScriptBaseClass.STATUS_SANDBOX => (LSL_Integer)(m_host.GetStatusSandbox() ? 1 : 0),
  1362. _ => (LSL_Integer)0,
  1363. };
  1364. }
  1365. public LSL_Integer llScaleByFactor(double scaling_factor)
  1366. {
  1367. SceneObjectGroup group = m_host.ParentGroup;
  1368. if(scaling_factor < 1e-6)
  1369. return ScriptBaseClass.FALSE;
  1370. if(scaling_factor > 1e6)
  1371. return ScriptBaseClass.FALSE;
  1372. if (group is null || group.IsDeleted || group.inTransit)
  1373. return ScriptBaseClass.FALSE;
  1374. if (group.RootPart.PhysActor is not null && group.RootPart.PhysActor.IsPhysical)
  1375. return ScriptBaseClass.FALSE;
  1376. if (group.RootPart.KeyframeMotion is not null)
  1377. return ScriptBaseClass.FALSE;
  1378. return group.GroupResize(scaling_factor) ? 1 : 0;
  1379. }
  1380. public LSL_Float llGetMaxScaleFactor()
  1381. {
  1382. SceneObjectGroup group = m_host.ParentGroup;
  1383. if (group is null || group.IsDeleted || group.inTransit)
  1384. return 1.0f;
  1385. return (LSL_Float)group.GetMaxGroupResizeScale();
  1386. }
  1387. public LSL_Float llGetMinScaleFactor()
  1388. {
  1389. SceneObjectGroup group = m_host.ParentGroup;
  1390. if (group is null || group.IsDeleted || group.inTransit)
  1391. return 1.0f;
  1392. return (LSL_Float)group.GetMinGroupResizeScale();
  1393. }
  1394. public void llSetScale(LSL_Vector scale)
  1395. {
  1396. SetScale(m_host, scale);
  1397. }
  1398. protected void SetScale(SceneObjectPart part, LSL_Vector scale)
  1399. {
  1400. // TODO: this needs to trigger a persistance save as well
  1401. if (part is null || part.ParentGroup.IsDeleted)
  1402. return;
  1403. // First we need to check whether or not we need to clamp the size of a physics-enabled prim
  1404. PhysicsActor pa = part.ParentGroup.RootPart.PhysActor;
  1405. if (pa != null && pa.IsPhysical)
  1406. {
  1407. scale.x = Math.Max(World.m_minPhys, Math.Min(World.m_maxPhys, scale.x));
  1408. scale.y = Math.Max(World.m_minPhys, Math.Min(World.m_maxPhys, scale.y));
  1409. scale.z = Math.Max(World.m_minPhys, Math.Min(World.m_maxPhys, scale.z));
  1410. }
  1411. else
  1412. {
  1413. // If not physical, then we clamp the scale to the non-physical min/max
  1414. scale.x = Math.Max(World.m_minNonphys, Math.Min(World.m_maxNonphys, scale.x));
  1415. scale.y = Math.Max(World.m_minNonphys, Math.Min(World.m_maxNonphys, scale.y));
  1416. scale.z = Math.Max(World.m_minNonphys, Math.Min(World.m_maxNonphys, scale.z));
  1417. }
  1418. Vector3 tmp = part.Scale;
  1419. tmp.X = (float)scale.x;
  1420. tmp.Y = (float)scale.y;
  1421. tmp.Z = (float)scale.z;
  1422. part.Scale = tmp;
  1423. part.ParentGroup.HasGroupChanged = true;
  1424. part.SendFullUpdateToAllClients();
  1425. }
  1426. public LSL_Vector llGetScale()
  1427. {
  1428. return new LSL_Vector(m_host.Scale.X, m_host.Scale.Y, m_host.Scale.Z);
  1429. }
  1430. public void llSetClickAction(int action)
  1431. {
  1432. m_host.ClickAction = (byte)action;
  1433. m_host.ParentGroup.HasGroupChanged = true;
  1434. m_host.ScheduleFullUpdate();
  1435. return;
  1436. }
  1437. public void llSetColor(LSL_Vector color, int face)
  1438. {
  1439. SetColor(m_host, color, face);
  1440. }
  1441. protected void SetColor(SceneObjectPart part, LSL_Vector color, int face)
  1442. {
  1443. if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
  1444. return;
  1445. m_host.SetFaceColorAlpha(face, color, null);
  1446. }
  1447. public void llSetContentType(LSL_Key reqid, LSL_Integer type)
  1448. {
  1449. if (m_UrlModule == null)
  1450. return;
  1451. if(!UUID.TryParse(reqid, out UUID id) || id.IsZero())
  1452. return;
  1453. // Make sure the content type is text/plain to start with
  1454. m_UrlModule.HttpContentType(id, "text/plain");
  1455. // Is the object owner online and in the region
  1456. ScenePresence agent = World.GetScenePresence(m_host.ParentGroup.OwnerID);
  1457. if (agent == null || agent.IsChildAgent || agent.IsDeleted)
  1458. return; // Fail if the owner is not in the same region
  1459. // Is it the embeded browser?
  1460. string userAgent = m_UrlModule.GetHttpHeader(id, "user-agent");
  1461. if(string.IsNullOrEmpty(userAgent))
  1462. return;
  1463. if (userAgent.IndexOf("SecondLife") < 0)
  1464. return; // Not the embedded browser
  1465. // Use the IP address of the client and check against the request
  1466. // seperate logins from the same IP will allow all of them to get non-text/plain as long
  1467. // as the owner is in the region. Same as SL!
  1468. string logonFromIPAddress = agent.ControllingClient.RemoteEndPoint.Address.ToString();
  1469. if (string.IsNullOrEmpty(logonFromIPAddress))
  1470. return;
  1471. string requestFromIPAddress = m_UrlModule.GetHttpHeader(id, "x-remote-ip");
  1472. //m_log.Debug("IP from header='" + requestFromIPAddress + "' IP from endpoint='" + logonFromIPAddress + "'");
  1473. if (requestFromIPAddress == null)
  1474. return;
  1475. requestFromIPAddress = requestFromIPAddress.Trim();
  1476. // If the request isnt from the same IP address then the request cannot be from the owner
  1477. if (!requestFromIPAddress.Equals(logonFromIPAddress))
  1478. return;
  1479. switch (type)
  1480. {
  1481. case ScriptBaseClass.CONTENT_TYPE_HTML:
  1482. m_UrlModule.HttpContentType(id, "text/html");
  1483. break;
  1484. case ScriptBaseClass.CONTENT_TYPE_XML:
  1485. m_UrlModule.HttpContentType(id, "application/xml");
  1486. break;
  1487. case ScriptBaseClass.CONTENT_TYPE_XHTML:
  1488. m_UrlModule.HttpContentType(id, "application/xhtml+xml");
  1489. break;
  1490. case ScriptBaseClass.CONTENT_TYPE_ATOM:
  1491. m_UrlModule.HttpContentType(id, "application/atom+xml");
  1492. break;
  1493. case ScriptBaseClass.CONTENT_TYPE_JSON:
  1494. m_UrlModule.HttpContentType(id, "application/json");
  1495. break;
  1496. case ScriptBaseClass.CONTENT_TYPE_LLSD:
  1497. m_UrlModule.HttpContentType(id, "application/llsd+xml");
  1498. break;
  1499. case ScriptBaseClass.CONTENT_TYPE_FORM:
  1500. m_UrlModule.HttpContentType(id, "application/x-www-form-urlencoded");
  1501. break;
  1502. case ScriptBaseClass.CONTENT_TYPE_RSS:
  1503. m_UrlModule.HttpContentType(id, "application/rss+xml");
  1504. break;
  1505. default:
  1506. m_UrlModule.HttpContentType(id, "text/plain");
  1507. break;
  1508. }
  1509. }
  1510. public static void SetTexGen(SceneObjectPart part, int face,int style)
  1511. {
  1512. if (part is null || part.ParentGroup is null || part.ParentGroup.IsDeleted)
  1513. return;
  1514. Primitive.TextureEntry tex = part.Shape.Textures;
  1515. MappingType textype;
  1516. textype = MappingType.Default;
  1517. if (style == ScriptBaseClass.PRIM_TEXGEN_PLANAR)
  1518. textype = MappingType.Planar;
  1519. int nsides = GetNumberOfSides(part);
  1520. if (face >= 0 && face < nsides)
  1521. {
  1522. tex.CreateFace((uint) face);
  1523. tex.FaceTextures[face].TexMapType = textype;
  1524. part.UpdateTextureEntry(tex);
  1525. return;
  1526. }
  1527. else if (face == ScriptBaseClass.ALL_SIDES)
  1528. {
  1529. for (uint i = 0; i < nsides; i++)
  1530. {
  1531. if (tex.FaceTextures[i] is not null)
  1532. tex.FaceTextures[i].TexMapType = textype;
  1533. }
  1534. tex.DefaultTexture.TexMapType = textype;
  1535. part.UpdateTextureEntry(tex);
  1536. return;
  1537. }
  1538. }
  1539. public static void SetGlow(SceneObjectPart part, int face, float glow)
  1540. {
  1541. if (part is null || part.ParentGroup is null || part.ParentGroup.IsDeleted)
  1542. return;
  1543. Primitive.TextureEntry tex = part.Shape.Textures;
  1544. int nsides = GetNumberOfSides(part);
  1545. if (face >= 0 && face < nsides)
  1546. {
  1547. tex.CreateFace((uint) face);
  1548. tex.FaceTextures[face].Glow = glow;
  1549. part.UpdateTextureEntry(tex);
  1550. return;
  1551. }
  1552. else if (face == ScriptBaseClass.ALL_SIDES)
  1553. {
  1554. for (uint i = 0; i < nsides; i++)
  1555. {
  1556. if (tex.FaceTextures[i] is not null)
  1557. tex.FaceTextures[i].Glow = glow;
  1558. }
  1559. tex.DefaultTexture.Glow = glow;
  1560. part.UpdateTextureEntry(tex);
  1561. return;
  1562. }
  1563. }
  1564. public static void SetShiny(SceneObjectPart part, int face, int shiny, Bumpiness bump)
  1565. {
  1566. if (part is null || part.ParentGroup is null || part.ParentGroup.IsDeleted)
  1567. return;
  1568. var sval = shiny switch
  1569. {
  1570. 0 => Shininess.None,
  1571. 1 => Shininess.Low,
  1572. 2 => Shininess.Medium,
  1573. 3 => Shininess.High,
  1574. _ => Shininess.None,
  1575. };
  1576. int nsides = GetNumberOfSides(part);
  1577. Primitive.TextureEntry tex = part.Shape.Textures;
  1578. if (face >= 0 && face < nsides)
  1579. {
  1580. tex.CreateFace((uint) face);
  1581. tex.FaceTextures[face].Shiny = sval;
  1582. tex.FaceTextures[face].Bump = bump;
  1583. part.UpdateTextureEntry(tex);
  1584. return;
  1585. }
  1586. else if (face == ScriptBaseClass.ALL_SIDES)
  1587. {
  1588. for (uint i = 0; i < nsides; i++)
  1589. {
  1590. if (tex.FaceTextures[i] is not null)
  1591. {
  1592. tex.FaceTextures[i].Shiny = sval;
  1593. tex.FaceTextures[i].Bump = bump;
  1594. }
  1595. }
  1596. tex.DefaultTexture.Shiny = sval;
  1597. tex.DefaultTexture.Bump = bump;
  1598. part.UpdateTextureEntry(tex);
  1599. return;
  1600. }
  1601. }
  1602. public static void SetFullBright(SceneObjectPart part, int face, bool bright)
  1603. {
  1604. if (part is null || part.ParentGroup is null || part.ParentGroup.IsDeleted)
  1605. return;
  1606. int nsides = GetNumberOfSides(part);
  1607. Primitive.TextureEntry tex = part.Shape.Textures;
  1608. if (face >= 0 && face < nsides)
  1609. {
  1610. tex.CreateFace((uint) face);
  1611. tex.FaceTextures[face].Fullbright = bright;
  1612. part.UpdateTextureEntry(tex);
  1613. return;
  1614. }
  1615. else if (face == ScriptBaseClass.ALL_SIDES)
  1616. {
  1617. tex.DefaultTexture.Fullbright = bright;
  1618. for (uint i = 0; i < nsides; i++)
  1619. {
  1620. if(tex.FaceTextures[i] is not null)
  1621. tex.FaceTextures[i].Fullbright = bright;
  1622. }
  1623. part.UpdateTextureEntry(tex);
  1624. return;
  1625. }
  1626. }
  1627. public LSL_Float llGetAlpha(int face)
  1628. {
  1629. return GetAlpha(m_host, face);
  1630. }
  1631. protected static LSL_Float GetAlpha(SceneObjectPart part, int face)
  1632. {
  1633. Primitive.TextureEntry tex = part.Shape.Textures;
  1634. int nsides = GetNumberOfSides(part);
  1635. if (face == ScriptBaseClass.ALL_SIDES)
  1636. {
  1637. int i;
  1638. double sum = 0.0;
  1639. for (i = 0 ; i < nsides; i++)
  1640. sum += tex.GetFace((uint)i).RGBA.A;
  1641. return sum;
  1642. }
  1643. if (face >= 0 && face < nsides)
  1644. {
  1645. return tex.GetFace((uint)face).RGBA.A;
  1646. }
  1647. return 0.0;
  1648. }
  1649. public void llSetAlpha(double alpha, int face)
  1650. {
  1651. SetAlpha(m_host, alpha, face);
  1652. }
  1653. public void llSetLinkAlpha(int linknumber, double alpha, int face)
  1654. {
  1655. List<SceneObjectPart> parts = GetLinkParts(linknumber);
  1656. if (parts.Count > 0)
  1657. {
  1658. try
  1659. {
  1660. foreach (SceneObjectPart part in parts)
  1661. SetAlpha(part, alpha, face);
  1662. }
  1663. finally { }
  1664. }
  1665. }
  1666. protected static void SetAlpha(SceneObjectPart part, double alpha, int face)
  1667. {
  1668. if (part is null || part.ParentGroup is null || part.ParentGroup.IsDeleted)
  1669. return;
  1670. Primitive.TextureEntry tex = part.Shape.Textures;
  1671. int nsides = GetNumberOfSides(part);
  1672. Color4 texcolor;
  1673. if (face >= 0 && face < nsides)
  1674. {
  1675. texcolor = tex.CreateFace((uint)face).RGBA;
  1676. texcolor.A = Utils.Clamp((float)alpha, 0.0f, 1.0f);
  1677. tex.FaceTextures[face].RGBA = texcolor;
  1678. part.UpdateTextureEntry(tex);
  1679. return;
  1680. }
  1681. else if (face == ScriptBaseClass.ALL_SIDES)
  1682. {
  1683. for (int i = 0; i < nsides; i++)
  1684. {
  1685. if (tex.FaceTextures[i] is not null)
  1686. {
  1687. texcolor = tex.FaceTextures[i].RGBA;
  1688. texcolor.A = Utils.Clamp((float)alpha, 0.0f, 1.0f);
  1689. tex.FaceTextures[i].RGBA = texcolor;
  1690. }
  1691. }
  1692. // In some cases, the default texture can be null, eg when every face
  1693. // has a unique texture
  1694. if (tex.DefaultTexture is not null)
  1695. {
  1696. texcolor = tex.DefaultTexture.RGBA;
  1697. texcolor.A = Utils.Clamp((float)alpha, 0.0f, 1.0f);
  1698. tex.DefaultTexture.RGBA = texcolor;
  1699. }
  1700. part.UpdateTextureEntry(tex);
  1701. return;
  1702. }
  1703. }
  1704. /// <summary>
  1705. /// Set flexi parameters of a part.
  1706. ///
  1707. /// FIXME: Much of this code should probably be within the part itself.
  1708. /// </summary>
  1709. /// <param name="part"></param>
  1710. /// <param name="flexi"></param>
  1711. /// <param name="softness"></param>
  1712. /// <param name="gravity"></param>
  1713. /// <param name="friction"></param>
  1714. /// <param name="wind"></param>
  1715. /// <param name="tension"></param>
  1716. /// <param name="Force"></param>
  1717. protected static void SetFlexi(SceneObjectPart part, bool flexi, int softness, float gravity, float friction,
  1718. float wind, float tension, LSL_Vector Force)
  1719. {
  1720. if (part == null)
  1721. return;
  1722. SceneObjectGroup sog = part.ParentGroup;
  1723. if(sog == null || sog.IsDeleted || sog.inTransit)
  1724. return;
  1725. PrimitiveBaseShape pbs = part.Shape;
  1726. pbs.FlexiSoftness = softness;
  1727. pbs.FlexiGravity = gravity;
  1728. pbs.FlexiDrag = friction;
  1729. pbs.FlexiWind = wind;
  1730. pbs.FlexiTension = tension;
  1731. pbs.FlexiForceX = (float)Force.x;
  1732. pbs.FlexiForceY = (float)Force.y;
  1733. pbs.FlexiForceZ = (float)Force.z;
  1734. pbs.FlexiEntry = flexi;
  1735. if (!pbs.SculptEntry && (pbs.PathCurve == (byte)Extrusion.Straight || pbs.PathCurve == (byte)Extrusion.Flexible))
  1736. {
  1737. if(flexi)
  1738. {
  1739. pbs.PathCurve = (byte)Extrusion.Flexible;
  1740. if(!sog.IsPhantom)
  1741. {
  1742. sog.ScriptSetPhantomStatus(true);
  1743. return;
  1744. }
  1745. }
  1746. else
  1747. {
  1748. // Other values not set, they do not seem to be sent to the viewer
  1749. // Setting PathCurve appears to be what actually toggles the check box and turns Flexi on and off
  1750. pbs.PathCurve = (byte)Extrusion.Straight;
  1751. }
  1752. }
  1753. part.ParentGroup.HasGroupChanged = true;
  1754. part.ScheduleFullUpdate();
  1755. }
  1756. /// <summary>
  1757. /// Set a light point on a part
  1758. /// </summary>
  1759. /// FIXME: Much of this code should probably be in SceneObjectGroup
  1760. ///
  1761. /// <param name="part"></param>
  1762. /// <param name="light"></param>
  1763. /// <param name="color"></param>
  1764. /// <param name="intensity"></param>
  1765. /// <param name="radius"></param>
  1766. /// <param name="falloff"></param>
  1767. protected static void SetPointLight(SceneObjectPart part, bool light, LSL_Vector color, float intensity, float radius, float falloff)
  1768. {
  1769. if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
  1770. return;
  1771. PrimitiveBaseShape pbs = part.Shape;
  1772. if (light)
  1773. {
  1774. pbs.LightEntry = true;
  1775. pbs.LightColorR = Utils.Clamp((float)color.x, 0.0f, 1.0f);
  1776. pbs.LightColorG = Utils.Clamp((float)color.y, 0.0f, 1.0f);
  1777. pbs.LightColorB = Utils.Clamp((float)color.z, 0.0f, 1.0f);
  1778. pbs.LightIntensity = Utils.Clamp(intensity, 0.0f, 1.0f);
  1779. pbs.LightRadius = Utils.Clamp(radius, 0.1f, 20.0f);
  1780. pbs.LightFalloff = Utils.Clamp(falloff, 0.01f, 2.0f);
  1781. }
  1782. else
  1783. {
  1784. pbs.LightEntry = false;
  1785. }
  1786. part.ParentGroup.HasGroupChanged = true;
  1787. part.ScheduleFullUpdate();
  1788. }
  1789. public LSL_Vector llGetColor(int face)
  1790. {
  1791. return GetColor(m_host, face);
  1792. }
  1793. public LSL_Vector GetColor(SceneObjectPart part, int face)
  1794. {
  1795. Primitive.TextureEntry tex = part.Shape.Textures;
  1796. Color4 texcolor;
  1797. LSL_Vector rgb = new();
  1798. int nsides = GetNumberOfSides(part);
  1799. if (face == ScriptBaseClass.ALL_SIDES)
  1800. {
  1801. int i;
  1802. for (i = 0; i < nsides; i++)
  1803. {
  1804. texcolor = tex.GetFace((uint)i).RGBA;
  1805. rgb.x += texcolor.R;
  1806. rgb.y += texcolor.G;
  1807. rgb.z += texcolor.B;
  1808. }
  1809. float invnsides = 1.0f / (float)nsides;
  1810. rgb.x *= invnsides;
  1811. rgb.y *= invnsides;
  1812. rgb.z *= invnsides;
  1813. return rgb;
  1814. }
  1815. if (face >= 0 && face < nsides)
  1816. {
  1817. texcolor = tex.GetFace((uint)face).RGBA;
  1818. rgb.x = texcolor.R;
  1819. rgb.y = texcolor.G;
  1820. rgb.z = texcolor.B;
  1821. return rgb;
  1822. }
  1823. return LSL_Vector.Zero;
  1824. }
  1825. public void llSetTexture(string texture, int face)
  1826. {
  1827. SetTexture(m_host, texture, face);
  1828. ScriptSleep(m_sleepMsOnSetTexture);
  1829. }
  1830. public void llSetLinkTexture(int linknumber, string texture, int face)
  1831. {
  1832. List<SceneObjectPart> parts = GetLinkParts(linknumber);
  1833. if (parts.Count > 0)
  1834. {
  1835. try
  1836. {
  1837. foreach (SceneObjectPart part in parts)
  1838. SetTexture(part, texture, face);
  1839. }
  1840. finally { }
  1841. }
  1842. ScriptSleep(m_sleepMsOnSetLinkTexture);
  1843. }
  1844. protected void SetTextureParams(SceneObjectPart part, string texture, double scaleU, double ScaleV,
  1845. double offsetU, double offsetV, double rotation, int face)
  1846. {
  1847. if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
  1848. return;
  1849. UUID textureID = UUID.Zero;
  1850. bool dotexture = false;
  1851. if(!string.IsNullOrEmpty(texture) && texture != ScriptBaseClass.NULL_KEY)
  1852. {
  1853. textureID = ScriptUtils.GetAssetIdFromItemName(m_host, texture, (int)AssetType.Texture);
  1854. dotexture = textureID.IsNotZero() ||
  1855. (UUID.TryParse(texture, out textureID) && textureID.IsNotZero());
  1856. }
  1857. Primitive.TextureEntry tex = part.Shape.Textures;
  1858. int nsides = GetNumberOfSides(part);
  1859. if (face >= 0 && face < nsides)
  1860. {
  1861. Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
  1862. if (dotexture)
  1863. texface.TextureID = textureID;
  1864. texface.RepeatU = (float)scaleU;
  1865. texface.RepeatV = (float)ScaleV;
  1866. texface.OffsetU = (float)offsetU;
  1867. texface.OffsetV = (float)offsetV;
  1868. texface.Rotation = (float)rotation;
  1869. tex.FaceTextures[face] = texface;
  1870. part.UpdateTextureEntry(tex);
  1871. return;
  1872. }
  1873. else if (face == ScriptBaseClass.ALL_SIDES)
  1874. {
  1875. for (uint i = 0; i < nsides; i++)
  1876. {
  1877. if (tex.FaceTextures[i] != null)
  1878. {
  1879. if (dotexture)
  1880. tex.FaceTextures[i].TextureID = textureID;
  1881. tex.FaceTextures[i].RepeatU = (float)scaleU;
  1882. tex.FaceTextures[i].RepeatV = (float)ScaleV;
  1883. tex.FaceTextures[i].OffsetU = (float)offsetU;
  1884. tex.FaceTextures[i].OffsetV = (float)offsetV;
  1885. tex.FaceTextures[i].Rotation = (float)rotation;
  1886. }
  1887. }
  1888. if (dotexture)
  1889. tex.DefaultTexture.TextureID = textureID;
  1890. tex.DefaultTexture.RepeatU = (float)scaleU;
  1891. tex.DefaultTexture.RepeatV = (float)ScaleV;
  1892. tex.DefaultTexture.OffsetU = (float)offsetU;
  1893. tex.DefaultTexture.OffsetV = (float)offsetV;
  1894. tex.DefaultTexture.Rotation = (float)rotation;
  1895. part.UpdateTextureEntry(tex);
  1896. return;
  1897. }
  1898. }
  1899. protected void SetTexture(SceneObjectPart part, string texture, int face)
  1900. {
  1901. if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
  1902. return;
  1903. UUID textureID = ScriptUtils.GetAssetIdFromItemName(m_host, texture, (int)AssetType.Texture);
  1904. if (textureID.IsZero())
  1905. {
  1906. if (!UUID.TryParse(texture, out textureID) || textureID.IsZero())
  1907. return;
  1908. }
  1909. Primitive.TextureEntry tex = part.Shape.Textures;
  1910. int nsides = GetNumberOfSides(part);
  1911. if (face >= 0 && face < nsides)
  1912. {
  1913. Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
  1914. texface.TextureID = textureID;
  1915. tex.FaceTextures[face] = texface;
  1916. part.UpdateTextureEntry(tex);
  1917. return;
  1918. }
  1919. else if (face == ScriptBaseClass.ALL_SIDES)
  1920. {
  1921. for (uint i = 0; i < nsides; i++)
  1922. {
  1923. if (tex.FaceTextures[i] != null)
  1924. {
  1925. tex.FaceTextures[i].TextureID = textureID;
  1926. }
  1927. }
  1928. tex.DefaultTexture.TextureID = textureID;
  1929. part.UpdateTextureEntry(tex);
  1930. return;
  1931. }
  1932. }
  1933. public void llScaleTexture(double u, double v, int face)
  1934. {
  1935. ScaleTexture(m_host, u, v, face);
  1936. ScriptSleep(m_sleepMsOnScaleTexture);
  1937. }
  1938. protected static void ScaleTexture(SceneObjectPart part, double u, double v, int face)
  1939. {
  1940. if (part is null || part.ParentGroup is null || part.ParentGroup.IsDeleted)
  1941. return;
  1942. Primitive.TextureEntry tex = part.Shape.Textures;
  1943. int nsides = GetNumberOfSides(part);
  1944. if (face >= 0 && face < nsides)
  1945. {
  1946. Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
  1947. texface.RepeatU = (float)u;
  1948. texface.RepeatV = (float)v;
  1949. tex.FaceTextures[face] = texface;
  1950. part.UpdateTextureEntry(tex);
  1951. return;
  1952. }
  1953. if (face == ScriptBaseClass.ALL_SIDES)
  1954. {
  1955. for (int i = 0; i < nsides; i++)
  1956. {
  1957. if (tex.FaceTextures[i] is not null)
  1958. {
  1959. tex.FaceTextures[i].RepeatU = (float)u;
  1960. tex.FaceTextures[i].RepeatV = (float)v;
  1961. }
  1962. }
  1963. tex.DefaultTexture.RepeatU = (float)u;
  1964. tex.DefaultTexture.RepeatV = (float)v;
  1965. part.UpdateTextureEntry(tex);
  1966. return;
  1967. }
  1968. }
  1969. public void llOffsetTexture(double u, double v, int face)
  1970. {
  1971. OffsetTexture(m_host, u, v, face);
  1972. ScriptSleep(m_sleepMsOnOffsetTexture);
  1973. }
  1974. protected static void OffsetTexture(SceneObjectPart part, double u, double v, int face)
  1975. {
  1976. if (part is null || part.ParentGroup is null || part.ParentGroup.IsDeleted)
  1977. return;
  1978. Primitive.TextureEntry tex = part.Shape.Textures;
  1979. int nsides = GetNumberOfSides(part);
  1980. if (face >= 0 && face < nsides)
  1981. {
  1982. Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
  1983. texface.OffsetU = (float)u;
  1984. texface.OffsetV = (float)v;
  1985. tex.FaceTextures[face] = texface;
  1986. part.UpdateTextureEntry(tex);
  1987. return;
  1988. }
  1989. if (face == ScriptBaseClass.ALL_SIDES)
  1990. {
  1991. for (int i = 0; i < nsides; i++)
  1992. {
  1993. if (tex.FaceTextures[i] is not null)
  1994. {
  1995. tex.FaceTextures[i].OffsetU = (float)u;
  1996. tex.FaceTextures[i].OffsetV = (float)v;
  1997. }
  1998. }
  1999. tex.DefaultTexture.OffsetU = (float)u;
  2000. tex.DefaultTexture.OffsetV = (float)v;
  2001. part.UpdateTextureEntry(tex);
  2002. return;
  2003. }
  2004. }
  2005. public void llRotateTexture(double rotation, int face)
  2006. {
  2007. RotateTexture(m_host, rotation, face);
  2008. ScriptSleep(m_sleepMsOnRotateTexture);
  2009. }
  2010. protected static void RotateTexture(SceneObjectPart part, double rotation, int face)
  2011. {
  2012. if (part is null || part.ParentGroup is null || part.ParentGroup.IsDeleted)
  2013. return;
  2014. Primitive.TextureEntry tex = part.Shape.Textures;
  2015. int nsides = GetNumberOfSides(part);
  2016. if (face >= 0 && face < nsides)
  2017. {
  2018. Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
  2019. texface.Rotation = (float)rotation;
  2020. tex.FaceTextures[face] = texface;
  2021. part.UpdateTextureEntry(tex);
  2022. return;
  2023. }
  2024. if (face == ScriptBaseClass.ALL_SIDES)
  2025. {
  2026. for (int i = 0; i < nsides; i++)
  2027. {
  2028. if (tex.FaceTextures[i] is not null)
  2029. {
  2030. tex.FaceTextures[i].Rotation = (float)rotation;
  2031. }
  2032. }
  2033. tex.DefaultTexture.Rotation = (float)rotation;
  2034. part.UpdateTextureEntry(tex);
  2035. return;
  2036. }
  2037. }
  2038. public LSL_String llGetTexture(int face)
  2039. {
  2040. return GetTexture(m_host, face);
  2041. }
  2042. protected static LSL_String GetTexture(SceneObjectPart part, int face)
  2043. {
  2044. Primitive.TextureEntry tex = part.Shape.Textures;
  2045. int nsides = GetNumberOfSides(part);
  2046. if (face == ScriptBaseClass.ALL_SIDES)
  2047. {
  2048. face = 0;
  2049. }
  2050. if (face >= 0 && face < nsides)
  2051. {
  2052. Primitive.TextureEntryFace texface;
  2053. texface = tex.GetFace((uint)face);
  2054. string texture = texface.TextureID.ToString();
  2055. lock (part.TaskInventory)
  2056. {
  2057. foreach (KeyValuePair<UUID, TaskInventoryItem> inv in part.TaskInventory)
  2058. {
  2059. if (inv.Value.AssetID.Equals(texface.TextureID))
  2060. {
  2061. texture = inv.Value.Name.ToString();
  2062. break;
  2063. }
  2064. }
  2065. }
  2066. return texture;
  2067. }
  2068. else
  2069. {
  2070. return ScriptBaseClass.NULL_KEY;
  2071. }
  2072. }
  2073. public void llSetPos(LSL_Vector pos)
  2074. {
  2075. SetPos(m_host, pos, true);
  2076. ScriptSleep(m_sleepMsOnSetPos);
  2077. }
  2078. /// <summary>
  2079. /// Tries to move the entire object so that the root prim is within 0.1m of position. http://wiki.secondlife.com/wiki/LlSetRegionPos
  2080. /// Documentation indicates that the use of x/y coordinates up to 10 meters outside the bounds of a region will work but do not specify what happens if there is no adjacent region for the object to move into.
  2081. /// Uses the RegionSize constant here rather than hard-coding 266.0 to alert any developer modifying OpenSim to support variable-sized regions that this method will need tweaking.
  2082. /// </summary>
  2083. /// <param name="pos"></param>
  2084. /// <returns>1 if successful, 0 otherwise.</returns>
  2085. public LSL_Integer llSetRegionPos(LSL_Vector pos)
  2086. {
  2087. // BEGIN WORKAROUND
  2088. // IF YOU GET REGION CROSSINGS WORKING WITH THIS FUNCTION, REPLACE THE WORKAROUND.
  2089. //
  2090. // This workaround is to prevent silent failure of this function.
  2091. // According to the specification on the SL Wiki, providing a position outside of the
  2092. if (pos.x < 0 || pos.x > World.RegionInfo.RegionSizeX || pos.y < 0 || pos.y > World.RegionInfo.RegionSizeY)
  2093. {
  2094. return 0;
  2095. }
  2096. // END WORK AROUND
  2097. else if ( // this is not part of the workaround if-block because it's not related to the workaround.
  2098. IsPhysical() ||
  2099. m_host.ParentGroup.IsAttachment || // return FALSE if attachment
  2100. (
  2101. pos.x < -10.0 || // return FALSE if more than 10 meters into a west-adjacent region.
  2102. pos.x > (World.RegionInfo.RegionSizeX + 10) || // return FALSE if more than 10 meters into a east-adjacent region.
  2103. pos.y < -10.0 || // return FALSE if more than 10 meters into a south-adjacent region.
  2104. pos.y > (World.RegionInfo.RegionSizeY + 10) || // return FALSE if more than 10 meters into a north-adjacent region.
  2105. pos.z > Constants.RegionHeight // return FALSE if altitude than 4096m
  2106. )
  2107. )
  2108. {
  2109. return 0;
  2110. }
  2111. // if we reach this point, then the object is not physical, it's not an attachment, and the destination is within the valid range.
  2112. // this could possibly be done in the above else-if block, but we're doing the check here to keep the code easier to read.
  2113. Vector3 objectPos = m_host.ParentGroup.RootPart.AbsolutePosition;
  2114. LandData here = World.GetLandData(objectPos);
  2115. LandData there = World.GetLandData(pos);
  2116. // we're only checking prim limits if it's moving to a different parcel under the assumption that if the object got onto the parcel without exceeding the prim limits.
  2117. bool sameParcel = here.GlobalID.Equals(there.GlobalID);
  2118. if (!sameParcel && !World.Permissions.CanRezObject(
  2119. m_host.ParentGroup.PrimCount, m_host.ParentGroup.OwnerID, pos))
  2120. {
  2121. return 0;
  2122. }
  2123. SetPos(m_host.ParentGroup.RootPart, pos, false);
  2124. return VecDistSquare(pos, llGetRootPosition()) <= 0.01 ? 1 : 0;
  2125. }
  2126. // Capped movemment if distance > 10m (http://wiki.secondlife.com/wiki/LlSetPos)
  2127. // note linked setpos is capped "differently"
  2128. private LSL_Vector SetPosAdjust(LSL_Vector start, LSL_Vector end)
  2129. {
  2130. if (VecDistSquare(start, end) > m_Script10mDistanceSquare)
  2131. return start + m_Script10mDistance * llVecNorm(end - start);
  2132. else
  2133. return end;
  2134. }
  2135. protected LSL_Vector GetSetPosTarget(SceneObjectPart part, LSL_Vector targetPos, LSL_Vector fromPos, bool adjust)
  2136. {
  2137. if (part == null)
  2138. return targetPos;
  2139. SceneObjectGroup grp = part.ParentGroup;
  2140. if (grp == null || grp.IsDeleted || grp.inTransit)
  2141. return targetPos;
  2142. if (adjust)
  2143. targetPos = SetPosAdjust(fromPos, targetPos);
  2144. if (m_disable_underground_movement && grp.AttachmentPoint == 0)
  2145. {
  2146. if (part.IsRoot)
  2147. {
  2148. float ground = World.GetGroundHeight((float)targetPos.x, (float)targetPos.y);
  2149. if ((targetPos.z < ground))
  2150. targetPos.z = ground;
  2151. }
  2152. }
  2153. return targetPos;
  2154. }
  2155. /// <summary>
  2156. /// set object position, optionally capping the distance.
  2157. /// </summary>
  2158. /// <param name="part"></param>
  2159. /// <param name="targetPos"></param>
  2160. /// <param name="adjust">if TRUE, will cap the distance to 10m.</param>
  2161. protected void SetPos(SceneObjectPart part, LSL_Vector targetPos, bool adjust)
  2162. {
  2163. if (part == null)
  2164. return;
  2165. SceneObjectGroup grp = part.ParentGroup;
  2166. if (grp == null || grp.IsDeleted || grp.inTransit)
  2167. return;
  2168. LSL_Vector currentPos = GetPartLocalPos(part);
  2169. LSL_Vector toPos = GetSetPosTarget(part, targetPos, currentPos, adjust);
  2170. if (part.IsRoot)
  2171. {
  2172. if (!grp.IsAttachment && !World.Permissions.CanObjectEntry(grp, false, (Vector3)toPos))
  2173. return;
  2174. grp.UpdateGroupPosition((Vector3)toPos);
  2175. }
  2176. else
  2177. {
  2178. part.OffsetPosition = (Vector3)toPos;
  2179. // SceneObjectGroup parent = part.ParentGroup;
  2180. // parent.HasGroupChanged = true;
  2181. // parent.ScheduleGroupForTerseUpdate();
  2182. part.ScheduleTerseUpdate();
  2183. }
  2184. }
  2185. public LSL_Vector llGetPos()
  2186. {
  2187. return m_host.GetWorldPosition();
  2188. }
  2189. public LSL_Vector llGetLocalPos()
  2190. {
  2191. return GetPartLocalPos(m_host);
  2192. }
  2193. protected static LSL_Vector GetPartLocalPos(SceneObjectPart part)
  2194. {
  2195. if (part.IsRoot)
  2196. {
  2197. if (part.ParentGroup.IsAttachment)
  2198. return new LSL_Vector(part.AttachedPos);
  2199. return new LSL_Vector(part.AbsolutePosition);
  2200. }
  2201. return new LSL_Vector(part.OffsetPosition);
  2202. }
  2203. public void llSetRot(LSL_Rotation rot)
  2204. {
  2205. // try to let this work as in SL...
  2206. if (m_host.ParentID == 0 || (m_host.ParentGroup != null && m_host == m_host.ParentGroup.RootPart))
  2207. {
  2208. // special case: If we are root, rotate complete SOG to new rotation
  2209. SetRot(m_host, rot);
  2210. }
  2211. else
  2212. {
  2213. // we are a child. The rotation values will be set to the one of root modified by rot, as in SL. Don't ask.
  2214. SceneObjectPart rootPart = m_host.ParentGroup.RootPart;
  2215. if (rootPart != null) // better safe than sorry
  2216. {
  2217. SetRot(m_host, rootPart.RotationOffset * (Quaternion)rot);
  2218. }
  2219. }
  2220. ScriptSleep(m_sleepMsOnSetRot);
  2221. }
  2222. public void llSetLocalRot(LSL_Rotation rot)
  2223. {
  2224. SetRot(m_host, rot);
  2225. ScriptSleep(m_sleepMsOnSetLocalRot);
  2226. }
  2227. protected static void SetRot(SceneObjectPart part, Quaternion rot)
  2228. {
  2229. if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted)
  2230. return;
  2231. bool isroot = (part == part.ParentGroup.RootPart);
  2232. bool isphys;
  2233. PhysicsActor pa = part.PhysActor;
  2234. // keep using physactor ideia of isphysical
  2235. // it should be SOP ideia of that
  2236. // not much of a issue with ubOde
  2237. if (pa != null && pa.IsPhysical)
  2238. isphys = true;
  2239. else
  2240. isphys = false;
  2241. // SL doesn't let scripts rotate root of physical linksets
  2242. if (isroot && isphys)
  2243. return;
  2244. part.UpdateRotation(rot);
  2245. // Update rotation does not move the object in the physics engine if it's a non physical linkset
  2246. // so do a nasty update of parts positions if is a root part rotation
  2247. if (isroot && pa != null) // with if above implies non physical root part
  2248. {
  2249. part.ParentGroup.ResetChildPrimPhysicsPositions();
  2250. }
  2251. else // fix sitting avatars. This is only needed bc of how we link avas to child parts, not root part
  2252. {
  2253. // List<ScenePresence> sittingavas = part.ParentGroup.GetLinkedAvatars();
  2254. List<ScenePresence> sittingavas = part.ParentGroup.GetSittingAvatars();
  2255. if (sittingavas.Count > 0)
  2256. {
  2257. foreach (ScenePresence av in sittingavas)
  2258. {
  2259. if (isroot || part.LocalId == av.ParentID)
  2260. av.SendTerseUpdateToAllClients();
  2261. }
  2262. }
  2263. }
  2264. }
  2265. /// <summary>
  2266. /// See http://lslwiki.net/lslwiki/wakka.php?wakka=ChildRotation
  2267. /// </summary>
  2268. public LSL_Rotation llGetRot()
  2269. {
  2270. // unlinked or root prim then use llRootRotation
  2271. // see llRootRotaion for references.
  2272. if (m_host.LinkNum == 0 || m_host.LinkNum == 1)
  2273. {
  2274. return llGetRootRotation();
  2275. }
  2276. Quaternion q = m_host.GetWorldRotation();
  2277. if (m_host.ParentGroup != null && m_host.ParentGroup.AttachmentPoint != 0)
  2278. {
  2279. ScenePresence avatar = World.GetScenePresence(m_host.ParentGroup.AttachedAvatar);
  2280. if (avatar != null)
  2281. {
  2282. if ((avatar.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0)
  2283. q = avatar.CameraRotation * q; // Mouselook
  2284. else
  2285. q = avatar.Rotation * q; // Currently infrequently updated so may be inaccurate
  2286. }
  2287. }
  2288. return new LSL_Rotation(q.X, q.Y, q.Z, q.W);
  2289. }
  2290. private LSL_Rotation GetPartRot(SceneObjectPart part)
  2291. {
  2292. Quaternion q;
  2293. if (part.LinkNum == 0 || part.LinkNum == 1) // unlinked or root prim
  2294. {
  2295. if (part.ParentGroup.AttachmentPoint != 0)
  2296. {
  2297. ScenePresence avatar = World.GetScenePresence(part.ParentGroup.AttachedAvatar);
  2298. if (avatar != null)
  2299. {
  2300. if ((avatar.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0)
  2301. q = avatar.CameraRotation; // Mouselook
  2302. else
  2303. q = avatar.GetWorldRotation(); // Currently infrequently updated so may be inaccurate
  2304. }
  2305. else
  2306. q = part.ParentGroup.GroupRotation; // Likely never get here but just in case
  2307. }
  2308. else
  2309. q = part.ParentGroup.GroupRotation; // just the group rotation
  2310. return new LSL_Rotation(q);
  2311. }
  2312. q = part.GetWorldRotation();
  2313. if (part.ParentGroup.AttachmentPoint != 0)
  2314. {
  2315. ScenePresence avatar = World.GetScenePresence(part.ParentGroup.AttachedAvatar);
  2316. if (avatar != null)
  2317. {
  2318. if ((avatar.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0)
  2319. q = avatar.CameraRotation * q; // Mouselook
  2320. else
  2321. q = avatar.Rotation * q; // Currently infrequently updated so may be inaccurate
  2322. }
  2323. }
  2324. return new LSL_Rotation(q.X, q.Y, q.Z, q.W);
  2325. }
  2326. public LSL_Rotation llGetLocalRot()
  2327. {
  2328. return GetPartLocalRot(m_host);
  2329. }
  2330. private static LSL_Rotation GetPartLocalRot(SceneObjectPart part)
  2331. {
  2332. return new LSL_Rotation(part.RotationOffset);
  2333. }
  2334. public void llSetForce(LSL_Vector force, int local)
  2335. {
  2336. if (!m_host.ParentGroup.IsDeleted)
  2337. {
  2338. if (local != 0)
  2339. force *= llGetRot();
  2340. m_host.ParentGroup.RootPart.SetForce(force);
  2341. }
  2342. }
  2343. public LSL_Vector llGetForce()
  2344. {
  2345. if (!m_host.ParentGroup.IsDeleted)
  2346. return m_host.ParentGroup.RootPart.GetForce();
  2347. return LSL_Vector.Zero;
  2348. }
  2349. public void llSetVelocity(LSL_Vector vel, int local)
  2350. {
  2351. m_host.SetVelocity(new Vector3((float)vel.x, (float)vel.y, (float)vel.z), local != 0);
  2352. }
  2353. public void llSetAngularVelocity(LSL_Vector avel, int local)
  2354. {
  2355. m_host.SetAngularVelocity(new Vector3((float)avel.x, (float)avel.y, (float)avel.z), local != 0);
  2356. }
  2357. public LSL_Integer llTarget(LSL_Vector position, double range)
  2358. {
  2359. return m_host.ParentGroup.RegisterTargetWaypoint(m_item.ItemID, position, (float)range);
  2360. }
  2361. public void llTargetRemove(int number)
  2362. {
  2363. m_host.ParentGroup.UnregisterTargetWaypoint(number);
  2364. }
  2365. public LSL_Integer llRotTarget(LSL_Rotation rot, double error)
  2366. {
  2367. return m_host.ParentGroup.RegisterRotTargetWaypoint(m_item.ItemID, rot, (float)error);
  2368. }
  2369. public void llRotTargetRemove(int number)
  2370. {
  2371. m_host.ParentGroup.UnRegisterRotTargetWaypoint(number);
  2372. }
  2373. public void llMoveToTarget(LSL_Vector target, double tau)
  2374. {
  2375. m_host.ParentGroup.MoveToTarget(target, (float)tau);
  2376. }
  2377. public void llStopMoveToTarget()
  2378. {
  2379. m_host.ParentGroup.StopMoveToTarget();
  2380. }
  2381. public void llApplyImpulse(LSL_Vector force, LSL_Integer local)
  2382. {
  2383. //No energy force yet
  2384. Vector3 v = force;
  2385. if (v.Length() > 20000.0f)
  2386. {
  2387. v.Normalize();
  2388. v *= 20000.0f;
  2389. }
  2390. m_host.ApplyImpulse(v, local != 0);
  2391. }
  2392. public void llApplyRotationalImpulse(LSL_Vector force, int local)
  2393. {
  2394. m_host.ParentGroup.RootPart.ApplyAngularImpulse(force, local != 0);
  2395. }
  2396. public void llSetTorque(LSL_Vector torque, int local)
  2397. {
  2398. m_host.ParentGroup.RootPart.SetAngularImpulse(torque, local != 0);
  2399. }
  2400. public LSL_Vector llGetTorque()
  2401. {
  2402. return new LSL_Vector(m_host.ParentGroup.GetTorque());
  2403. }
  2404. public void llSetForceAndTorque(LSL_Vector force, LSL_Vector torque, int local)
  2405. {
  2406. llSetForce(force, local);
  2407. llSetTorque(torque, local);
  2408. }
  2409. public LSL_Vector llGetVel()
  2410. {
  2411. Vector3 vel = Vector3.Zero;
  2412. if (m_host.ParentGroup.IsAttachment)
  2413. {
  2414. ScenePresence avatar = m_host.ParentGroup.Scene.GetScenePresence(m_host.ParentGroup.AttachedAvatar);
  2415. if (avatar != null)
  2416. vel = avatar.GetWorldVelocity();
  2417. }
  2418. else
  2419. {
  2420. vel = m_host.ParentGroup.RootPart.Velocity;
  2421. }
  2422. return new LSL_Vector(vel);
  2423. }
  2424. public LSL_Vector llGetAccel()
  2425. {
  2426. return new LSL_Vector(m_host.Acceleration);
  2427. }
  2428. public LSL_Vector llGetOmega()
  2429. {
  2430. Vector3 avel = m_host.AngularVelocity;
  2431. return new LSL_Vector(avel.X, avel.Y, avel.Z);
  2432. }
  2433. public LSL_Float llGetTimeOfDay()
  2434. {
  2435. return (double)((DateTime.Now.TimeOfDay.TotalMilliseconds / 1000) % (3600 * 4));
  2436. }
  2437. public LSL_Float llGetWallclock()
  2438. {
  2439. return DateTime.Now.TimeOfDay.TotalSeconds;
  2440. }
  2441. public LSL_Float llGetTime()
  2442. {
  2443. double ScriptTime = Util.GetTimeStampMS() - m_timer;
  2444. return (float)Math.Round((ScriptTime / 1000.0), 3);
  2445. }
  2446. public void llResetTime()
  2447. {
  2448. m_timer = Util.GetTimeStampMS();
  2449. }
  2450. public LSL_Float llGetAndResetTime()
  2451. {
  2452. double now = Util.GetTimeStampMS();
  2453. double ScriptTime = now - m_timer;
  2454. m_timer = now;
  2455. return (float)Math.Round((ScriptTime / 1000.0), 3);
  2456. }
  2457. public void llSound(string sound, double volume, int queue, int loop)
  2458. {
  2459. Deprecated("llSound", "Use llPlaySound instead");
  2460. }
  2461. // Xantor 20080528 PlaySound updated so it accepts an objectinventory name -or- a key to a sound
  2462. // 20080530 Updated to remove code duplication
  2463. public void llPlaySound(string sound, double volume)
  2464. {
  2465. if (m_SoundModule == null)
  2466. return;
  2467. UUID soundID = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound);
  2468. if(soundID.IsNotZero())
  2469. m_SoundModule.SendSound(m_host, soundID, volume, false, 0, false, false);
  2470. }
  2471. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  2472. public void llLinkPlaySound(LSL_Integer linknumber, string sound, double volume)
  2473. {
  2474. llLinkPlaySound(linknumber, sound, volume, 0);
  2475. }
  2476. public void llLinkPlaySound(LSL_Integer linknumber, string sound, double volume, LSL_Integer flags)
  2477. {
  2478. if (m_SoundModule is null)
  2479. return;
  2480. if (m_host.ParentGroup is null || m_host.ParentGroup.IsDeleted)
  2481. return;
  2482. UUID soundID = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound);
  2483. if (soundID.IsZero())
  2484. return;
  2485. List<SceneObjectPart> parts = GetLinkParts(m_host, linknumber.value);
  2486. if (parts.Count == 0)
  2487. return;
  2488. switch (flags)
  2489. {
  2490. case ScriptBaseClass.SOUND_PLAY: // play
  2491. foreach (SceneObjectPart sop in parts)
  2492. m_SoundModule.SendSound(sop, soundID, volume, false, 0, false, false);
  2493. break;
  2494. case ScriptBaseClass.SOUND_LOOP: // loop
  2495. foreach (SceneObjectPart sop in parts)
  2496. m_SoundModule.LoopSound(sop, soundID, volume, false, false);
  2497. break;
  2498. case ScriptBaseClass.SOUND_TRIGGER: //trigger
  2499. foreach (SceneObjectPart sop in parts)
  2500. m_SoundModule.SendSound(sop, soundID, volume, true, 0, false, false);
  2501. break;
  2502. case ScriptBaseClass.SOUND_SYNC: // play slave
  2503. foreach (SceneObjectPart sop in parts)
  2504. m_SoundModule.SendSound(sop, soundID, volume, false, 0, true, false);
  2505. break;
  2506. case ScriptBaseClass.SOUND_SYNC | ScriptBaseClass.SOUND_LOOP: // loop slave
  2507. foreach (SceneObjectPart sop in parts)
  2508. m_SoundModule.LoopSound(sop, soundID, volume, false, true);
  2509. break;
  2510. }
  2511. }
  2512. public void llLoopSound(string sound, double volume)
  2513. {
  2514. if (m_SoundModule is null)
  2515. return;
  2516. UUID soundID = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound);
  2517. if(soundID.IsZero())
  2518. return;
  2519. m_SoundModule.LoopSound(m_host, soundID, volume, false, false);
  2520. }
  2521. public void llLoopSoundMaster(string sound, double volume)
  2522. {
  2523. if (m_SoundModule is null)
  2524. return;
  2525. UUID soundID = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound);
  2526. if(soundID.IsZero())
  2527. return;
  2528. m_SoundModule.LoopSound(m_host, soundID, volume, true, false);
  2529. }
  2530. public void llLoopSoundSlave(string sound, double volume)
  2531. {
  2532. if (m_SoundModule is null)
  2533. return;
  2534. UUID soundID = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound);
  2535. if(soundID.IsZero())
  2536. return;
  2537. m_SoundModule.LoopSound(m_host, soundID, volume, false, true);
  2538. }
  2539. public void llPlaySoundSlave(string sound, double volume)
  2540. {
  2541. if (m_SoundModule is null)
  2542. return;
  2543. UUID soundID = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound);
  2544. if(soundID.IsZero())
  2545. return;
  2546. // send the sound, once, to all clients in range
  2547. m_SoundModule.SendSound(m_host, soundID, volume, false, 0, true, false);
  2548. }
  2549. public void llTriggerSound(string sound, double volume)
  2550. {
  2551. if (m_SoundModule is null)
  2552. return;
  2553. UUID soundID = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound);
  2554. if(soundID.IsZero())
  2555. return;
  2556. // send the sound, once, to all clients in rangeTrigger or play an attached sound in this part's inventory.
  2557. m_SoundModule.SendSound(m_host, soundID, volume, true, 0, false, false);
  2558. }
  2559. public void llStopSound()
  2560. {
  2561. m_SoundModule?.StopSound(m_host);
  2562. }
  2563. public void llLinkStopSound(LSL_Integer linknumber)
  2564. {
  2565. if (m_SoundModule is not null)
  2566. {
  2567. foreach(SceneObjectPart sop in GetLinkParts(linknumber))
  2568. m_SoundModule.StopSound(sop);
  2569. }
  2570. }
  2571. public void llPreloadSound(string sound)
  2572. {
  2573. if (m_SoundModule is null)
  2574. return;
  2575. UUID soundID = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound);
  2576. if(soundID.IsZero())
  2577. return;
  2578. m_SoundModule.PreloadSound(m_host, soundID);
  2579. ScriptSleep(m_sleepMsOnPreloadSound);
  2580. }
  2581. /// <summary>
  2582. /// Return a portion of the designated string bounded by
  2583. /// inclusive indices (start and end). As usual, the negative
  2584. /// indices, and the tolerance for out-of-bound values, makes
  2585. /// this more complicated than it might otherwise seem.
  2586. /// </summary>
  2587. public LSL_String llGetSubString(string src, int start, int end)
  2588. {
  2589. // Normalize indices (if negative).
  2590. // After normlaization they may still be
  2591. // negative, but that is now relative to
  2592. // the start, rather than the end, of the
  2593. // sequence.
  2594. if (start < 0)
  2595. {
  2596. start = src.Length+start;
  2597. }
  2598. if (end < 0)
  2599. {
  2600. end = src.Length+end;
  2601. }
  2602. // Conventional substring
  2603. if (start <= end)
  2604. {
  2605. // Implies both bounds are out-of-range.
  2606. if (end < 0 || start >= src.Length)
  2607. {
  2608. return String.Empty;
  2609. }
  2610. // If end is positive, then it directly
  2611. // corresponds to the lengt of the substring
  2612. // needed (plus one of course). BUT, it
  2613. // must be within bounds.
  2614. if (end >= src.Length)
  2615. {
  2616. end = src.Length-1;
  2617. }
  2618. if (start < 0)
  2619. {
  2620. return src[..(end + 1)];
  2621. }
  2622. // Both indices are positive
  2623. return src[start..(end + 1)];
  2624. }
  2625. // Inverted substring (end < start)
  2626. else
  2627. {
  2628. // Implies both indices are below the
  2629. // lower bound. In the inverted case, that
  2630. // means the entire string will be returned
  2631. // unchanged.
  2632. if (start < 0)
  2633. {
  2634. return src;
  2635. }
  2636. // If both indices are greater than the upper
  2637. // bound the result may seem initially counter
  2638. // intuitive.
  2639. if (end >= src.Length)
  2640. {
  2641. return src;
  2642. }
  2643. if (end < 0)
  2644. {
  2645. if (start < src.Length)
  2646. {
  2647. return src[start..];
  2648. }
  2649. else
  2650. {
  2651. return String.Empty;
  2652. }
  2653. }
  2654. else
  2655. {
  2656. if (start < src.Length)
  2657. {
  2658. return src[..(end + 1)] + src[start..];
  2659. }
  2660. else
  2661. {
  2662. return src[..(end + 1)];
  2663. }
  2664. }
  2665. }
  2666. }
  2667. /// <summary>
  2668. /// Delete substring removes the specified substring bounded
  2669. /// by the inclusive indices start and end. Indices may be
  2670. /// negative (indicating end-relative) and may be inverted,
  2671. /// i.e. end < start.
  2672. /// </summary>
  2673. public LSL_String llDeleteSubString(string src, int start, int end)
  2674. {
  2675. // Normalize indices (if negative).
  2676. // After normlaization they may still be
  2677. // negative, but that is now relative to
  2678. // the start, rather than the end, of the
  2679. // sequence.
  2680. if (start < 0)
  2681. {
  2682. start = src.Length+start;
  2683. }
  2684. if (end < 0)
  2685. {
  2686. end = src.Length+end;
  2687. }
  2688. // Conventionally delimited substring
  2689. if (start <= end)
  2690. {
  2691. // If both bounds are outside of the existing
  2692. // string, then return unchanged.
  2693. if (end < 0 || start >= src.Length)
  2694. {
  2695. return src;
  2696. }
  2697. // At least one bound is in-range, so we
  2698. // need to clip the out-of-bound argument.
  2699. if (start < 0)
  2700. {
  2701. start = 0;
  2702. }
  2703. if (end >= src.Length)
  2704. {
  2705. end = src.Length-1;
  2706. }
  2707. return src.Remove(start,end-start+1);
  2708. }
  2709. // Inverted substring
  2710. else
  2711. {
  2712. // In this case, out of bounds means that
  2713. // the existing string is part of the cut.
  2714. if (start < 0 || end >= src.Length)
  2715. {
  2716. return String.Empty;
  2717. }
  2718. if (end > 0)
  2719. {
  2720. if (start < src.Length)
  2721. {
  2722. return src.Remove(start).Remove(0, end + 1);
  2723. }
  2724. else
  2725. {
  2726. return src.Remove(0, end + 1);
  2727. }
  2728. }
  2729. else
  2730. {
  2731. if (start < src.Length)
  2732. {
  2733. return src.Remove(start);
  2734. }
  2735. else
  2736. {
  2737. return src;
  2738. }
  2739. }
  2740. }
  2741. }
  2742. /// <summary>
  2743. /// Insert string inserts the specified string identified by src
  2744. /// at the index indicated by index. Index may be negative, in
  2745. /// which case it is end-relative. The index may exceed either
  2746. /// string bound, with the result being a concatenation.
  2747. /// </summary>
  2748. // this is actually wrong. according to SL wiki, this function should not support negative indexes.
  2749. public LSL_String llInsertString(string dest, int index, string src)
  2750. {
  2751. // Normalize indices (if negative).
  2752. // After normalization they may still be
  2753. // negative, but that is now relative to
  2754. // the start, rather than the end, of the
  2755. // sequence.
  2756. char c;
  2757. if (index < 0)
  2758. {
  2759. index = dest.Length+index;
  2760. // Negative now means it is less than the lower
  2761. // bound of the string.
  2762. if(index > 0)
  2763. {
  2764. c = dest[index];
  2765. if (c >= 0xDC00 && c <= 0xDFFF)
  2766. --index;
  2767. }
  2768. if (index < 0)
  2769. {
  2770. return src+dest;
  2771. }
  2772. }
  2773. else
  2774. {
  2775. c = dest[index];
  2776. if (c >= 0xDC00 && c <= 0xDFFF)
  2777. ++index;
  2778. }
  2779. if (index >= dest.Length)
  2780. {
  2781. return dest + src;
  2782. }
  2783. // The index is in bounds.
  2784. // In this case the index refers to the index that will
  2785. // be assigned to the first character of the inserted string.
  2786. // So unlike the other string operations, we do not add one
  2787. // to get the correct string length.
  2788. return dest[..index] + src + dest[index..];
  2789. }
  2790. public LSL_String llToUpper(string src)
  2791. {
  2792. return src.ToUpper();
  2793. }
  2794. public LSL_String llToLower(string src)
  2795. {
  2796. return src.ToLower();
  2797. }
  2798. public LSL_Integer llGiveMoney(LSL_Key destination, LSL_Integer amount)
  2799. {
  2800. if (m_item.PermsGranter.IsZero())
  2801. return 0;
  2802. if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_DEBIT) == 0)
  2803. {
  2804. Error("llGiveMoney", "No permissions to give money");
  2805. return 0;
  2806. }
  2807. if (!UUID.TryParse(destination, out UUID toID))
  2808. {
  2809. Error("llGiveMoney", "Bad key in llGiveMoney");
  2810. return 0;
  2811. }
  2812. IMoneyModule money = World.RequestModuleInterface<IMoneyModule>();
  2813. if (money is null)
  2814. {
  2815. NotImplemented("llGiveMoney");
  2816. return 0;
  2817. }
  2818. void act(string _)
  2819. {
  2820. money.ObjectGiveMoney(m_host.ParentGroup.RootPart.UUID, m_host.ParentGroup.RootPart.OwnerID,
  2821. toID, amount, UUID.Zero, out _);
  2822. }
  2823. m_AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, act);
  2824. return 0;
  2825. }
  2826. public void llMakeExplosion(int particles, double scale, double vel, double lifetime, double arc, string texture, LSL_Vector offset)
  2827. {
  2828. Deprecated("llMakeExplosion", "Use llParticleSystem instead");
  2829. ScriptSleep(m_sleepMsOnMakeExplosion);
  2830. }
  2831. public void llMakeFountain(int particles, double scale, double vel, double lifetime, double arc, int bounce, string texture, LSL_Vector offset, double bounce_offset)
  2832. {
  2833. Deprecated("llMakeFountain", "Use llParticleSystem instead");
  2834. ScriptSleep(m_sleepMsOnMakeFountain);
  2835. }
  2836. public void llMakeSmoke(int particles, double scale, double vel, double lifetime, double arc, string texture, LSL_Vector offset)
  2837. {
  2838. Deprecated("llMakeSmoke", "Use llParticleSystem instead");
  2839. ScriptSleep(m_sleepMsOnMakeSmoke);
  2840. }
  2841. public void llMakeFire(int particles, double scale, double vel, double lifetime, double arc, string texture, LSL_Vector offset)
  2842. {
  2843. Deprecated("llMakeFire", "Use llParticleSystem instead");
  2844. ScriptSleep(m_sleepMsOnMakeFire);
  2845. }
  2846. public void llRezAtRoot(string inventory, LSL_Vector pos, LSL_Vector vel, LSL_Rotation rot, int param)
  2847. {
  2848. doObjectRez(inventory, pos, vel, rot, param, true);
  2849. }
  2850. public void doObjectRez(string inventory, LSL_Vector pos, LSL_Vector vel, LSL_Rotation rot, int param, bool atRoot)
  2851. {
  2852. if (string.IsNullOrEmpty(inventory) || Double.IsNaN(rot.x) || Double.IsNaN(rot.y) || Double.IsNaN(rot.z) || Double.IsNaN(rot.s))
  2853. return;
  2854. if (VecDistSquare(llGetPos(), pos) > m_Script10mDistanceSquare)
  2855. return;
  2856. TaskInventoryItem item = m_host.Inventory.GetInventoryItem(inventory);
  2857. if (item == null)
  2858. {
  2859. Error("llRez(AtRoot/Object)", "Can't find object '" + inventory + "'");
  2860. return;
  2861. }
  2862. if (item.InvType != (int)InventoryType.Object)
  2863. {
  2864. Error("llRez(AtRoot/Object)", "Can't create requested object; object is missing from database");
  2865. return;
  2866. }
  2867. Util.FireAndForget(x =>
  2868. {
  2869. Quaternion wrot = rot;
  2870. wrot.Normalize();
  2871. List<SceneObjectGroup> new_groups = World.RezObject(m_host, item, pos, wrot, vel, param, atRoot);
  2872. // If either of these are null, then there was an unknown error.
  2873. if (new_groups == null)
  2874. return;
  2875. bool notAttachment = !m_host.ParentGroup.IsAttachment;
  2876. foreach (SceneObjectGroup group in new_groups)
  2877. {
  2878. // objects rezzed with this method are die_at_edge by default.
  2879. group.RootPart.SetDieAtEdge(true);
  2880. group.ResumeScripts();
  2881. m_ScriptEngine.PostObjectEvent(m_host.LocalId, new EventParams(
  2882. "object_rez", new Object[] {
  2883. new LSL_String(
  2884. group.RootPart.UUID.ToString()) },
  2885. Array.Empty<DetectParams>()));
  2886. if (notAttachment)
  2887. {
  2888. float groupmass = group.GetMass();
  2889. PhysicsActor pa = group.RootPart.PhysActor;
  2890. //Recoil.
  2891. if (pa != null && pa.IsPhysical && !((Vector3)vel).IsZero())
  2892. {
  2893. Vector3 recoil = -vel * groupmass * m_recoilScaleFactor;
  2894. if (!recoil.IsZero())
  2895. {
  2896. llApplyImpulse(recoil, 0);
  2897. }
  2898. }
  2899. }
  2900. }
  2901. }, null, "LSL_Api.doObjectRez");
  2902. //ScriptSleep((int)((groupmass * velmag) / 10));
  2903. ScriptSleep(m_sleepMsOnRezAtRoot);
  2904. }
  2905. public void llRezObject(string inventory, LSL_Vector pos, LSL_Vector vel, LSL_Rotation rot, int param)
  2906. {
  2907. doObjectRez(inventory, pos, vel, rot, param, false);
  2908. }
  2909. public void llLookAt(LSL_Vector target, double strength, double damping)
  2910. {
  2911. SceneObjectGroup sog = m_host.ParentGroup;
  2912. if (sog is null || sog.IsDeleted)
  2913. return;
  2914. // Get the normalized vector to the target
  2915. LSL_Vector from = llGetPos();
  2916. // normalized direction to target
  2917. LSL_Vector dir = llVecNorm(target - from);
  2918. LSL_Vector left = new(-dir.y, dir.x, 0.0f);
  2919. left = llVecNorm(left);
  2920. // make up orthogonal to left and dir
  2921. LSL_Vector up = LSL_Vector.Cross(dir, left);
  2922. // compute rotation based on orthogonal axes
  2923. // and rotate so Z points to target with X below horizont
  2924. LSL_Rotation rot = new LSL_Rotation(0.0, 0.707107, 0.0, 0.707107) * llAxes2Rot(dir, left, up);
  2925. if (!sog.UsesPhysics || sog.IsAttachment)
  2926. {
  2927. // Do nothing if either value is 0 (this has been checked in SL)
  2928. if (strength <= 0.0 || damping <= 0.0)
  2929. return;
  2930. llSetLocalRot(rot);
  2931. }
  2932. else
  2933. {
  2934. if (strength == 0)
  2935. {
  2936. llSetLocalRot(rot);
  2937. return;
  2938. }
  2939. sog.StartLookAt(rot, (float)strength, (float)damping);
  2940. }
  2941. }
  2942. public void llStopLookAt()
  2943. {
  2944. m_host.StopLookAt();
  2945. }
  2946. public void llSetTimerEvent(double sec)
  2947. {
  2948. if (sec != 0.0 && sec < m_MinTimerInterval)
  2949. sec = m_MinTimerInterval;
  2950. // Setting timer repeat
  2951. m_AsyncCommands.TimerPlugin.SetTimerEvent(m_host.LocalId, m_item.ItemID, sec);
  2952. }
  2953. public virtual void llSleep(double sec)
  2954. {
  2955. // m_log.Info("llSleep snoozing " + sec + "s.");
  2956. Sleep((int)(sec * 1000));
  2957. }
  2958. public LSL_Float llGetMass()
  2959. {
  2960. if (m_host.ParentGroup.IsAttachment)
  2961. {
  2962. ScenePresence attachedAvatar = World.GetScenePresence(m_host.ParentGroup.AttachedAvatar);
  2963. return attachedAvatar is null ? 0 : attachedAvatar.GetMass();
  2964. }
  2965. else
  2966. return m_host.ParentGroup.GetMass();
  2967. }
  2968. public LSL_Float llGetMassMKS()
  2969. {
  2970. return 100f * llGetMass();
  2971. }
  2972. public void llCollisionFilter(LSL_String name, LSL_Key id, LSL_Integer accept)
  2973. {
  2974. _ = UUID.TryParse(id, out UUID objectID);
  2975. if(objectID.IsZero())
  2976. m_host.SetCollisionFilter(accept != 0, name.m_string.ToLower(CultureInfo.InvariantCulture), string.Empty);
  2977. else
  2978. m_host.SetCollisionFilter(accept != 0, name.m_string.ToLower(CultureInfo.InvariantCulture), objectID.ToString());
  2979. }
  2980. public void llTakeControls(int controls, int accept, int pass_on)
  2981. {
  2982. if (!m_item.PermsGranter.IsZero())
  2983. {
  2984. ScenePresence presence = World.GetScenePresence(m_item.PermsGranter);
  2985. if (presence != null)
  2986. {
  2987. if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0)
  2988. {
  2989. presence.RegisterControlEventsToScript(controls, accept, pass_on, m_host.LocalId, m_item.ItemID);
  2990. }
  2991. }
  2992. }
  2993. }
  2994. public void llReleaseControls()
  2995. {
  2996. if (!m_item.PermsGranter.IsZero())
  2997. {
  2998. ScenePresence presence = World.GetScenePresence(m_item.PermsGranter);
  2999. if (presence != null)
  3000. {
  3001. if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0)
  3002. {
  3003. // Unregister controls from Presence
  3004. presence.UnRegisterControlEventsToScript(m_host.LocalId, m_item.ItemID);
  3005. // Remove Take Control permission.
  3006. m_item.PermsMask &= ~ScriptBaseClass.PERMISSION_TAKE_CONTROLS;
  3007. }
  3008. }
  3009. }
  3010. }
  3011. public void llReleaseURL(string url)
  3012. {
  3013. m_UrlModule?.ReleaseURL(url);
  3014. }
  3015. /// <summary>
  3016. /// Attach the object containing this script to the avatar that owns it.
  3017. /// </summary>
  3018. /// <param name='attachmentPoint'>
  3019. /// The attachment point (e.g. <see cref="OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass.ATTACH_CHEST">ATTACH_CHEST</see>)
  3020. /// </param>
  3021. /// <returns>true if the attach suceeded, false if it did not</returns>
  3022. public bool AttachToAvatar(int attachmentPoint)
  3023. {
  3024. SceneObjectGroup grp = m_host.ParentGroup;
  3025. ScenePresence presence = World.GetScenePresence(m_host.OwnerID);
  3026. IAttachmentsModule attachmentsModule = m_ScriptEngine.World.AttachmentsModule;
  3027. if (attachmentsModule != null)
  3028. return attachmentsModule.AttachObject(presence, grp, (uint)attachmentPoint, false, true, true);
  3029. else
  3030. return false;
  3031. }
  3032. /// <summary>
  3033. /// Detach the object containing this script from the avatar it is attached to.
  3034. /// </summary>
  3035. /// <remarks>
  3036. /// Nothing happens if the object is not attached.
  3037. /// </remarks>
  3038. public void DetachFromAvatar()
  3039. {
  3040. Util.FireAndForget(DetachWrapper, m_host, "LSL_Api.DetachFromAvatar");
  3041. }
  3042. private void DetachWrapper(object o)
  3043. {
  3044. if (World.AttachmentsModule != null)
  3045. {
  3046. SceneObjectPart host = (SceneObjectPart)o;
  3047. ScenePresence presence = World.GetScenePresence(host.OwnerID);
  3048. World.AttachmentsModule.DetachSingleAttachmentToInv(presence, host.ParentGroup);
  3049. }
  3050. }
  3051. public void llAttachToAvatar(LSL_Integer attachmentPoint)
  3052. {
  3053. if (m_item.PermsGranter != m_host.OwnerID)
  3054. return;
  3055. SceneObjectGroup grp = m_host.ParentGroup;
  3056. if (grp == null || grp.IsDeleted || grp.IsAttachment)
  3057. return;
  3058. if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_ATTACH) != 0)
  3059. AttachToAvatar(attachmentPoint);
  3060. }
  3061. public void llAttachToAvatarTemp(LSL_Integer attachmentPoint)
  3062. {
  3063. IAttachmentsModule attachmentsModule = World.RequestModuleInterface<IAttachmentsModule>();
  3064. if (attachmentsModule == null)
  3065. return;
  3066. if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_ATTACH) == 0)
  3067. return;
  3068. SceneObjectGroup grp = m_host.ParentGroup;
  3069. if (grp == null || grp.IsDeleted || grp.IsAttachment)
  3070. return;
  3071. if (!World.TryGetScenePresence(m_item.PermsGranter, out ScenePresence target))
  3072. return;
  3073. if (target.UUID != grp.OwnerID)
  3074. {
  3075. uint effectivePerms = grp.EffectiveOwnerPerms;
  3076. if ((effectivePerms & (uint)PermissionMask.Transfer) == 0)
  3077. return;
  3078. UUID permsgranter = m_item.PermsGranter;
  3079. int permsmask = m_item.PermsMask;
  3080. grp.SetOwner(target.UUID, target.ControllingClient.ActiveGroupId);
  3081. if (World.Permissions.PropagatePermissions())
  3082. {
  3083. foreach (SceneObjectPart child in grp.Parts)
  3084. {
  3085. child.Inventory.ChangeInventoryOwner(target.UUID);
  3086. child.TriggerScriptChangedEvent(Changed.OWNER);
  3087. child.ApplyNextOwnerPermissions();
  3088. }
  3089. grp.InvalidateEffectivePerms();
  3090. }
  3091. m_item.PermsMask = permsmask;
  3092. m_item.PermsGranter = permsgranter;
  3093. grp.RootPart.ObjectSaleType = 0;
  3094. grp.RootPart.SalePrice = 10;
  3095. grp.HasGroupChanged = true;
  3096. grp.RootPart.SendPropertiesToClient(target.ControllingClient);
  3097. grp.RootPart.ScheduleFullUpdate();
  3098. }
  3099. attachmentsModule.AttachObject(target, grp, (uint)attachmentPoint, false, false, true);
  3100. }
  3101. public void llDetachFromAvatar()
  3102. {
  3103. if (m_host.ParentGroup.AttachmentPoint == 0)
  3104. return;
  3105. if (m_item.PermsGranter != m_host.OwnerID)
  3106. return;
  3107. if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_ATTACH) != 0)
  3108. DetachFromAvatar();
  3109. }
  3110. public void llTakeCamera(string avatar)
  3111. {
  3112. Deprecated("llTakeCamera", "Use llSetCameraParams instead");
  3113. }
  3114. public void llReleaseCamera(string avatar)
  3115. {
  3116. Deprecated("llReleaseCamera", "Use llClearCameraParams instead");
  3117. }
  3118. public LSL_Key llGetOwner()
  3119. {
  3120. return m_host.OwnerID.ToString();
  3121. }
  3122. public void llInstantMessage(string userKey, string message)
  3123. {
  3124. if (m_TransferModule == null || String.IsNullOrEmpty(message))
  3125. return;
  3126. if (!UUID.TryParse(userKey, out UUID userID) || userID.IsZero())
  3127. {
  3128. Error("llInstantMessage","An invalid key was passed to llInstantMessage");
  3129. ScriptSleep(2000);
  3130. return;
  3131. }
  3132. Vector3 pos = m_host.AbsolutePosition;
  3133. GridInstantMessage msg = new()
  3134. {
  3135. fromAgentID = m_host.OwnerID.Guid,
  3136. toAgentID = userID.Guid,
  3137. imSessionID = m_host.UUID.Guid, // This is the item we're mucking with here
  3138. timestamp = (uint)Util.UnixTimeSinceEpoch(),
  3139. fromAgentName = m_host.Name, //client.FirstName + " " + client.LastName;// fromAgentName;
  3140. dialog = 19, // MessageFromObject
  3141. fromGroup = false,
  3142. offline = 0,
  3143. ParentEstateID = World.RegionInfo.EstateSettings.EstateID,
  3144. Position = pos,
  3145. RegionID = World.RegionInfo.RegionID.Guid,
  3146. message = (message.Length > 1024) ? message[..1024] : message,
  3147. binaryBucket = Util.StringToBytes256($"{m_regionName}/{(int)pos.X}/{(int)pos.Y}/{(int)pos.Z}")
  3148. };
  3149. m_TransferModule?.SendInstantMessage(msg, delegate(bool success) {});
  3150. ScriptSleep(m_sleepMsOnInstantMessage);
  3151. }
  3152. public void llEmail(string address, string subject, string message)
  3153. {
  3154. if (m_emailModule == null)
  3155. {
  3156. Error("llEmail", "Email module not configured");
  3157. return;
  3158. }
  3159. // this is a fire and forget no event is sent to script
  3160. void act(string eventID)
  3161. {
  3162. //Restrict email destination to the avatars registered email address?
  3163. //The restriction only applies if the destination address is not local.
  3164. if (m_restrictEmail == true && address.Contains(m_internalObjectHost) == false)
  3165. {
  3166. UserAccount account = m_userAccountService.GetUserAccount(RegionScopeID, m_host.OwnerID);
  3167. if (account == null)
  3168. return;
  3169. if (String.IsNullOrEmpty(account.Email))
  3170. return;
  3171. address = account.Email;
  3172. }
  3173. m_emailModule.SendEmail(m_host.UUID, m_host.ParentGroup.OwnerID, address, subject, message);
  3174. // no dataserver event
  3175. }
  3176. m_AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId,
  3177. m_item.ItemID, act);
  3178. ScriptSleep(m_sleepMsOnEmail);
  3179. }
  3180. public void llGetNextEmail(string address, string subject)
  3181. {
  3182. if (m_emailModule == null)
  3183. {
  3184. Error("llGetNextEmail", "Email module not configured");
  3185. return;
  3186. }
  3187. Email email;
  3188. email = m_emailModule.GetNextEmail(m_host.UUID, address, subject);
  3189. if (email == null)
  3190. return;
  3191. m_ScriptEngine.PostObjectEvent(m_host.LocalId,
  3192. new EventParams("email",
  3193. new Object[] {
  3194. new LSL_String(email.time),
  3195. new LSL_String(email.sender),
  3196. new LSL_String(email.subject),
  3197. new LSL_String(email.message),
  3198. new LSL_Integer(email.numLeft)},
  3199. Array.Empty<DetectParams>()));
  3200. }
  3201. public void llTargetedEmail(LSL_Integer target, LSL_String subject, LSL_String message)
  3202. {
  3203. SceneObjectGroup parent = m_host.ParentGroup;
  3204. if (parent == null || parent.IsDeleted)
  3205. return;
  3206. if (m_emailModule == null)
  3207. {
  3208. Error("llTargetedEmail", "Email module not configured");
  3209. return;
  3210. }
  3211. if (subject.Length + message.Length > 4096)
  3212. {
  3213. Error("llTargetedEmail", "Message is too large");
  3214. return;
  3215. }
  3216. // this is a fire and forget no event is sent to script
  3217. void act(string eventID)
  3218. {
  3219. UserAccount account = null;
  3220. if (target == ScriptBaseClass.TARGETED_EMAIL_OBJECT_OWNER)
  3221. {
  3222. if (parent.OwnerID.Equals(parent.GroupID))
  3223. return;
  3224. account = m_userAccountService.GetUserAccount(RegionScopeID, parent.OwnerID);
  3225. }
  3226. else if (target == ScriptBaseClass.TARGETED_EMAIL_ROOT_CREATOR)
  3227. {
  3228. // non standard avoid creator spam
  3229. if (m_item.CreatorID.Equals(parent.RootPart.CreatorID))
  3230. account = m_userAccountService.GetUserAccount(RegionScopeID, parent.RootPart.CreatorID);
  3231. else
  3232. return;
  3233. }
  3234. else
  3235. return;
  3236. if (account == null)
  3237. return;
  3238. if (String.IsNullOrEmpty(account.Email))
  3239. return;
  3240. m_emailModule.SendEmail(m_host.UUID, m_host.ParentGroup.OwnerID, account.Email, subject, message);
  3241. }
  3242. m_AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId,
  3243. m_item.ItemID, act);
  3244. ScriptSleep(m_sleepMsOnEmail);
  3245. }
  3246. public LSL_Key llGetKey()
  3247. {
  3248. return m_host.UUID.ToString();
  3249. }
  3250. public LSL_Key llGenerateKey()
  3251. {
  3252. return UUID.Random().ToString();
  3253. }
  3254. public void llSetBuoyancy(double buoyancy)
  3255. {
  3256. if (!m_host.ParentGroup.IsDeleted)
  3257. {
  3258. m_host.ParentGroup.RootPart.SetBuoyancy((float)buoyancy);
  3259. }
  3260. }
  3261. /// <summary>
  3262. /// Attempt to clamp the object on the Z axis at the given height over tau seconds.
  3263. /// </summary>
  3264. /// <param name="height">Height to hover. Height of zero disables hover.</param>
  3265. /// <param name="water">False if height is calculated just from ground, otherwise uses ground or water depending on whichever is higher</param>
  3266. /// <param name="tau">Number of seconds over which to reach target</param>
  3267. public void llSetHoverHeight(double height, int water, double tau)
  3268. {
  3269. PIDHoverType hoverType = PIDHoverType.Ground;
  3270. if (water != 0)
  3271. {
  3272. hoverType = PIDHoverType.GroundAndWater;
  3273. }
  3274. m_host.SetHoverHeight((float)height, hoverType, (float)tau);
  3275. }
  3276. public void llStopHover()
  3277. {
  3278. m_host.SetHoverHeight(0f, PIDHoverType.Ground, 0f);
  3279. }
  3280. public void llMinEventDelay(double delay)
  3281. {
  3282. try
  3283. {
  3284. m_ScriptEngine.SetMinEventDelay(m_item.ItemID, delay);
  3285. }
  3286. catch (NotImplementedException)
  3287. {
  3288. // Currently not implemented in DotNetEngine only XEngine
  3289. NotImplemented("llMinEventDelay", "In DotNetEngine");
  3290. }
  3291. }
  3292. public void llSoundPreload(string sound)
  3293. {
  3294. Deprecated("llSoundPreload", "Use llPreloadSound instead");
  3295. }
  3296. public void llRotLookAt(LSL_Rotation target, double strength, double damping)
  3297. {
  3298. // Per discussion with Melanie, for non-physical objects llLookAt appears to simply
  3299. // set the rotation of the object, copy that behavior
  3300. SceneObjectGroup sog = m_host.ParentGroup;
  3301. if(sog == null || sog.IsDeleted)
  3302. return;
  3303. if (strength == 0 || !sog.UsesPhysics || sog.IsAttachment)
  3304. {
  3305. llSetLocalRot(target);
  3306. }
  3307. else
  3308. {
  3309. sog.RotLookAt(target, (float)strength, (float)damping);
  3310. }
  3311. }
  3312. public LSL_Integer llStringLength(string str)
  3313. {
  3314. if(str == null || str.Length <= 0)
  3315. return 0;
  3316. return str.Length;
  3317. }
  3318. public void llStartAnimation(string anim)
  3319. {
  3320. if (m_item.PermsGranter.IsZero())
  3321. return;
  3322. if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION) != 0)
  3323. {
  3324. ScenePresence presence = World.GetScenePresence(m_item.PermsGranter);
  3325. if (presence is not null)
  3326. {
  3327. // Do NOT try to parse UUID, animations cannot be triggered by ID
  3328. UUID animID = ScriptUtils.GetAssetIdFromItemName(m_host, anim, (int)AssetType.Animation);
  3329. if (animID.IsZero())
  3330. presence.Animator.AddAnimation(anim, m_host.UUID);
  3331. else
  3332. presence.Animator.AddAnimation(animID, m_host.UUID);
  3333. }
  3334. }
  3335. }
  3336. public void llStopAnimation(string anim)
  3337. {
  3338. if (m_item.PermsGranter.IsZero())
  3339. return;
  3340. if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION) != 0)
  3341. {
  3342. ScenePresence presence = World.GetScenePresence(m_item.PermsGranter);
  3343. if (presence is not null)
  3344. {
  3345. UUID animID = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, anim);
  3346. if (animID.IsNotZero())
  3347. presence.Animator.RemoveAnimation(animID, true);
  3348. else if (presence.TryGetAnimationOverride(anim.ToUpper(), out UUID sitanimID))
  3349. presence.Animator.RemoveAnimation(sitanimID, true);
  3350. else
  3351. presence.Animator.RemoveAnimation(anim);
  3352. }
  3353. }
  3354. }
  3355. public void llStartObjectAnimation(string anim)
  3356. {
  3357. // Do NOT try to parse UUID, animations cannot be triggered by ID
  3358. UUID animID = ScriptUtils.GetAssetIdFromItemName(m_host, anim, (int)AssetType.Animation);
  3359. if (animID.IsZero())
  3360. animID = DefaultAvatarAnimations.GetDefaultAnimation(anim);
  3361. if (animID.IsNotZero())
  3362. m_host.AddAnimation(animID, anim);
  3363. }
  3364. public void llStopObjectAnimation(string anim)
  3365. {
  3366. m_host.RemoveAnimation(anim);
  3367. }
  3368. public LSL_List llGetObjectAnimationNames()
  3369. {
  3370. LSL_List ret = new();
  3371. if(m_host.AnimationsNames is null || m_host.AnimationsNames.Count == 0)
  3372. return ret;
  3373. foreach (string name in m_host.AnimationsNames.Values)
  3374. ret.Add(new LSL_String(name));
  3375. return ret;
  3376. }
  3377. public void llPointAt(LSL_Vector pos)
  3378. {
  3379. }
  3380. public void llStopPointAt()
  3381. {
  3382. }
  3383. public void llTargetOmega(LSL_Vector axis, double spinrate, double gain)
  3384. {
  3385. TargetOmega(m_host, axis, (float)spinrate, (float)gain);
  3386. }
  3387. protected static void TargetOmega(SceneObjectPart part, LSL_Vector axis, float spinrate, float gain)
  3388. {
  3389. if(MathF.Abs(gain) < 1e-6f)
  3390. {
  3391. part.UpdateAngularVelocity(Vector3.Zero);
  3392. part.ScheduleFullAnimUpdate();
  3393. }
  3394. else
  3395. part.UpdateAngularVelocity((Vector3)axis * spinrate);
  3396. }
  3397. public LSL_Integer llGetStartParameter()
  3398. {
  3399. return m_ScriptEngine.GetStartParameter(m_item.ItemID);
  3400. }
  3401. public void llRequestPermissions(string agent, int perm)
  3402. {
  3403. if (!UUID.TryParse(agent, out UUID agentID) || agentID.IsZero())
  3404. return;
  3405. if (agentID.IsZero() || perm == 0) // Releasing permissions
  3406. {
  3407. llReleaseControls();
  3408. m_item.PermsGranter = UUID.Zero;
  3409. m_item.PermsMask = 0;
  3410. m_ScriptEngine.PostScriptEvent(m_item.ItemID, new EventParams(
  3411. "run_time_permissions", new Object[] {
  3412. new LSL_Integer(0) },
  3413. Array.Empty<DetectParams>()));
  3414. return;
  3415. }
  3416. if (m_item.PermsGranter != agentID || (perm & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) == 0)
  3417. llReleaseControls();
  3418. int implicitPerms = 0;
  3419. if (m_host.ParentGroup.IsAttachment && (UUID)agent == m_host.ParentGroup.AttachedAvatar)
  3420. {
  3421. // When attached, certain permissions are implicit if requested from owner
  3422. implicitPerms = ScriptBaseClass.PERMISSION_TAKE_CONTROLS |
  3423. ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION |
  3424. ScriptBaseClass.PERMISSION_CONTROL_CAMERA |
  3425. ScriptBaseClass.PERMISSION_TRACK_CAMERA |
  3426. ScriptBaseClass.PERMISSION_ATTACH |
  3427. ScriptBaseClass.PERMISSION_OVERRIDE_ANIMATIONS;
  3428. }
  3429. else
  3430. {
  3431. if (m_host.ParentGroup.HasSittingAvatar(agentID))
  3432. {
  3433. // When agent is sitting, certain permissions are implicit if requested from sitting agent
  3434. implicitPerms = ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION |
  3435. ScriptBaseClass.PERMISSION_CONTROL_CAMERA |
  3436. ScriptBaseClass.PERMISSION_TRACK_CAMERA |
  3437. ScriptBaseClass.PERMISSION_TAKE_CONTROLS;
  3438. }
  3439. else
  3440. {
  3441. if (World.GetExtraSetting("auto_grant_attach_perms") == "true")
  3442. implicitPerms = ScriptBaseClass.PERMISSION_ATTACH;
  3443. }
  3444. if (World.GetExtraSetting("auto_grant_all_perms") == "true")
  3445. {
  3446. implicitPerms = perm;
  3447. }
  3448. }
  3449. if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms
  3450. {
  3451. m_host.TaskInventory.LockItemsForWrite(true);
  3452. m_host.TaskInventory[m_item.ItemID].PermsGranter = agentID;
  3453. m_host.TaskInventory[m_item.ItemID].PermsMask = perm;
  3454. m_host.TaskInventory.LockItemsForWrite(false);
  3455. m_ScriptEngine.PostScriptEvent(m_item.ItemID, new EventParams(
  3456. "run_time_permissions", new Object[] {
  3457. new LSL_Integer(perm) },
  3458. Array.Empty<DetectParams>()));
  3459. return;
  3460. }
  3461. ScenePresence presence = World.GetScenePresence(agentID);
  3462. if (presence != null)
  3463. {
  3464. // If permissions are being requested from an NPC and were not implicitly granted above then
  3465. // auto grant all requested permissions if the script is owned by the NPC or the NPCs owner
  3466. INPCModule npcModule = World.RequestModuleInterface<INPCModule>();
  3467. if (npcModule != null && npcModule.IsNPC(agentID, World))
  3468. {
  3469. if (npcModule.CheckPermissions(agentID, m_host.OwnerID))
  3470. {
  3471. lock (m_host.TaskInventory)
  3472. {
  3473. m_host.TaskInventory[m_item.ItemID].PermsGranter = agentID;
  3474. m_host.TaskInventory[m_item.ItemID].PermsMask = perm;
  3475. }
  3476. m_ScriptEngine.PostScriptEvent(
  3477. m_item.ItemID,
  3478. new EventParams(
  3479. "run_time_permissions", new Object[] { new LSL_Integer(perm) }, Array.Empty<DetectParams>()));
  3480. }
  3481. // it is an NPC, exit even if the permissions werent granted above, they are not going to answer
  3482. // the question!
  3483. return;
  3484. }
  3485. string ownerName = resolveName(m_host.ParentGroup.RootPart.OwnerID);
  3486. if (ownerName == String.Empty)
  3487. ownerName = "(hippos)";
  3488. if (!m_waitingForScriptAnswer)
  3489. {
  3490. m_host.TaskInventory.LockItemsForWrite(true);
  3491. m_host.TaskInventory[m_item.ItemID].PermsGranter = agentID;
  3492. m_host.TaskInventory[m_item.ItemID].PermsMask = 0;
  3493. m_host.TaskInventory.LockItemsForWrite(false);
  3494. presence.ControllingClient.OnScriptAnswer += handleScriptAnswer;
  3495. m_waitingForScriptAnswer=true;
  3496. }
  3497. presence.ControllingClient.SendScriptQuestion(
  3498. m_host.UUID, m_host.ParentGroup.RootPart.Name, ownerName, m_item.ItemID, perm);
  3499. return;
  3500. }
  3501. // Requested agent is not in range, refuse perms
  3502. m_ScriptEngine.PostScriptEvent(
  3503. m_item.ItemID,
  3504. new EventParams("run_time_permissions", new Object[] { new LSL_Integer(0) }, Array.Empty<DetectParams>()));
  3505. }
  3506. void handleScriptAnswer(IClientAPI client, UUID taskID, UUID itemID, int answer)
  3507. {
  3508. if (taskID != m_host.UUID)
  3509. return;
  3510. client.OnScriptAnswer -= handleScriptAnswer;
  3511. m_waitingForScriptAnswer = false;
  3512. if ((answer & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) == 0)
  3513. llReleaseControls();
  3514. m_host.TaskInventory.LockItemsForWrite(true);
  3515. m_host.TaskInventory[m_item.ItemID].PermsMask = answer;
  3516. m_host.TaskInventory.LockItemsForWrite(false);
  3517. m_ScriptEngine.PostScriptEvent(m_item.ItemID, new EventParams(
  3518. "run_time_permissions", new Object[] {
  3519. new LSL_Integer(answer) },
  3520. Array.Empty<DetectParams>()));
  3521. }
  3522. public LSL_Key llGetPermissionsKey()
  3523. {
  3524. return m_item.PermsGranter.ToString();
  3525. }
  3526. public LSL_Integer llGetPermissions()
  3527. {
  3528. int perms = m_item.PermsMask;
  3529. if (m_automaticLinkPermission)
  3530. perms |= ScriptBaseClass.PERMISSION_CHANGE_LINKS;
  3531. return perms;
  3532. }
  3533. public LSL_Integer llGetLinkNumber()
  3534. {
  3535. if (m_host.ParentGroup.PrimCount > 1)
  3536. {
  3537. return m_host.LinkNum;
  3538. }
  3539. else
  3540. {
  3541. return 0;
  3542. }
  3543. }
  3544. public void llSetLinkColor(int linknumber, LSL_Vector color, int face)
  3545. {
  3546. List<SceneObjectPart> parts = GetLinkParts(linknumber);
  3547. if (parts.Count > 0)
  3548. {
  3549. try
  3550. {
  3551. foreach (SceneObjectPart part in parts)
  3552. part.SetFaceColorAlpha(face, color, null);
  3553. }
  3554. finally { }
  3555. }
  3556. }
  3557. public void llCreateLink(LSL_Key target, LSL_Integer parent)
  3558. {
  3559. if (!m_automaticLinkPermission)
  3560. {
  3561. if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0)
  3562. {
  3563. Error("llCreateLink", "PERMISSION_CHANGE_LINKS required");
  3564. return;
  3565. }
  3566. if (m_item.PermsGranter.NotEqual(m_host.ParentGroup.OwnerID))
  3567. {
  3568. Error("llCreateLink", "PERMISSION_CHANGE_LINKS not set by script owner");
  3569. return;
  3570. }
  3571. }
  3572. CreateLink(target, parent);
  3573. }
  3574. public void CreateLink(string target, int parent)
  3575. {
  3576. if (!UUID.TryParse(target, out UUID targetID) || targetID.IsZero())
  3577. return;
  3578. SceneObjectGroup hostgroup = m_host.ParentGroup;
  3579. if (hostgroup.AttachmentPoint != 0)
  3580. return; // Fail silently if attached
  3581. if ((hostgroup.RootPart.OwnerMask & (uint)PermissionMask.Modify) == 0)
  3582. return;
  3583. SceneObjectPart targetPart = World.GetSceneObjectPart(targetID);
  3584. if (targetPart == null)
  3585. return;
  3586. SceneObjectGroup targetgrp = targetPart.ParentGroup;
  3587. if (targetgrp == null || targetgrp.OwnerID.NotEqual(hostgroup.OwnerID))
  3588. return;
  3589. if (targetgrp.AttachmentPoint != 0)
  3590. return; // Fail silently if attached
  3591. if ((targetgrp.RootPart.OwnerMask & (uint)PermissionMask.Modify) == 0)
  3592. return;
  3593. SceneObjectGroup parentPrim, childPrim;
  3594. if (parent != 0)
  3595. {
  3596. parentPrim = hostgroup;
  3597. childPrim = targetgrp;
  3598. }
  3599. else
  3600. {
  3601. parentPrim = targetgrp;
  3602. childPrim = hostgroup;
  3603. }
  3604. // Required for linking
  3605. childPrim.RootPart.ClearUpdateSchedule();
  3606. parentPrim.LinkToGroup(childPrim, true);
  3607. parentPrim.TriggerScriptChangedEvent(Changed.LINK);
  3608. parentPrim.RootPart.CreateSelected = false;
  3609. parentPrim.HasGroupChanged = true;
  3610. parentPrim.ScheduleGroupForFullUpdate();
  3611. IClientAPI client = null;
  3612. ScenePresence sp = World.GetScenePresence(m_host.OwnerID);
  3613. if (sp != null)
  3614. client = sp.ControllingClient;
  3615. if (client != null)
  3616. parentPrim.SendPropertiesToClient(client);
  3617. ScriptSleep(m_sleepMsOnCreateLink);
  3618. }
  3619. public void llBreakLink(int linknum)
  3620. {
  3621. if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0
  3622. && !m_automaticLinkPermission)
  3623. {
  3624. Error("llBreakLink", "PERMISSION_CHANGE_LINKS permission not set");
  3625. return;
  3626. }
  3627. BreakLink(linknum);
  3628. }
  3629. public void BreakLink(int linknum)
  3630. {
  3631. if (linknum < ScriptBaseClass.LINK_THIS)
  3632. return;
  3633. SceneObjectGroup parentSOG = m_host.ParentGroup;
  3634. if (parentSOG.AttachmentPoint != 0)
  3635. return; // Fail silently if attached
  3636. if ((parentSOG.RootPart.OwnerMask & (uint)PermissionMask.Modify) == 0)
  3637. return;
  3638. SceneObjectPart childPrim = null;
  3639. switch (linknum)
  3640. {
  3641. case ScriptBaseClass.LINK_ROOT:
  3642. case ScriptBaseClass.LINK_SET:
  3643. case ScriptBaseClass.LINK_ALL_OTHERS:
  3644. case ScriptBaseClass.LINK_ALL_CHILDREN:
  3645. break;
  3646. case ScriptBaseClass.LINK_THIS: // not as spec
  3647. childPrim = m_host;
  3648. break;
  3649. default:
  3650. childPrim = parentSOG.GetLinkNumPart(linknum);
  3651. break;
  3652. }
  3653. if (linknum == ScriptBaseClass.LINK_ROOT)
  3654. {
  3655. List<ScenePresence> avs = parentSOG.GetSittingAvatars();
  3656. foreach (ScenePresence av in avs)
  3657. av.StandUp();
  3658. List<SceneObjectPart> parts = new(parentSOG.Parts);
  3659. parts.Remove(parentSOG.RootPart);
  3660. if (parts.Count > 0)
  3661. {
  3662. try
  3663. {
  3664. foreach (SceneObjectPart part in parts)
  3665. {
  3666. parentSOG.DelinkFromGroup(part.LocalId, true);
  3667. }
  3668. }
  3669. finally { }
  3670. }
  3671. parentSOG.HasGroupChanged = true;
  3672. parentSOG.ScheduleGroupForFullUpdate();
  3673. parentSOG.TriggerScriptChangedEvent(Changed.LINK);
  3674. if (parts.Count > 0)
  3675. {
  3676. SceneObjectPart newRoot = parts[0];
  3677. parts.Remove(newRoot);
  3678. try
  3679. {
  3680. foreach (SceneObjectPart part in parts)
  3681. {
  3682. part.ClearUpdateSchedule();
  3683. newRoot.ParentGroup.LinkToGroup(part.ParentGroup);
  3684. }
  3685. }
  3686. finally { }
  3687. newRoot.ParentGroup.HasGroupChanged = true;
  3688. newRoot.ParentGroup.ScheduleGroupForFullUpdate();
  3689. }
  3690. }
  3691. else
  3692. {
  3693. if (childPrim == null)
  3694. return;
  3695. List<ScenePresence> avs = parentSOG.GetSittingAvatars();
  3696. foreach (ScenePresence av in avs)
  3697. av.StandUp();
  3698. parentSOG.DelinkFromGroup(childPrim.LocalId, true);
  3699. }
  3700. }
  3701. public void llBreakAllLinks()
  3702. {
  3703. TaskInventoryItem item = m_item;
  3704. if ((item.PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0
  3705. && !m_automaticLinkPermission)
  3706. {
  3707. Error("llBreakAllLinks","Script trying to link but PERMISSION_CHANGE_LINKS permission not set!");
  3708. return;
  3709. }
  3710. BreakAllLinks();
  3711. }
  3712. public void BreakAllLinks()
  3713. {
  3714. SceneObjectGroup parentPrim = m_host.ParentGroup;
  3715. if (parentPrim.AttachmentPoint != 0)
  3716. return; // Fail silently if attached
  3717. List<SceneObjectPart> parts = new(parentPrim.Parts);
  3718. parts.Remove(parentPrim.RootPart);
  3719. foreach (SceneObjectPart part in parts)
  3720. {
  3721. parentPrim.DelinkFromGroup(part.LocalId, true);
  3722. parentPrim.TriggerScriptChangedEvent(Changed.LINK);
  3723. }
  3724. parentPrim.HasGroupChanged = true;
  3725. parentPrim.ScheduleGroupForFullUpdate();
  3726. }
  3727. public LSL_Key llGetLinkKey(int linknum)
  3728. {
  3729. if (linknum < 0)
  3730. {
  3731. if (linknum == ScriptBaseClass.LINK_THIS)
  3732. return m_host.UUID.ToString();
  3733. return ScriptBaseClass.NULL_KEY;
  3734. }
  3735. SceneObjectGroup sog = m_host.ParentGroup;
  3736. if (linknum < 2)
  3737. return sog.RootPart.UUID.ToString();
  3738. SceneObjectPart part = sog.GetLinkNumPart(linknum);
  3739. if (part is not null)
  3740. {
  3741. return part.UUID.ToString();
  3742. }
  3743. else
  3744. {
  3745. if (linknum > sog.PrimCount)
  3746. {
  3747. linknum -= sog.PrimCount + 1;
  3748. List<ScenePresence> avatars = GetLinkAvatars(ScriptBaseClass.LINK_SET, sog);
  3749. if (avatars.Count > linknum)
  3750. {
  3751. return avatars[linknum].UUID.ToString();
  3752. }
  3753. }
  3754. return ScriptBaseClass.NULL_KEY;
  3755. }
  3756. }
  3757. public LSL_Key llGetObjectLinkKey(LSL_Key objectid, int linknum)
  3758. {
  3759. if (!UUID.TryParse(objectid, out UUID oID) || oID.IsZero())
  3760. return ScriptBaseClass.NULL_KEY;
  3761. if (!World.TryGetSceneObjectPart(oID, out SceneObjectPart sop))
  3762. return ScriptBaseClass.NULL_KEY;
  3763. if (linknum < 0)
  3764. {
  3765. if (linknum == ScriptBaseClass.LINK_THIS)
  3766. return sop.UUID.ToString();
  3767. return ScriptBaseClass.NULL_KEY;
  3768. }
  3769. SceneObjectGroup sog = sop.ParentGroup;
  3770. if (linknum < 2)
  3771. return sog.RootPart.UUID.ToString();
  3772. SceneObjectPart part = sog.GetLinkNumPart(linknum);
  3773. if (part is not null)
  3774. {
  3775. return part.UUID.ToString();
  3776. }
  3777. else
  3778. {
  3779. if (linknum > sog.PrimCount)
  3780. {
  3781. linknum -= sog.PrimCount + 1;
  3782. List<ScenePresence> avatars = GetLinkAvatars(ScriptBaseClass.LINK_SET, sog);
  3783. if (avatars.Count > linknum)
  3784. {
  3785. return avatars[linknum].UUID.ToString();
  3786. }
  3787. }
  3788. return ScriptBaseClass.NULL_KEY;
  3789. }
  3790. }
  3791. /// <summary>
  3792. /// Returns the name of the child prim or seated avatar matching the
  3793. /// specified link number.
  3794. /// </summary>
  3795. /// <param name="linknum">
  3796. /// The number of a link in the linkset or a link-related constant.
  3797. /// </param>
  3798. /// <returns>
  3799. /// The name determined to match the specified link number.
  3800. /// </returns>
  3801. /// <remarks>
  3802. /// The rules governing the returned name are not simple. The only
  3803. /// time a blank name is returned is if the target prim has a blank
  3804. /// name. If no prim with the given link number can be found then
  3805. /// usually NULL_KEY is returned but there are exceptions.
  3806. ///
  3807. /// In a single unlinked prim, A call with 0 returns the name, all
  3808. /// other values for link number return NULL_KEY
  3809. ///
  3810. /// In link sets it is more complicated.
  3811. ///
  3812. /// If the script is in the root prim:-
  3813. /// A zero link number returns NULL_KEY.
  3814. /// Positive link numbers return the name of the prim, or NULL_KEY
  3815. /// if a prim does not exist at that position.
  3816. /// Negative link numbers return the name of the first child prim.
  3817. ///
  3818. /// If the script is in a child prim:-
  3819. /// Link numbers 0 or 1 return the name of the root prim.
  3820. /// Positive link numbers return the name of the prim or NULL_KEY
  3821. /// if a prim does not exist at that position.
  3822. /// Negative numbers return the name of the root prim.
  3823. ///
  3824. /// References
  3825. /// http://lslwiki.net/lslwiki/wakka.php?wakka=llGetLinkName
  3826. /// Mentions NULL_KEY being returned
  3827. /// http://wiki.secondlife.com/wiki/LlGetLinkName
  3828. /// Mentions using the LINK_* constants, some of which are negative
  3829. /// </remarks>
  3830. public LSL_String llGetLinkName(int linknum)
  3831. {
  3832. ISceneEntity entity = GetLinkEntity(m_host, linknum);
  3833. return (entity is null) ? ScriptBaseClass.NULL_KEY : entity.Name;
  3834. }
  3835. public LSL_Integer llGetInventoryNumber(int type)
  3836. {
  3837. int count = 0;
  3838. m_host.TaskInventory.LockItemsForRead(true);
  3839. foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
  3840. {
  3841. if (inv.Value.Type == type || type == -1)
  3842. count++;
  3843. }
  3844. m_host.TaskInventory.LockItemsForRead(false);
  3845. return count;
  3846. }
  3847. public LSL_String llGetInventoryName(int type, int number)
  3848. {
  3849. ArrayList keys = new();
  3850. m_host.TaskInventory.LockItemsForRead(true);
  3851. foreach (KeyValuePair<UUID, TaskInventoryItem> inv in m_host.TaskInventory)
  3852. {
  3853. if (inv.Value.Type == type || type == -1)
  3854. {
  3855. keys.Add(inv.Value.Name);
  3856. }
  3857. }
  3858. m_host.TaskInventory.LockItemsForRead(false);
  3859. if (keys.Count == 0)
  3860. {
  3861. return String.Empty;
  3862. }
  3863. keys.Sort();
  3864. if (keys.Count > number)
  3865. {
  3866. return (string)keys[number];
  3867. }
  3868. return String.Empty;
  3869. }
  3870. public LSL_Float llGetEnergy()
  3871. {
  3872. // TODO: figure out real energy value
  3873. return 1.0f;
  3874. }
  3875. public void llGiveInventory(LSL_Key destination, LSL_String inventory)
  3876. {
  3877. if (!UUID.TryParse(destination, out UUID destId) || destId.IsZero())
  3878. {
  3879. Error("llGiveInventory", "Can't parse destination key '" + destination + "'");
  3880. return;
  3881. }
  3882. TaskInventoryItem item = m_host.Inventory.GetInventoryItem(inventory);
  3883. if (item is null)
  3884. {
  3885. Error("llGiveInventory", "Can't find inventory object '" + inventory + "'");
  3886. return;
  3887. }
  3888. // check if destination is an object
  3889. if (World.TryGetSceneObjectPart(destId, out _))
  3890. {
  3891. // destination is an object
  3892. World.MoveTaskInventoryItem(destId, m_host, item.ItemID);
  3893. return;
  3894. }
  3895. ScenePresence presence = World.GetScenePresence(destId);
  3896. if (presence is null)
  3897. {
  3898. UserAccount account = m_userAccountService.GetUserAccount(RegionScopeID, destId);
  3899. if (account is null)
  3900. {
  3901. GridUserInfo info = World.GridUserService.GetGridUserInfo(destId.ToString());
  3902. if(info is null || info.Online == false)
  3903. {
  3904. Error("llGiveInventory", "Can't find destination '" + destId.ToString() + "'");
  3905. return;
  3906. }
  3907. }
  3908. }
  3909. // destination is an avatar
  3910. InventoryItemBase agentItem = World.MoveTaskInventoryItem(destId, UUID.Zero, m_host, item.ItemID, out string message);
  3911. if (agentItem is null)
  3912. {
  3913. llSay(0, message);
  3914. return;
  3915. }
  3916. byte[] bucket = new byte[1];
  3917. bucket[0] = (byte)item.Type;
  3918. GridInstantMessage msg = new(World, m_host.OwnerID, m_host.Name, destId,
  3919. (byte)InstantMessageDialog.TaskInventoryOffered,
  3920. m_host.OwnerID.Equals(m_host.GroupID), "'"+item.Name+"'. ("+m_host.Name+" is located at "+
  3921. m_regionName + " "+ m_host.AbsolutePosition.ToString() + ")",
  3922. agentItem.ID, true, m_host.AbsolutePosition,
  3923. bucket, true);
  3924. if (World.TryGetScenePresence(destId, out ScenePresence sp))
  3925. sp.ControllingClient.SendInstantMessage(msg);
  3926. else
  3927. m_TransferModule?.SendInstantMessage(msg, delegate(bool success) {});
  3928. //This delay should only occur when giving inventory to avatars.
  3929. ScriptSleep(m_sleepMsOnGiveInventory);
  3930. }
  3931. [DebuggerNonUserCode]
  3932. public void llRemoveInventory(string name)
  3933. {
  3934. TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name);
  3935. if (item == null)
  3936. return;
  3937. if (item.ItemID == m_item.ItemID)
  3938. throw new ScriptDeleteException();
  3939. else
  3940. m_host.Inventory.RemoveInventoryItem(item.ItemID);
  3941. }
  3942. public void llSetText(string text, LSL_Vector color, double alpha)
  3943. {
  3944. Vector3 av3 = Vector3.Clamp(color, 0.0f, 1.0f);
  3945. m_host.SetText(text, av3, Utils.Clamp((float)alpha, 0.0f, 1.0f));
  3946. }
  3947. public LSL_Float llWater(LSL_Vector offset)
  3948. {
  3949. return World.RegionInfo.RegionSettings.WaterHeight;
  3950. }
  3951. public void llPassTouches(int pass)
  3952. {
  3953. if (pass != 0)
  3954. m_host.PassTouches = true;
  3955. else
  3956. m_host.PassTouches = false;
  3957. }
  3958. public LSL_Key llRequestAgentData(string id, int data)
  3959. {
  3960. if(data < 1 || data > ScriptBaseClass.DATA_PAYINFO)
  3961. return string.Empty;
  3962. if (UUID.TryParse(id, out UUID uuid) && uuid.IsNotZero())
  3963. {
  3964. //pre process fast local avatars
  3965. switch(data)
  3966. {
  3967. case ScriptBaseClass.DATA_RATING:
  3968. case ScriptBaseClass.DATA_NAME: // DATA_NAME (First Last)
  3969. case ScriptBaseClass.DATA_ONLINE:
  3970. World.TryGetScenePresence(uuid, out ScenePresence sp);
  3971. if (sp != null)
  3972. {
  3973. string reply = data switch
  3974. {
  3975. ScriptBaseClass.DATA_RATING => "0,0,0,0,0,0",
  3976. ScriptBaseClass.DATA_NAME => sp.Firstname + " " + sp.Lastname,
  3977. _ => "1"
  3978. };
  3979. string ftid = m_AsyncCommands.DataserverPlugin.RequestWithImediatePost(m_host.LocalId,
  3980. m_item.ItemID, reply);
  3981. ScriptSleep(m_sleepMsOnRequestAgentData);
  3982. return ftid;
  3983. }
  3984. break;
  3985. case ScriptBaseClass.DATA_BORN: // DATA_BORN (YYYY-MM-DD)
  3986. case 7: // DATA_USERLEVEL (integer). This is not available in LL and so has no constant.
  3987. case ScriptBaseClass.DATA_PAYINFO: // DATA_PAYINFO (0|1|2|3)
  3988. break;
  3989. default:
  3990. return string.Empty; // Raise no event
  3991. }
  3992. void act(string eventID)
  3993. {
  3994. IUserManagement umm = World.RequestModuleInterface<IUserManagement>();
  3995. if(umm == null)
  3996. return;
  3997. UserData udt = umm.GetUserData(uuid);
  3998. if (udt == null || udt.IsUnknownUser)
  3999. return;
  4000. string reply = null;
  4001. switch(data)
  4002. {
  4003. case ScriptBaseClass.DATA_ONLINE:
  4004. if (!m_PresenceInfoCache.TryGetValue(uuid, out PresenceInfo pinfo))
  4005. {
  4006. PresenceInfo[] pinfos = World.PresenceService.GetAgents([uuid.ToString()]);
  4007. if (pinfos != null && pinfos.Length > 0)
  4008. {
  4009. foreach (PresenceInfo p in pinfos)
  4010. {
  4011. if (!p.RegionID.IsZero())
  4012. {
  4013. pinfo = p;
  4014. }
  4015. }
  4016. }
  4017. m_PresenceInfoCache.AddOrUpdate(uuid, pinfo, m_llRequestAgentDataCacheTimeout);
  4018. }
  4019. reply = pinfo == null ? "0" : "1";
  4020. break;
  4021. case ScriptBaseClass.DATA_NAME:
  4022. reply = udt.FirstName + " " + udt.LastName;
  4023. break;
  4024. case ScriptBaseClass.DATA_RATING:
  4025. reply = "0,0,0,0,0,0";
  4026. break;
  4027. case 7:
  4028. case ScriptBaseClass.DATA_BORN:
  4029. case ScriptBaseClass.DATA_PAYINFO:
  4030. if (udt.IsLocal)
  4031. {
  4032. UserAccount account = m_userAccountService.GetUserAccount(RegionScopeID, uuid);
  4033. if (account is not null)
  4034. {
  4035. reply = data switch
  4036. {
  4037. 7 => account.UserLevel.ToString(),
  4038. ScriptBaseClass.DATA_BORN => Util.ToDateTime(account.Created).ToString("yyyy-MM-dd"),
  4039. _ => ((account.UserFlags >> 2) & 0x03).ToString()
  4040. };
  4041. }
  4042. }
  4043. else
  4044. {
  4045. if (data == 7)
  4046. reply = "0";
  4047. }
  4048. break;
  4049. default:
  4050. break;
  4051. }
  4052. if(reply != null)
  4053. m_AsyncCommands.DataserverPlugin.DataserverReply(eventID, reply);
  4054. }
  4055. UUID tid = m_AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId,
  4056. m_item.ItemID, act);
  4057. ScriptSleep(m_sleepMsOnRequestAgentData);
  4058. return tid.ToString();
  4059. }
  4060. else
  4061. {
  4062. Error("llRequestAgentData","Invalid UUID passed to llRequestAgentData.");
  4063. }
  4064. return String.Empty;
  4065. }
  4066. //bad if lm is HG
  4067. public LSL_Key llRequestInventoryData(LSL_String name)
  4068. {
  4069. void act(string eventID)
  4070. {
  4071. string reply = String.Empty;
  4072. foreach (TaskInventoryItem item in m_host.Inventory.GetInventoryItems())
  4073. {
  4074. if (item.Type == 3 && item.Name == name)
  4075. {
  4076. AssetBase a = World.AssetService.Get(item.AssetID.ToString());
  4077. if (a is not null)
  4078. {
  4079. AssetLandmark lm = new(a);
  4080. if (lm is not null)
  4081. {
  4082. double rx = (lm.RegionHandle >> 32) - (double)World.RegionInfo.WorldLocX + (double)lm.Position.X;
  4083. double ry = (lm.RegionHandle & 0xffffffff) - (double)World.RegionInfo.WorldLocY + (double)lm.Position.Y;
  4084. LSL_Vector region = new(rx, ry, lm.Position.Z);
  4085. reply = region.ToString();
  4086. }
  4087. }
  4088. break;
  4089. }
  4090. }
  4091. m_AsyncCommands.DataserverPlugin.DataserverReply(eventID, reply);
  4092. }
  4093. UUID tid = m_AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId,
  4094. m_item.ItemID, act);
  4095. ScriptSleep(m_sleepMsOnRequestInventoryData);
  4096. return tid.ToString();
  4097. }
  4098. public void llSetDamage(double damage)
  4099. {
  4100. m_host.ParentGroup.Damage = (float)damage;
  4101. }
  4102. public void llTeleportAgentHome(string agent)
  4103. {
  4104. if (UUID.TryParse(agent, out UUID agentId) && agentId.IsNotZero())
  4105. {
  4106. ScenePresence presence = World.GetScenePresence(agentId);
  4107. if (presence == null || presence.IsDeleted || presence.IsChildAgent || presence.IsNPC || presence.IsInTransit)
  4108. return;
  4109. // agent must not be a god
  4110. if (presence.GodController.UserLevel >= 200)
  4111. return;
  4112. // agent must be over the owners land
  4113. if (m_host.OwnerID.Equals(World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID))
  4114. {
  4115. World.TeleportClientHome(agentId, presence.ControllingClient);
  4116. }
  4117. }
  4118. ScriptSleep(m_sleepMsOnSetDamage);
  4119. }
  4120. public void llTeleportAgent(string agent, string destination, LSL_Vector targetPos, LSL_Vector targetLookAt)
  4121. {
  4122. // If attached using llAttachToAvatarTemp, cowardly refuse
  4123. if (m_host.ParentGroup.AttachmentPoint != 0 && m_host.ParentGroup.FromItemID.IsZero())
  4124. return;
  4125. if (UUID.TryParse(agent, out UUID agentId) && agentId.IsNotZero())
  4126. {
  4127. ScenePresence presence = World.GetScenePresence(agentId);
  4128. if (presence == null || presence.IsDeleted || presence.IsChildAgent || presence.IsNPC || presence.IsSatOnObject || presence.IsInTransit)
  4129. return;
  4130. if (m_item.PermsGranter.Equals(agentId))
  4131. {
  4132. if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TELEPORT) != 0)
  4133. {
  4134. DoLLTeleport(presence, destination, targetPos, targetLookAt);
  4135. return;
  4136. }
  4137. }
  4138. // special opensim legacy extra permissions, possible to remove
  4139. // agent must be wearing the object
  4140. if (m_host.ParentGroup.AttachmentPoint != 0 && m_host.OwnerID.Equals(presence.UUID))
  4141. {
  4142. DoLLTeleport(presence, destination, targetPos, targetLookAt);
  4143. return;
  4144. }
  4145. // agent must not be a god
  4146. if (presence.IsViewerUIGod)
  4147. return;
  4148. // agent must be over the owners land
  4149. ILandObject agentLand = World.LandChannel.GetLandObject(presence.AbsolutePosition);
  4150. ILandObject objectLand = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
  4151. if (m_host.OwnerID.Equals(objectLand.LandData.OwnerID) && m_host.OwnerID.Equals(agentLand.LandData.OwnerID))
  4152. {
  4153. DoLLTeleport(presence, destination, targetPos, targetLookAt);
  4154. }
  4155. }
  4156. }
  4157. public void llTeleportAgentGlobalCoords(string agent, LSL_Vector global_coords, LSL_Vector targetPos, LSL_Vector targetLookAt)
  4158. {
  4159. // If attached using llAttachToAvatarTemp, cowardly refuse
  4160. if (m_host.ParentGroup.AttachmentPoint != 0 && m_host.ParentGroup.FromItemID.IsZero())
  4161. return;
  4162. if (UUID.TryParse(agent, out UUID agentId) && agentId.IsNotZero())
  4163. {
  4164. // This function is owner only!
  4165. if (m_host.OwnerID.NotEqual(agentId))
  4166. return;
  4167. ScenePresence presence = World.GetScenePresence(agentId);
  4168. if (presence == null || presence.IsDeleted || presence.IsChildAgent || presence.IsNPC || presence.IsSatOnObject || presence.IsInTransit)
  4169. return;
  4170. if (m_item.PermsGranter.Equals(agentId))
  4171. {
  4172. if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TELEPORT) != 0)
  4173. {
  4174. ulong regionHandle = Util.RegionWorldLocToHandle((uint)global_coords.x, (uint)global_coords.y);
  4175. World.RequestTeleportLocation(presence.ControllingClient, regionHandle, targetPos, targetLookAt, (uint)TeleportFlags.ViaLocation);
  4176. }
  4177. }
  4178. }
  4179. }
  4180. private void DoLLTeleport(ScenePresence sp, string destination, Vector3 targetPos, Vector3 targetLookAt)
  4181. {
  4182. UUID assetID = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, destination);
  4183. // The destination is not an asset ID and also doesn't name a landmark.
  4184. // Use it as a sim name
  4185. if (assetID.IsZero())
  4186. {
  4187. if(string.IsNullOrEmpty(destination))
  4188. World.RequestTeleportLocation(sp.ControllingClient, m_regionName, targetPos, targetLookAt, (uint)TeleportFlags.ViaLocation);
  4189. else
  4190. World.RequestTeleportLocation(sp.ControllingClient, destination, targetPos, targetLookAt, (uint)TeleportFlags.ViaLocation);
  4191. return;
  4192. }
  4193. AssetBase lma = World.AssetService.Get(assetID.ToString());
  4194. if (lma == null || lma.Data == null || lma.Data.Length == 0)
  4195. return;
  4196. if (lma.Type != (sbyte)AssetType.Landmark)
  4197. return;
  4198. AssetLandmark lm = new(lma);
  4199. World.RequestTeleportLandmark(sp.ControllingClient, lm, targetLookAt);
  4200. }
  4201. public void llTextBox(string agent, string message, int chatChannel)
  4202. {
  4203. IDialogModule dm = World.RequestModuleInterface<IDialogModule>();
  4204. if (dm == null)
  4205. return;
  4206. if (!UUID.TryParse(agent, out UUID av) || av.IsZero())
  4207. {
  4208. Error("llTextBox", "First parameter must be a valid agent key");
  4209. return;
  4210. }
  4211. if (message.Length == 0)
  4212. {
  4213. Error("llTextBox", "Empty message");
  4214. }
  4215. else if (Encoding.UTF8.GetByteCount(message) > 512)
  4216. {
  4217. Error("llTextBox", "Message longer than 512 bytes");
  4218. }
  4219. else if(m_host.GetOwnerName(out string fname, out string lname))
  4220. {
  4221. dm.SendTextBoxToUser(av, message, chatChannel, m_host.Name, m_host.UUID, fname, lname, m_host.OwnerID);
  4222. ScriptSleep(m_sleepMsOnTextBox);
  4223. }
  4224. }
  4225. public void llModifyLand(int action, int brush)
  4226. {
  4227. ITerrainModule tm = m_ScriptEngine.World.RequestModuleInterface<ITerrainModule>();
  4228. tm?.ModifyTerrain(m_host.OwnerID, m_host.AbsolutePosition, (byte) brush, (byte) action);
  4229. }
  4230. public void llCollisionSound(LSL_String impact_sound, LSL_Float impact_volume)
  4231. {
  4232. if(String.IsNullOrEmpty(impact_sound.m_string))
  4233. {
  4234. m_host.CollisionSoundVolume = (float)impact_volume;
  4235. m_host.CollisionSound = m_host.invalidCollisionSoundUUID;
  4236. m_host.CollisionSoundType = -1; // disable all sounds
  4237. m_host.aggregateScriptEvents();
  4238. return;
  4239. }
  4240. // TODO: Parameter check logic required.
  4241. UUID soundId = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, impact_sound, AssetType.Sound);
  4242. if(soundId.IsZero())
  4243. m_host.CollisionSoundType = -1;
  4244. else
  4245. {
  4246. m_host.CollisionSound = soundId;
  4247. m_host.CollisionSoundVolume = (float)impact_volume;
  4248. m_host.CollisionSoundType = 1;
  4249. }
  4250. m_host.aggregateScriptEvents();
  4251. }
  4252. public LSL_String llGetAnimation(LSL_Key id)
  4253. {
  4254. // This should only return a value if the avatar is in the same region
  4255. if(!UUID.TryParse(id, out UUID avatar) || avatar.IsZero())
  4256. return "";
  4257. ScenePresence presence = World.GetScenePresence(avatar);
  4258. if (presence == null || presence.IsChildAgent || presence.Animator == null)
  4259. return string.Empty;
  4260. //if (presence.SitGround)
  4261. // return "Sitting on Ground";
  4262. //if (presence.ParentID != 0 || presence.ParentUUID != UUID.Zero)
  4263. // return "Sitting";
  4264. string movementAnimation = presence.Animator.CurrentMovementAnimation;
  4265. if (MovementAnimationsForLSL.TryGetValue(movementAnimation, out string lslMovementAnimation))
  4266. return lslMovementAnimation;
  4267. return string.Empty;
  4268. }
  4269. public void llMessageLinked(int linknumber, int num, string msg, string id)
  4270. {
  4271. List<SceneObjectPart> parts = GetLinkParts(linknumber);
  4272. UUID partItemID;
  4273. foreach (SceneObjectPart part in parts)
  4274. {
  4275. foreach (TaskInventoryItem item in part.Inventory.GetInventoryItems())
  4276. {
  4277. if (item.Type == ScriptBaseClass.INVENTORY_SCRIPT)
  4278. {
  4279. partItemID = item.ItemID;
  4280. int linkNumber = m_host.LinkNum;
  4281. if (m_host.ParentGroup.PrimCount == 1)
  4282. linkNumber = 0;
  4283. object[] resobj = new object[]
  4284. {
  4285. new LSL_Integer(linkNumber), new LSL_Integer(num), new LSL_String(msg), new LSL_String(id)
  4286. };
  4287. m_ScriptEngine.PostScriptEvent(partItemID,
  4288. new EventParams("link_message",
  4289. resobj, Array.Empty<DetectParams>()));
  4290. }
  4291. }
  4292. }
  4293. }
  4294. public void llPushObject(string target, LSL_Vector impulse, LSL_Vector ang_impulse, int local)
  4295. {
  4296. bool pushrestricted = World.RegionInfo.RegionSettings.RestrictPushing;
  4297. bool pushAllowed = false;
  4298. bool pusheeIsAvatar = false;
  4299. if (!UUID.TryParse(target, out UUID targetID) || targetID.IsZero())
  4300. return;
  4301. ScenePresence pusheeav = null;
  4302. Vector3 PusheePos = Vector3.Zero;
  4303. SceneObjectPart pusheeob = null;
  4304. ScenePresence avatar = World.GetScenePresence(targetID);
  4305. if (avatar != null)
  4306. {
  4307. pusheeIsAvatar = true;
  4308. // Pushee doesn't have a physics actor
  4309. if (avatar.PhysicsActor == null)
  4310. return;
  4311. // Pushee is in GodMode this pushing object isn't owned by them
  4312. if (avatar.IsViewerUIGod && m_host.OwnerID != targetID)
  4313. return;
  4314. pusheeav = avatar;
  4315. // Find pushee position
  4316. // Pushee Linked?
  4317. SceneObjectPart sitPart = pusheeav.ParentPart;
  4318. if (sitPart != null)
  4319. PusheePos = sitPart.AbsolutePosition;
  4320. else
  4321. PusheePos = pusheeav.AbsolutePosition;
  4322. }
  4323. if (!pusheeIsAvatar)
  4324. {
  4325. // not an avatar so push is not affected by parcel flags
  4326. pusheeob = World.GetSceneObjectPart((UUID)target);
  4327. // We can't find object
  4328. if (pusheeob == null)
  4329. return;
  4330. // Object not pushable. Not an attachment and has no physics component
  4331. if (!pusheeob.ParentGroup.IsAttachment && pusheeob.PhysActor == null)
  4332. return;
  4333. PusheePos = pusheeob.AbsolutePosition;
  4334. pushAllowed = true;
  4335. }
  4336. else
  4337. {
  4338. if (pushrestricted)
  4339. {
  4340. ILandObject targetlandObj = World.LandChannel.GetLandObject(PusheePos);
  4341. // We didn't find the parcel but region is push restricted so assume it is NOT ok
  4342. if (targetlandObj == null)
  4343. return;
  4344. // Need provisions for Group Owned here
  4345. if (m_host.OwnerID.Equals(targetlandObj.LandData.OwnerID) ||
  4346. targetlandObj.LandData.IsGroupOwned || m_host.OwnerID.Equals(targetID))
  4347. {
  4348. pushAllowed = true;
  4349. }
  4350. }
  4351. else
  4352. {
  4353. ILandObject targetlandObj = World.LandChannel.GetLandObject(PusheePos);
  4354. if (targetlandObj == null)
  4355. {
  4356. // We didn't find the parcel but region isn't push restricted so assume it's ok
  4357. pushAllowed = true;
  4358. }
  4359. else
  4360. {
  4361. // Parcel push restriction
  4362. if ((targetlandObj.LandData.Flags & (uint)ParcelFlags.RestrictPushObject) == (uint)ParcelFlags.RestrictPushObject)
  4363. {
  4364. // Need provisions for Group Owned here
  4365. if (m_host.OwnerID.Equals(targetlandObj.LandData.OwnerID) ||
  4366. targetlandObj.LandData.IsGroupOwned ||
  4367. m_host.OwnerID.Equals(targetID))
  4368. {
  4369. pushAllowed = true;
  4370. }
  4371. //ParcelFlags.RestrictPushObject
  4372. //pushAllowed = true;
  4373. }
  4374. else
  4375. {
  4376. // Parcel isn't push restricted
  4377. pushAllowed = true;
  4378. }
  4379. }
  4380. }
  4381. }
  4382. if (pushAllowed)
  4383. {
  4384. float distance = (PusheePos - m_host.AbsolutePosition).Length();
  4385. //float distance_term = distance * distance * distance; // Script Energy
  4386. // use total object mass and not part
  4387. //float pusher_mass = m_host.ParentGroup.GetMass();
  4388. float PUSH_ATTENUATION_DISTANCE = 17f;
  4389. float PUSH_ATTENUATION_SCALE = 5f;
  4390. float distance_attenuation = 1f;
  4391. if (distance > PUSH_ATTENUATION_DISTANCE)
  4392. {
  4393. float normalized_units = 1f + (distance - PUSH_ATTENUATION_DISTANCE) / PUSH_ATTENUATION_SCALE;
  4394. distance_attenuation = 1f / normalized_units;
  4395. }
  4396. Vector3 applied_linear_impulse = impulse;
  4397. {
  4398. //float impulse_length = applied_linear_impulse.Length();
  4399. //float desired_energy = impulse_length * pusher_mass;
  4400. float scaling_factor = 1f;
  4401. scaling_factor *= distance_attenuation;
  4402. applied_linear_impulse *= scaling_factor;
  4403. }
  4404. if (pusheeIsAvatar)
  4405. {
  4406. if (pusheeav is not null)
  4407. {
  4408. PhysicsActor pa = pusheeav.PhysicsActor;
  4409. if (pa is not null)
  4410. {
  4411. if (local != 0)
  4412. applied_linear_impulse *= pusheeav.GetWorldRotation();
  4413. pa.AddForce(applied_linear_impulse, true);
  4414. }
  4415. }
  4416. }
  4417. else
  4418. {
  4419. if (pusheeob is not null)
  4420. {
  4421. if (pusheeob.PhysActor is not null)
  4422. pusheeob.ApplyImpulse(applied_linear_impulse, local != 0);
  4423. }
  4424. }
  4425. }
  4426. }
  4427. public void llPassCollisions(int pass)
  4428. {
  4429. m_host.PassCollisions = pass == 1;
  4430. }
  4431. public LSL_String llGetScriptName()
  4432. {
  4433. return m_item.Name ?? String.Empty;
  4434. }
  4435. public LSL_Integer llGetLinkNumberOfSides(int link)
  4436. {
  4437. SceneObjectPart linkedPart;
  4438. if (link == ScriptBaseClass.LINK_ROOT)
  4439. linkedPart = m_host.ParentGroup.RootPart;
  4440. else if (link == ScriptBaseClass.LINK_THIS)
  4441. linkedPart = m_host;
  4442. else
  4443. linkedPart = m_host.ParentGroup.GetLinkNumPart(link);
  4444. return GetNumberOfSides(linkedPart);
  4445. }
  4446. public LSL_Integer llGetNumberOfSides()
  4447. {
  4448. return m_host.GetNumberOfSides();
  4449. }
  4450. protected static int GetNumberOfSides(SceneObjectPart part)
  4451. {
  4452. return part.GetNumberOfSides();
  4453. }
  4454. // Xantor 29/apr/2008
  4455. // Returns rotation described by rotating angle radians about axis.
  4456. // q = cos(a/2) + i (x * sin(a/2)) + j (y * sin(a/2)) + k (z * sin(a/2))
  4457. public LSL_Rotation llAxisAngle2Rot(LSL_Vector axis, double angle)
  4458. {
  4459. double x, y, z, s, t;
  4460. s = Math.Cos(angle * 0.5);
  4461. t = Math.Sin(angle * 0.5); // temp value to avoid 2 more sin() calcs
  4462. axis = LSL_Vector.Norm(axis);
  4463. x = axis.x * t;
  4464. y = axis.y * t;
  4465. z = axis.z * t;
  4466. return new LSL_Rotation(x,y,z,s);
  4467. }
  4468. /// <summary>
  4469. /// Returns the axis of rotation for a quaternion
  4470. /// </summary>
  4471. /// <returns></returns>
  4472. /// <param name='rot'></param>
  4473. public LSL_Vector llRot2Axis(LSL_Rotation rot)
  4474. {
  4475. rot.Normalize();
  4476. double s = Math.Sqrt(1 - rot.s * rot.s);
  4477. if (s < 1e-8)
  4478. return new LSL_Vector(0, 0, 0);
  4479. double invS = 1.0 / s;
  4480. if (rot.s < 0)
  4481. invS = -invS;
  4482. return new LSL_Vector(rot.x * invS, rot.y * invS, rot.z * invS);
  4483. }
  4484. // Returns the angle of a quaternion (see llRot2Axis for the axis)
  4485. public LSL_Float llRot2Angle(LSL_Rotation rot)
  4486. {
  4487. rot.Normalize();
  4488. double angle = 2 * Math.Acos(rot.s);
  4489. if (angle > Math.PI)
  4490. angle = 2 * Math.PI - angle;
  4491. return angle;
  4492. }
  4493. public LSL_Float llAcos(LSL_Float val)
  4494. {
  4495. return Math.Acos(val);
  4496. }
  4497. public LSL_Float llAsin(LSL_Float val)
  4498. {
  4499. return Math.Asin(val);
  4500. }
  4501. // jcochran 5/jan/2012
  4502. public LSL_Float llAngleBetween(LSL_Rotation a, LSL_Rotation b)
  4503. {
  4504. double aa = (a.x * a.x + a.y * a.y + a.z * a.z + a.s * a.s);
  4505. double bb = (b.x * b.x + b.y * b.y + b.z * b.z + b.s * b.s);
  4506. double aa_bb = aa * bb;
  4507. if (aa_bb == 0) return 0.0;
  4508. double ab = (a.x * b.x + a.y * b.y + a.z * b.z + a.s * b.s);
  4509. double quotient = (ab * ab) / aa_bb;
  4510. if (quotient >= 1.0) return 0.0;
  4511. return Math.Acos(2 * quotient - 1);
  4512. }
  4513. public LSL_Key llGetInventoryKey(string name)
  4514. {
  4515. TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name);
  4516. if (item is null)
  4517. return ScriptBaseClass.NULL_KEY;
  4518. if ((item.CurrentPermissions
  4519. & (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify))
  4520. == (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify))
  4521. {
  4522. return item.AssetID.ToString();
  4523. }
  4524. return ScriptBaseClass.NULL_KEY;
  4525. }
  4526. public void llAllowInventoryDrop(LSL_Integer add)
  4527. {
  4528. m_host.ParentGroup.RootPart.AllowedDrop = add != 0;
  4529. m_host.ParentGroup.RootPart.aggregateScriptEvents();
  4530. }
  4531. public LSL_Vector llGetTextureOffset(int face)
  4532. {
  4533. return GetTextureOffset(m_host, face);
  4534. }
  4535. protected static LSL_Vector GetTextureOffset(SceneObjectPart part, int face)
  4536. {
  4537. if (face == ScriptBaseClass.ALL_SIDES)
  4538. face = 0;
  4539. if (face >= 0 && face < GetNumberOfSides(part))
  4540. {
  4541. Primitive.TextureEntryFace teface = part.Shape.Textures.GetFace((uint)face);
  4542. return new LSL_Vector (teface.OffsetU, teface.OffsetV, 0.0);
  4543. }
  4544. return LSL_Vector.Zero;
  4545. }
  4546. public LSL_Vector llGetTextureScale(int side)
  4547. {
  4548. Primitive.TextureEntryFace teface;
  4549. if (side == ScriptBaseClass.ALL_SIDES)
  4550. teface = m_host.Shape.Textures.GetFace(0);
  4551. else
  4552. teface = m_host.Shape.Textures.GetFace((uint)side);
  4553. return new LSL_Vector(teface.RepeatU, teface.RepeatV, 0.0);
  4554. }
  4555. public LSL_Float llGetTextureRot(int face)
  4556. {
  4557. return GetTextureRot(m_host, face);
  4558. }
  4559. protected static LSL_Float GetTextureRot(SceneObjectPart part, int face)
  4560. {
  4561. Primitive.TextureEntry tex = part.Shape.Textures;
  4562. if (face == ScriptBaseClass.ALL_SIDES)
  4563. face = 0;
  4564. if (face >= 0 && face < GetNumberOfSides(part))
  4565. return tex.GetFace((uint)face).Rotation;
  4566. return 0.0;
  4567. }
  4568. public LSL_Integer llSubStringIndex(string source, string pattern)
  4569. {
  4570. if (string.IsNullOrEmpty(source))
  4571. return -1;
  4572. if (string.IsNullOrEmpty(pattern))
  4573. return 0;
  4574. return source.IndexOf(pattern);
  4575. }
  4576. public LSL_Key llGetOwnerKey(string id)
  4577. {
  4578. if (UUID.TryParse(id, out UUID key))
  4579. {
  4580. if(key.IsZero())
  4581. return id;
  4582. SceneObjectPart obj = World.GetSceneObjectPart(key);
  4583. return (obj == null) ? id : obj.OwnerID.ToString();
  4584. }
  4585. else
  4586. {
  4587. return ScriptBaseClass.NULL_KEY;
  4588. }
  4589. }
  4590. public LSL_Vector llGetCenterOfMass()
  4591. {
  4592. return new LSL_Vector(m_host.GetCenterOfMass());
  4593. }
  4594. public LSL_List llListSort(LSL_List src, int stride, int ascending)
  4595. {
  4596. return src.Sort(stride, ascending == 1);
  4597. }
  4598. public LSL_List llListSortStrided(LSL_List src, int stride, int stride_index, int ascending)
  4599. {
  4600. return src.Sort(stride, stride_index, ascending == 1);
  4601. }
  4602. public LSL_Integer llGetListLength(LSL_List src)
  4603. {
  4604. return src.Length;
  4605. }
  4606. public LSL_Integer llList2Integer(LSL_List src, int index)
  4607. {
  4608. if (index < 0)
  4609. index = src.Length + index;
  4610. if (index >= src.Length || index < 0)
  4611. return 0;
  4612. object item = src.Data[index];
  4613. // Vectors & Rotations always return zero in SL, but
  4614. // keys don't always return zero, it seems to be a bit complex.
  4615. if (item is LSL_Vector || item is LSL_Rotation)
  4616. return 0;
  4617. try
  4618. {
  4619. if (item is LSL_Integer LSL_Integeritem)
  4620. return LSL_Integeritem;
  4621. if (item is int LSL_Intitem)
  4622. return new LSL_Integer(LSL_Intitem);
  4623. if (item is LSL_Float LSL_Floatitem)
  4624. return new LSL_Integer(LSL_Floatitem.value);
  4625. return new LSL_Integer(item.ToString());
  4626. }
  4627. catch (FormatException)
  4628. {
  4629. return 0;
  4630. }
  4631. }
  4632. public LSL_Float llList2Float(LSL_List src, int index)
  4633. {
  4634. if (index < 0)
  4635. index = src.Length + index;
  4636. if (index >= src.Length || index < 0)
  4637. return 0;
  4638. object item = src.Data[index];
  4639. // Vectors & Rotations always return zero in SL
  4640. if(item is LSL_Vector || item is LSL_Rotation)
  4641. return 0;
  4642. // valid keys seem to get parsed as integers then converted to floats
  4643. if (item is LSL_Key lslk)
  4644. {
  4645. if(UUID.TryParse(lslk.m_string, out UUID _))
  4646. return Convert.ToDouble(new LSL_Integer(lslk.m_string).value);
  4647. // we can't do this because a string is also a LSL_Key for now :(
  4648. //else
  4649. // return 0;
  4650. }
  4651. try
  4652. {
  4653. if (item is LSL_Float floatitem)
  4654. return floatitem;
  4655. if (item is LSL_Integer intitem)
  4656. return new LSL_Float(intitem.value);
  4657. if (item is int LSL_Intitem)
  4658. return new LSL_Float(LSL_Intitem);
  4659. if (item is LSL_String lstringitem)
  4660. {
  4661. Match m = Regex.Match(lstringitem.m_string, "^\\s*(-?\\+?[,0-9]+\\.?[0-9]*)");
  4662. if (m != Match.Empty)
  4663. {
  4664. if (Double.TryParse(m.Value, out double d))
  4665. return d;
  4666. }
  4667. return 0.0;
  4668. }
  4669. return Convert.ToDouble(item);
  4670. }
  4671. catch (FormatException)
  4672. {
  4673. return 0.0;
  4674. }
  4675. }
  4676. public LSL_String llList2String(LSL_List src, int index)
  4677. {
  4678. if (index < 0)
  4679. index = src.Length + index;
  4680. if (index >= src.Length || index < 0)
  4681. return String.Empty;
  4682. return src.Data[index].ToString();
  4683. }
  4684. public LSL_Key llList2Key(LSL_List src, int index)
  4685. {
  4686. if (index < 0)
  4687. index = src.Length + index;
  4688. if (index >= src.Length || index < 0)
  4689. return String.Empty;
  4690. object item = src.Data[index];
  4691. // SL spits out an empty string for types other than key & string
  4692. // At the time of patching, LSL_Key is currently LSL_String,
  4693. // so the OR check may be a little redundant, but it's being done
  4694. // for completion and should LSL_Key ever be implemented
  4695. // as it's own struct
  4696. // NOTE: 3rd case is needed because a NULL_KEY comes through as
  4697. // type 'obj' and wrongly returns ""
  4698. if (!(item is LSL_String ||
  4699. item is LSL_Key ||
  4700. item.ToString().Equals("00000000-0000-0000-0000-000000000000")))
  4701. {
  4702. return String.Empty;
  4703. }
  4704. return item.ToString();
  4705. }
  4706. public LSL_Vector llList2Vector(LSL_List src, int index)
  4707. {
  4708. if (index < 0)
  4709. index = src.Length + index;
  4710. if (index >= src.Length || index < 0)
  4711. return LSL_Vector.Zero;
  4712. object item = src.Data[index];
  4713. if(item is LSL_Vector vec)
  4714. return vec;
  4715. if (item is LSL_String lsv)
  4716. return new LSL_Vector(lsv);
  4717. if (item is string sv) // xengine sees string
  4718. return new LSL_Vector(sv);
  4719. return LSL_Vector.Zero;
  4720. }
  4721. public LSL_Rotation llList2Rot(LSL_List src, int index)
  4722. {
  4723. if (index < 0)
  4724. index = src.Length + index;
  4725. if (index >= src.Length || index < 0)
  4726. return LSL_Rotation.Identity;
  4727. object item = src.Data[index];
  4728. if (item is LSL_Rotation rot)
  4729. return rot;
  4730. if (item is LSL_String lls)
  4731. return new LSL_Rotation(lls);
  4732. if (item is string ls) // xengine sees string)
  4733. return new LSL_Rotation(ls);
  4734. return LSL_Rotation.Identity;
  4735. }
  4736. public LSL_List llList2List(LSL_List src, int start, int end)
  4737. {
  4738. return src.GetSublist(start, end);
  4739. }
  4740. public LSL_List llDeleteSubList(LSL_List src, int start, int end)
  4741. {
  4742. return src.DeleteSublist(start, end);
  4743. }
  4744. public LSL_Integer llGetListEntryType(LSL_List src, int index)
  4745. {
  4746. if (index < 0)
  4747. {
  4748. index = src.Length + index;
  4749. if (index < 0)
  4750. return 0;
  4751. }
  4752. else if (index >= src.Length)
  4753. return 0;
  4754. object o = src.Data[index];
  4755. if (o is null)
  4756. return 0;
  4757. if (o is LSL_Integer || o is Int32)
  4758. return 1;
  4759. if (o is LSL_Float || o is Single || o is Double)
  4760. return 2;
  4761. if (o is LSL_String || o is String)
  4762. return UUID.TryParse(o.ToString(), out UUID _) ? 4 : 3;
  4763. if (o is LSL_Key)
  4764. return 4;
  4765. if (o is LSL_Vector)
  4766. return 5;
  4767. if (o is LSL_Rotation)
  4768. return 6;
  4769. if (o is LSL_List)
  4770. return 7;
  4771. return 0;
  4772. }
  4773. /// <summary>
  4774. /// Process the supplied list and return the
  4775. /// content of the list formatted as a comma
  4776. /// separated list. There is a space after
  4777. /// each comma.
  4778. /// </summary>
  4779. public LSL_String llList2CSV(LSL_List src)
  4780. {
  4781. return string.Join(", ",
  4782. (new List<object>(src.Data)).ConvertAll<string>(o =>
  4783. {
  4784. return o.ToString();
  4785. }).ToArray());
  4786. }
  4787. /// <summary>
  4788. /// The supplied string is scanned for commas
  4789. /// and converted into a list. Commas are only
  4790. /// effective if they are encountered outside
  4791. /// of '<' '>' delimiters. Any whitespace
  4792. /// before or after an element is trimmed.
  4793. /// </summary>
  4794. public LSL_List llCSV2List(string src)
  4795. {
  4796. LSL_List result = new();
  4797. int parens = 0;
  4798. int start = 0;
  4799. int length = 0;
  4800. ReadOnlySpan<char> s = src.AsSpan();
  4801. for (int i = 0; i < s.Length; i++)
  4802. {
  4803. switch (s[i])
  4804. {
  4805. case '<':
  4806. parens++;
  4807. length++;
  4808. break;
  4809. case '>':
  4810. if (parens > 0)
  4811. parens--;
  4812. length++;
  4813. break;
  4814. case ',':
  4815. if (parens == 0)
  4816. {
  4817. result.Add(new LSL_String(src.Substring(start,length).Trim()));
  4818. start += length+1;
  4819. length = 0;
  4820. }
  4821. else
  4822. {
  4823. length++;
  4824. }
  4825. break;
  4826. default:
  4827. length++;
  4828. break;
  4829. }
  4830. }
  4831. result.Add(new LSL_String(src.Substring(start,length).Trim()));
  4832. return result;
  4833. }
  4834. /// <summary>
  4835. /// Randomizes the list, be arbitrarily reordering
  4836. /// sublists of stride elements. As the stride approaches
  4837. /// the size of the list, the options become very
  4838. /// limited.
  4839. /// </summary>
  4840. /// <remarks>
  4841. /// This could take a while for very large list
  4842. /// sizes.
  4843. /// </remarks>
  4844. public LSL_List llListRandomize(LSL_List src, int stride)
  4845. {
  4846. LSL_List result;
  4847. int chunkk;
  4848. int[] chunks;
  4849. if (stride <= 0)
  4850. {
  4851. stride = 1;
  4852. }
  4853. // Stride MUST be a factor of the list length
  4854. // If not, then return the src list. This also
  4855. // traps those cases where stride > length.
  4856. if (src.Length != stride && src.Length % stride == 0)
  4857. {
  4858. chunkk = src.Length/stride;
  4859. chunks = new int[chunkk];
  4860. for (int i = 0; i < chunkk; i++)
  4861. {
  4862. chunks[i] = i;
  4863. }
  4864. // Knuth shuffle the chunkk index
  4865. for (int i = chunkk - 1; i > 0; i--)
  4866. {
  4867. // Elect an unrandomized chunk to swap
  4868. int index = Random.Shared.Next(i + 1);
  4869. // and swap position with first unrandomized chunk
  4870. int tmp = chunks[i];
  4871. chunks[i] = chunks[index];
  4872. chunks[index] = tmp;
  4873. }
  4874. // Construct the randomized list
  4875. result = new LSL_List();
  4876. for (int i = 0; i < chunkk; i++)
  4877. {
  4878. for (int j = 0; j < stride; j++)
  4879. {
  4880. result.Add(src.Data[chunks[i] * stride + j]);
  4881. }
  4882. }
  4883. }
  4884. else
  4885. {
  4886. object[] array = new object[src.Length];
  4887. Array.Copy(src.Data, 0, array, 0, src.Length);
  4888. result = new LSL_List(array);
  4889. }
  4890. return result;
  4891. }
  4892. public LSL_List llList2ListStrided(LSL_List src, int start, int end, int stride)
  4893. {
  4894. if (start < 0)
  4895. {
  4896. start += src.Length;
  4897. if (start < 0)
  4898. start = 0;
  4899. }
  4900. if (end < 0)
  4901. {
  4902. end += src.Length;
  4903. if (end < 0)
  4904. end = 0;
  4905. }
  4906. if (start > end)
  4907. {
  4908. start = 0;
  4909. end = src.Length - 1;
  4910. }
  4911. else
  4912. {
  4913. if (start >= src.Length)
  4914. return new LSL_List();
  4915. if (end >= src.Length)
  4916. end = src.Length - 1;
  4917. }
  4918. if (stride < 1)
  4919. stride = 1;
  4920. int size;
  4921. if (stride > 1)
  4922. {
  4923. if (start > 0)
  4924. {
  4925. int sst = start / stride;
  4926. sst *= stride;
  4927. if (sst != start)
  4928. start = sst + stride;
  4929. if (start > end)
  4930. return new LSL_List();
  4931. }
  4932. size = end - start + 1;
  4933. int sz = size / stride;
  4934. if (sz * stride < size)
  4935. sz++;
  4936. size = sz;
  4937. }
  4938. else
  4939. size = end - start + 1;
  4940. object[] res = new object[size];
  4941. int j = 0;
  4942. for (int i = start; i <= end; i += stride, j++)
  4943. res[j] = src.Data[i];
  4944. return new LSL_List(res);
  4945. }
  4946. public LSL_List llList2ListSlice(LSL_List src, int start, int end, int stride, int stride_index)
  4947. {
  4948. if (start < 0)
  4949. {
  4950. start += src.Length;
  4951. if (start < 0)
  4952. start = 0;
  4953. }
  4954. if (end < 0)
  4955. {
  4956. end += src.Length;
  4957. if (end < 0)
  4958. end = 0;
  4959. }
  4960. if (start > end)
  4961. {
  4962. start = 0;
  4963. end = src.Length - 1;
  4964. }
  4965. else
  4966. {
  4967. if (start >= src.Length)
  4968. return new LSL_List();
  4969. if (end >= src.Length)
  4970. end = src.Length - 1;
  4971. }
  4972. if (stride < 1)
  4973. stride = 1;
  4974. if (stride_index < 0)
  4975. {
  4976. stride_index += stride;
  4977. if (stride_index < 0)
  4978. return new LSL_List();
  4979. }
  4980. else if (stride_index >= stride)
  4981. return new LSL_List();
  4982. int size;
  4983. if (stride > 1)
  4984. {
  4985. if (start > 0)
  4986. {
  4987. int sst = start / stride;
  4988. sst *= stride;
  4989. if (sst != start)
  4990. start = sst + stride;
  4991. if (start > end)
  4992. return new LSL_List();
  4993. }
  4994. start += stride_index;
  4995. size = end - start + 1;
  4996. int sz = size / stride;
  4997. if (sz * stride < size)
  4998. sz++;
  4999. size = sz;
  5000. }
  5001. else
  5002. size = end - start + 1;
  5003. object[] res = new object[size];
  5004. int j = 0;
  5005. for (int i = start; i <= end; i += stride, j++)
  5006. res[j] = src.Data[i];
  5007. //m_log.Debug($" test {size} {j}");
  5008. return new LSL_List(res);
  5009. }
  5010. public LSL_Integer llGetRegionAgentCount()
  5011. {
  5012. int count = 0;
  5013. World.ForEachRootScenePresence(delegate(ScenePresence sp) {
  5014. count++;
  5015. });
  5016. return new LSL_Integer(count);
  5017. }
  5018. public LSL_Vector llGetRegionCorner()
  5019. {
  5020. return new LSL_Vector(World.RegionInfo.WorldLocX, World.RegionInfo.WorldLocY, 0);
  5021. }
  5022. public LSL_String llGetEnv(LSL_String name)
  5023. {
  5024. string sname = name;
  5025. sname = sname.ToLower();
  5026. switch(sname)
  5027. {
  5028. case "agent_limit":
  5029. return World.RegionInfo.RegionSettings.AgentLimit.ToString();
  5030. case "dynamic_pathfinding":
  5031. return "0";
  5032. case "estate_id":
  5033. return World.RegionInfo.EstateSettings.EstateID.ToString();
  5034. case "estate_name":
  5035. return World.RegionInfo.EstateSettings.EstateName;
  5036. case "frame_number":
  5037. return World.Frame.ToString();
  5038. case "region_cpu_ratio":
  5039. return "1";
  5040. case "region_idle":
  5041. return "0";
  5042. case "region_product_name":
  5043. if (World.RegionInfo.RegionType != String.Empty)
  5044. return World.RegionInfo.RegionType;
  5045. else
  5046. return "";
  5047. case "region_product_sku":
  5048. return "OpenSim";
  5049. case "region_start_time":
  5050. return World.UnixStartTime.ToString();
  5051. case "region_up_time":
  5052. int time = Util.UnixTimeSinceEpoch() - World.UnixStartTime;
  5053. return time.ToString();
  5054. case "sim_channel":
  5055. return "OpenSim";
  5056. case "sim_version":
  5057. return World.GetSimulatorVersion();
  5058. case "simulator_hostname":
  5059. IUrlModule UrlModule = World.RequestModuleInterface<IUrlModule>();
  5060. return UrlModule.ExternalHostNameForLSL;
  5061. case "region_max_prims":
  5062. return World.RegionInfo.ObjectCapacity.ToString();
  5063. case "region_object_bonus":
  5064. return World.RegionInfo.RegionSettings.ObjectBonus.ToString();
  5065. case "whisper_range":
  5066. return m_whisperdistance.ToString();
  5067. case "chat_range":
  5068. return m_saydistance.ToString();
  5069. case "shout_range":
  5070. return m_shoutdistance.ToString();
  5071. default:
  5072. return "";
  5073. }
  5074. }
  5075. /// <summary>
  5076. /// Insert the list identified by <paramref name="src"/> into the
  5077. /// list designated by <paramref name="dest"/> such that the first
  5078. /// new element has the index specified by <paramref name="index"/>
  5079. /// </summary>
  5080. public LSL_List llListInsertList(LSL_List dest, LSL_List src, int index)
  5081. {
  5082. LSL_List pref;
  5083. LSL_List suff;
  5084. if (index < 0)
  5085. {
  5086. index += dest.Length;
  5087. if (index < 0)
  5088. {
  5089. index = 0;
  5090. }
  5091. }
  5092. if (index != 0)
  5093. {
  5094. pref = dest.GetSublist(0,index-1);
  5095. if (index < dest.Length)
  5096. {
  5097. suff = dest.GetSublist(index,-1);
  5098. return pref + src + suff;
  5099. }
  5100. else
  5101. {
  5102. return pref + src;
  5103. }
  5104. }
  5105. else
  5106. {
  5107. if (index < dest.Length)
  5108. {
  5109. suff = dest.GetSublist(index,-1);
  5110. return src + suff;
  5111. }
  5112. else
  5113. {
  5114. return src;
  5115. }
  5116. }
  5117. }
  5118. private static bool ListFind_areEqual(object l, object r)
  5119. {
  5120. if (l is null || r is null)
  5121. return false;
  5122. if (l is LSL_Integer lli)
  5123. {
  5124. if (r is LSL_Integer rli)
  5125. return lli.value == rli.value;
  5126. if (r is int ri)
  5127. return lli.value == ri;
  5128. return false;
  5129. }
  5130. if (l is int li)
  5131. {
  5132. if (r is LSL_Integer rli)
  5133. return li == rli.value;
  5134. if (r is int ri)
  5135. return li == ri;
  5136. return false;
  5137. }
  5138. if (l is LSL_Float llf)
  5139. {
  5140. if (r is LSL_Float rlf)
  5141. return llf.value == rlf.value;
  5142. if (r is float rf)
  5143. return llf.value == (double)rf;
  5144. if (r is double rd)
  5145. return llf.value == rd;
  5146. return false;
  5147. }
  5148. if (l is double ld)
  5149. {
  5150. if (r is LSL_Float rlf)
  5151. return ld == rlf.value;
  5152. if (r is float rf)
  5153. return ld == (double)rf;
  5154. if (r is double rd)
  5155. return ld == rd;
  5156. return false;
  5157. }
  5158. if (l is float lf)
  5159. {
  5160. if (r is LSL_Float rlf)
  5161. return lf == (float)rlf.value;
  5162. if (r is float rf)
  5163. return lf == rf;
  5164. if (r is double rd)
  5165. return lf == (float)rd;
  5166. return false;
  5167. }
  5168. if (l is LSL_String lls)
  5169. {
  5170. if (r is LSL_String rls)
  5171. return lls.m_string.Equals(rls.m_string, StringComparison.Ordinal);
  5172. if (r is string rs)
  5173. return lls.m_string.Equals(rs, StringComparison.Ordinal);
  5174. return false;
  5175. }
  5176. if (l is string ls)
  5177. {
  5178. if (r is LSL_String rls)
  5179. return ls.Equals(rls.m_string, StringComparison.Ordinal);
  5180. if (r is string rs)
  5181. return ls.Equals(rs, StringComparison.Ordinal);
  5182. if (r is LSL_Key rlk)
  5183. return ls.Equals(rlk.m_string, StringComparison.OrdinalIgnoreCase);
  5184. return false;
  5185. }
  5186. if(l is LSL_Key llk)
  5187. {
  5188. if (r is LSL_Key rlk)
  5189. return llk.m_string.Equals(rlk.m_string, StringComparison.OrdinalIgnoreCase);
  5190. if (r is string rk)
  5191. return llk.m_string.Equals(rk, StringComparison.OrdinalIgnoreCase);
  5192. }
  5193. if (l is LSL_Vector llv)
  5194. {
  5195. if(r is LSL_Vector rlv)
  5196. return llv.Equals(rlv);
  5197. return false;
  5198. }
  5199. if (l is LSL_Rotation llr)
  5200. {
  5201. if(r is LSL_Rotation rlr)
  5202. return llr.Equals(rlr);
  5203. return false;
  5204. }
  5205. return false;
  5206. }
  5207. /// <summary>
  5208. /// Returns the index of the first occurrence of test
  5209. /// in src.
  5210. /// </summary>
  5211. /// <param name="src">Source list</param>
  5212. /// <param name="test">List to search for</param>
  5213. /// <returns>
  5214. /// The index number of the point in src where test was found if it was found.
  5215. /// Otherwise returns -1
  5216. /// </returns>
  5217. public LSL_Integer llListFindList(LSL_List src, LSL_List test)
  5218. {
  5219. if (src.Length == 0)
  5220. return -1;
  5221. if (test.Length == 0)
  5222. return 0;
  5223. if (test.Length > src.Length)
  5224. return -1;
  5225. object test0 = test[0];
  5226. for (int i = 0; i <= src.Length - test.Length; i++)
  5227. {
  5228. if (ListFind_areEqual(test0, src[i]))
  5229. {
  5230. int k = i + 1;
  5231. int j = 1;
  5232. while(j < test.Length)
  5233. {
  5234. if (!ListFind_areEqual(test[j], src[k]))
  5235. break;
  5236. ++j;
  5237. ++k;
  5238. }
  5239. if (j == test.Length)
  5240. return i;
  5241. }
  5242. }
  5243. return -1;
  5244. }
  5245. public LSL_Integer llListFindStrided(LSL_List src, LSL_List test, LSL_Integer lstart, LSL_Integer lend, LSL_Integer lstride)
  5246. {
  5247. if (src.Length == 0)
  5248. return -1;
  5249. if (test.Length == 0)
  5250. return 0;
  5251. if (test.Length > src.Length)
  5252. return -1;
  5253. int start = lstart.value;
  5254. if (start < 0)
  5255. {
  5256. start += src.Length;
  5257. if (start < 0)
  5258. return -1;
  5259. }
  5260. else if (start >= src.Length)
  5261. return -1;
  5262. int end = lend.value;
  5263. if (end < 0)
  5264. {
  5265. end += src.Length;
  5266. if (end < 0)
  5267. return -1;
  5268. end -= test.Length - 1;
  5269. }
  5270. else if (end >= src.Length)
  5271. end = src.Length - test.Length;
  5272. int stride = lstride.value;
  5273. if (stride < 1)
  5274. stride = 1;
  5275. object test0 = test[0];
  5276. for (int i = start; i <= end; i += stride)
  5277. {
  5278. if (ListFind_areEqual(test0, src[i]))
  5279. {
  5280. int k = i + 1;
  5281. int j = 1;
  5282. while (j < test.Length)
  5283. {
  5284. if (!ListFind_areEqual(test[j], src[k]))
  5285. break;
  5286. ++j;
  5287. ++k;
  5288. }
  5289. if (j == test.Length)
  5290. return i;
  5291. }
  5292. }
  5293. return -1;
  5294. }
  5295. public LSL_String llGetObjectName()
  5296. {
  5297. return m_host.Name ?? string.Empty;
  5298. }
  5299. public void llSetObjectName(string name)
  5300. {
  5301. m_host.Name = name ?? String.Empty;
  5302. }
  5303. public LSL_String llGetDate()
  5304. {
  5305. return DateTime.UtcNow.ToString("yyyy-MM-dd");
  5306. }
  5307. public LSL_Integer llEdgeOfWorld(LSL_Vector pos, LSL_Vector dir)
  5308. {
  5309. if(dir.x == 0 && dir.y == 0)
  5310. return 1; // SL wiki
  5311. float rsx = World.RegionInfo.RegionSizeX;
  5312. float rsy = World.RegionInfo.RegionSizeY;
  5313. // can understand what sl does if position is not in region, so do something :)
  5314. float px = Math.Clamp((float)pos.x, 0.5f, rsx - 0.5f);
  5315. float py = Math.Clamp((float)pos.y, 0.5f, rsy - 0.5f);
  5316. float ex, ey;
  5317. if (dir.x == 0)
  5318. {
  5319. ex = px;
  5320. ey = dir.y > 0 ? rsy + 1.0f : -1.0f;
  5321. }
  5322. else if(dir.y == 0)
  5323. {
  5324. ex = dir.x > 0 ? rsx + 1.0f : -1.0f;
  5325. ey = py;
  5326. }
  5327. else
  5328. {
  5329. float dx = (float) dir.x;
  5330. float dy = (float) dir.y;
  5331. float t1 = dx * dx + dy * dy;
  5332. t1 = (float)Math.Sqrt(t1);
  5333. dx /= t1;
  5334. dy /= t1;
  5335. if(dx > 0)
  5336. t1 = (rsx + 1f - px)/dx;
  5337. else
  5338. t1 = -(px + 1f)/dx;
  5339. float t2;
  5340. if(dy > 0)
  5341. t2 = (rsy + 1f - py)/dy;
  5342. else
  5343. t2 = -(py + 1f)/dy;
  5344. if(t1 > t2)
  5345. t1 = t2;
  5346. ex = px + t1 * dx;
  5347. ey = py + t1 * dy;
  5348. }
  5349. ex += World.RegionInfo.WorldLocX;
  5350. ey += World.RegionInfo.WorldLocY;
  5351. if(World.GridService.GetRegionByPosition(RegionScopeID, (int)ex, (int)ey) != null)
  5352. return 0;
  5353. return 1;
  5354. }
  5355. /// <summary>
  5356. /// Not fully implemented yet. Still to do:-
  5357. /// AGENT_BUSY
  5358. /// Remove as they are done
  5359. /// </summary>
  5360. static readonly UUID busyAnimation = new("efcf670c-2d18-8128-973a-034ebc806b67");
  5361. public LSL_Integer llGetAgentInfo(LSL_Key id)
  5362. {
  5363. if (!UUID.TryParse(id, out UUID key) || key.IsZero())
  5364. {
  5365. return 0;
  5366. }
  5367. ScenePresence agent = World.GetScenePresence(key);
  5368. if (agent == null)
  5369. {
  5370. return 0;
  5371. }
  5372. if (agent.IsChildAgent || agent.IsDeleted)
  5373. return 0; // Fail if they are not in the same region
  5374. int flags = 0;
  5375. try
  5376. {
  5377. // note: in OpenSim, sitting seems to cancel AGENT_ALWAYS_RUN, unlike SL
  5378. if (agent.SetAlwaysRun)
  5379. {
  5380. flags |= ScriptBaseClass.AGENT_ALWAYS_RUN;
  5381. }
  5382. if (agent.HasAttachments())
  5383. {
  5384. flags |= ScriptBaseClass.AGENT_ATTACHMENTS;
  5385. if (agent.HasScriptedAttachments())
  5386. flags |= ScriptBaseClass.AGENT_SCRIPTED;
  5387. }
  5388. if ((agent.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0)
  5389. {
  5390. flags |= ScriptBaseClass.AGENT_FLYING;
  5391. flags |= ScriptBaseClass.AGENT_IN_AIR; // flying always implies in-air, even if colliding with e.g. a wall
  5392. }
  5393. if ((agent.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_AWAY) != 0)
  5394. {
  5395. flags |= ScriptBaseClass.AGENT_AWAY;
  5396. }
  5397. if(agent.Animator.HasAnimation(busyAnimation))
  5398. {
  5399. flags |= ScriptBaseClass.AGENT_BUSY;
  5400. }
  5401. // seems to get unset, even if in mouselook, when avatar is sitting on a prim???
  5402. if ((agent.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0)
  5403. {
  5404. flags |= ScriptBaseClass.AGENT_MOUSELOOK;
  5405. }
  5406. if ((agent.State & (byte)AgentState.Typing) != 0)
  5407. {
  5408. flags |= ScriptBaseClass.AGENT_TYPING;
  5409. }
  5410. string agentMovementAnimation = agent.Animator.CurrentMovementAnimation;
  5411. if (agentMovementAnimation == "CROUCH")
  5412. {
  5413. flags |= ScriptBaseClass.AGENT_CROUCHING;
  5414. }
  5415. else if (agentMovementAnimation == "WALK" || agentMovementAnimation == "CROUCHWALK")
  5416. {
  5417. flags |= ScriptBaseClass.AGENT_WALKING;
  5418. }
  5419. // not colliding implies in air. Note: flying also implies in-air, even if colliding (see above)
  5420. // note: AGENT_IN_AIR and AGENT_WALKING seem to be mutually exclusive states in SL.
  5421. // note: this may need some tweaking when walking downhill. you "fall down" for a brief instant
  5422. // and don't collide when walking downhill, which instantly registers as in-air, briefly. should
  5423. // there be some minimum non-collision threshold time before claiming the avatar is in-air?
  5424. if ((flags & ScriptBaseClass.AGENT_WALKING) == 0 && !agent.IsColliding )
  5425. {
  5426. flags |= ScriptBaseClass.AGENT_IN_AIR;
  5427. }
  5428. if (agent.ParentPart != null)
  5429. {
  5430. flags |= ScriptBaseClass.AGENT_ON_OBJECT;
  5431. flags |= ScriptBaseClass.AGENT_SITTING;
  5432. }
  5433. if (agent.Animator.Animations.ImplicitDefaultAnimation.AnimID.Equals(DefaultAvatarAnimations.AnimsUUIDbyName["SIT_GROUND_CONSTRAINED"]))
  5434. {
  5435. flags |= ScriptBaseClass.AGENT_SITTING;
  5436. }
  5437. if (agent.Appearance.VisualParams[(int)AvatarAppearance.VPElement.SHAPE_MALE] > 0)
  5438. {
  5439. flags |= ScriptBaseClass.AGENT_MALE;
  5440. }
  5441. }
  5442. catch
  5443. {
  5444. return 0;
  5445. }
  5446. return flags;
  5447. }
  5448. public LSL_String llGetAgentLanguage(LSL_Key id)
  5449. {
  5450. // This should only return a value if the avatar is in the same region, but eh. idc.
  5451. if (World.AgentPreferencesService == null)
  5452. {
  5453. Error("llGetAgentLanguage", "No AgentPreferencesService present");
  5454. }
  5455. else
  5456. {
  5457. if (UUID.TryParse(id, out UUID key) && key.IsNotZero())
  5458. {
  5459. return new LSL_String(World.AgentPreferencesService.GetLang(key));
  5460. }
  5461. }
  5462. return new LSL_String("en-us");
  5463. }
  5464. /// <summary>
  5465. /// http://wiki.secondlife.com/wiki/LlGetAgentList
  5466. /// The list of options is currently not used in SL
  5467. /// scope is one of:-
  5468. /// AGENT_LIST_REGION - all in the region
  5469. /// AGENT_LIST_PARCEL - all in the same parcel as the scripted object
  5470. /// AGENT_LIST_PARCEL_OWNER - all in any parcel owned by the owner of the
  5471. /// current parcel.
  5472. /// AGENT_LIST_EXCLUDENPC ignore NPCs (bit mask)
  5473. /// </summary>
  5474. public LSL_List llGetAgentList(LSL_Integer scope, LSL_List options)
  5475. {
  5476. // do our bit masks part
  5477. bool noNPC = (scope & ScriptBaseClass.AGENT_LIST_EXCLUDENPC) !=0;
  5478. // remove bit masks part
  5479. scope &= ~ ScriptBaseClass.AGENT_LIST_EXCLUDENPC;
  5480. // the constants are 1, 2 and 4 so bits are being set, but you
  5481. // get an error "INVALID_SCOPE" if it is anything but 1, 2 and 4
  5482. bool regionWide = scope == ScriptBaseClass.AGENT_LIST_REGION;
  5483. bool parcelOwned = scope == ScriptBaseClass.AGENT_LIST_PARCEL_OWNER;
  5484. bool parcel = scope == ScriptBaseClass.AGENT_LIST_PARCEL;
  5485. LSL_List result = new();
  5486. if (!regionWide && !parcelOwned && !parcel)
  5487. {
  5488. result.Add("INVALID_SCOPE");
  5489. return result;
  5490. }
  5491. ILandObject land;
  5492. UUID id = UUID.Zero;
  5493. if (parcel || parcelOwned)
  5494. {
  5495. land = World.LandChannel.GetLandObject(m_host.ParentGroup.RootPart.GetWorldPosition());
  5496. if (land == null)
  5497. {
  5498. id = UUID.Zero;
  5499. }
  5500. else
  5501. {
  5502. if (parcelOwned)
  5503. {
  5504. id = land.LandData.OwnerID;
  5505. }
  5506. else
  5507. {
  5508. id = land.LandData.GlobalID;
  5509. }
  5510. }
  5511. }
  5512. World.ForEachRootScenePresence(
  5513. delegate (ScenePresence ssp)
  5514. {
  5515. if(noNPC && ssp.IsNPC)
  5516. return;
  5517. // Gods are not listed in SL
  5518. if (!ssp.IsDeleted && !ssp.IsViewerUIGod && !ssp.IsChildAgent)
  5519. {
  5520. if (!regionWide)
  5521. {
  5522. land = World.LandChannel.GetLandObject(ssp.AbsolutePosition);
  5523. if (land != null)
  5524. {
  5525. if (parcelOwned && land.LandData.OwnerID.Equals(id) ||
  5526. parcel && land.LandData.GlobalID.Equals(id))
  5527. {
  5528. result.Add(new LSL_Key(ssp.UUID.ToString()));
  5529. }
  5530. }
  5531. }
  5532. else
  5533. {
  5534. result.Add(new LSL_Key(ssp.UUID.ToString()));
  5535. }
  5536. }
  5537. // Maximum of 100 results
  5538. if (result.Length > 99)
  5539. {
  5540. return;
  5541. }
  5542. }
  5543. );
  5544. return result;
  5545. }
  5546. public void llAdjustSoundVolume(LSL_Float volume)
  5547. {
  5548. m_host.AdjustSoundGain(volume);
  5549. ScriptSleep(m_sleepMsOnAdjustSoundVolume);
  5550. }
  5551. public void llLinkAdjustSoundVolume(LSL_Integer linknumber, LSL_Float volume)
  5552. {
  5553. foreach (SceneObjectPart part in GetLinkParts(linknumber))
  5554. part.AdjustSoundGain(volume);
  5555. ScriptSleep(m_sleepMsOnAdjustSoundVolume);
  5556. }
  5557. public void llSetSoundRadius(double radius)
  5558. {
  5559. m_host.SoundRadius = radius;
  5560. }
  5561. public void llLinkSetSoundRadius(int linknumber, double radius)
  5562. {
  5563. foreach (SceneObjectPart sop in GetLinkParts(linknumber))
  5564. sop.SoundRadius = radius;
  5565. }
  5566. public LSL_String llKey2Name(LSL_Key id)
  5567. {
  5568. if (UUID.TryParse(id, out UUID key) && key.IsNotZero())
  5569. {
  5570. ScenePresence presence = World.GetScenePresence(key);
  5571. if (presence is not null)
  5572. return presence.Name;
  5573. SceneObjectPart sop = World.GetSceneObjectPart(key);
  5574. if (sop is not null)
  5575. return sop.Name;
  5576. }
  5577. return LSL_String.Empty;
  5578. }
  5579. public LSL_Key llName2Key(LSL_String name)
  5580. {
  5581. if(string.IsNullOrWhiteSpace(name))
  5582. return ScriptBaseClass.NULL_KEY;
  5583. int nc = Util.ParseAvatarName(name, out string firstName, out string lastName, out string server);
  5584. if (nc < 2)
  5585. return ScriptBaseClass.NULL_KEY;
  5586. string sname;
  5587. if (nc == 2)
  5588. sname = firstName + " " + lastName;
  5589. else
  5590. sname = firstName + "." + lastName + " @" + server;
  5591. foreach (ScenePresence sp in World.GetScenePresences())
  5592. {
  5593. if (sp.IsDeleted || sp.IsChildAgent)
  5594. continue;
  5595. if (String.Compare(sname, sp.Name, true) == 0)
  5596. return sp.UUID.ToString();
  5597. }
  5598. return ScriptBaseClass.NULL_KEY;
  5599. }
  5600. public LSL_Key llRequestUserKey(LSL_String username)
  5601. {
  5602. if (string.IsNullOrWhiteSpace(username))
  5603. return ScriptBaseClass.NULL_KEY;
  5604. int nc = Util.ParseAvatarName(username, out string firstName, out string lastName, out string server);
  5605. if (nc < 2)
  5606. return ScriptBaseClass.NULL_KEY;
  5607. string sname;
  5608. if (nc == 2)
  5609. sname = firstName + " " + lastName;
  5610. else
  5611. sname = firstName + "." + lastName + " @" + server;
  5612. foreach (ScenePresence sp in World.GetScenePresences())
  5613. {
  5614. if (sp.IsDeleted || sp.IsChildAgent)
  5615. continue;
  5616. if (String.Compare(sname, sp.Name, true) == 0)
  5617. {
  5618. string ftid = m_AsyncCommands.DataserverPlugin.RequestWithImediatePost(m_host.LocalId,
  5619. m_item.ItemID, sp.UUID.ToString());
  5620. return ftid;
  5621. }
  5622. }
  5623. void act(string eventID)
  5624. {
  5625. string reply = ScriptBaseClass.NULL_KEY;
  5626. UUID userID = UUID.Zero;
  5627. IUserManagement userManager = World.RequestModuleInterface<IUserManagement>();
  5628. if (nc == 2)
  5629. {
  5630. if (userManager is not null)
  5631. {
  5632. userID = userManager.GetUserIdByName(firstName, lastName);
  5633. if (!userID.IsZero())
  5634. reply = userID.ToString();
  5635. }
  5636. }
  5637. else
  5638. {
  5639. string url = "http://" + server;
  5640. if (Uri.TryCreate(url, UriKind.Absolute, out Uri dummy))
  5641. {
  5642. bool notfound = true;
  5643. if (userManager is not null)
  5644. {
  5645. string hgfirst = firstName + "." + lastName;
  5646. string hglast = "@" + server;
  5647. userID = userManager.GetUserIdByName(hgfirst, hglast);
  5648. if (!userID.IsZero())
  5649. {
  5650. notfound = false;
  5651. reply = userID.ToString();
  5652. }
  5653. }
  5654. if (notfound)
  5655. {
  5656. try
  5657. {
  5658. UserAgentServiceConnector userConnection = new(url);
  5659. if (userConnection is not null)
  5660. {
  5661. userID = userConnection.GetUUID(firstName, lastName);
  5662. if (!userID.IsZero())
  5663. {
  5664. userManager?.AddUser(userID, firstName, lastName, url);
  5665. reply = userID.ToString();
  5666. }
  5667. }
  5668. }
  5669. catch
  5670. {
  5671. reply = ScriptBaseClass.NULL_KEY;
  5672. }
  5673. }
  5674. }
  5675. }
  5676. m_AsyncCommands.DataserverPlugin.DataserverReply(eventID, reply);
  5677. }
  5678. UUID tid = m_AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, act);
  5679. ScriptSleep(m_sleepMsOnRequestAgentData);
  5680. return tid.ToString();
  5681. }
  5682. public void llSetTextureAnim(int mode, int face, int sizex, int sizey, double start, double length, double rate)
  5683. {
  5684. SetTextureAnim(m_host, mode, face, sizex, sizey, start, length, rate);
  5685. }
  5686. public void llSetLinkTextureAnim(int linknumber, int mode, int face, int sizex, int sizey, double start, double length, double rate)
  5687. {
  5688. List<SceneObjectPart> parts = GetLinkParts(linknumber);
  5689. try
  5690. {
  5691. foreach (SceneObjectPart part in parts)
  5692. {
  5693. SetTextureAnim(part, mode, face, sizex, sizey, start, length, rate);
  5694. }
  5695. }
  5696. finally
  5697. {
  5698. }
  5699. }
  5700. private static void SetTextureAnim(SceneObjectPart part, int mode, int face, int sizex, int sizey, double start, double length, double rate)
  5701. {
  5702. //ALL_SIDES
  5703. if (face == ScriptBaseClass.ALL_SIDES)
  5704. face = 255;
  5705. Primitive.TextureAnimation pTexAnim = new()
  5706. {
  5707. Flags = (Primitive.TextureAnimMode)mode,
  5708. Face = (uint)face,
  5709. Length = (float)length,
  5710. Rate = (float)rate,
  5711. SizeX = (uint)sizex,
  5712. SizeY = (uint)sizey,
  5713. Start = (float)start
  5714. };
  5715. part.AddTextureAnimation(pTexAnim);
  5716. part.SendFullUpdateToAllClients();
  5717. part.ParentGroup.HasGroupChanged = true;
  5718. }
  5719. public void llTriggerSoundLimited(string sound, double volume, LSL_Vector top_north_east,
  5720. LSL_Vector bottom_south_west)
  5721. {
  5722. m_SoundModule?.TriggerSoundLimited(m_host.UUID,
  5723. ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound), volume,
  5724. bottom_south_west, top_north_east);
  5725. }
  5726. public void llEjectFromLand(LSL_Key pest)
  5727. {
  5728. if (UUID.TryParse(pest, out UUID agentID) && agentID.IsNotZero())
  5729. {
  5730. ScenePresence presence = World.GetScenePresence(agentID);
  5731. if (presence != null)
  5732. {
  5733. // agent must be over the owners land
  5734. ILandObject land = World.LandChannel.GetLandObject(presence.AbsolutePosition);
  5735. if (land == null)
  5736. return;
  5737. if (m_host.OwnerID.Equals(land.LandData.OwnerID))
  5738. {
  5739. Vector3 p = World.GetNearestAllowedPosition(presence, land);
  5740. presence.TeleportOnEject(p);
  5741. presence.ControllingClient.SendAlertMessage("You have been ejected from this land");
  5742. }
  5743. }
  5744. }
  5745. ScriptSleep(m_sleepMsOnEjectFromLand);
  5746. }
  5747. public LSL_List llParseString2List(string str, LSL_List separators, LSL_List in_spacers)
  5748. {
  5749. return ParseString2List(str, separators, in_spacers, false);
  5750. }
  5751. public LSL_Integer llOverMyLand(string id)
  5752. {
  5753. if (UUID.TryParse(id, out UUID key) && key.IsNotZero())
  5754. {
  5755. try
  5756. {
  5757. ScenePresence presence = World.GetScenePresence(key);
  5758. if (presence != null) // object is an avatar
  5759. {
  5760. if (m_host.OwnerID.Equals(World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID))
  5761. return 1;
  5762. }
  5763. else // object is not an avatar
  5764. {
  5765. SceneObjectPart obj = World.GetSceneObjectPart(key);
  5766. if (obj != null &&
  5767. m_host.OwnerID.Equals(World.LandChannel.GetLandObject(obj.AbsolutePosition).LandData.OwnerID))
  5768. return 1;
  5769. }
  5770. }
  5771. catch { }
  5772. }
  5773. return 0;
  5774. }
  5775. public LSL_Key llGetLandOwnerAt(LSL_Vector pos)
  5776. {
  5777. ILandObject land = World.LandChannel.GetLandObject((float)pos.x, (float)pos.y);
  5778. if (land == null)
  5779. return ScriptBaseClass.NULL_KEY;
  5780. return land.LandData.OwnerID.ToString();
  5781. }
  5782. /// <summary>
  5783. /// According to http://lslwiki.net/lslwiki/wakka.php?wakka=llGetAgentSize
  5784. /// only the height of avatars vary and that says:
  5785. /// Width (x) and depth (y) are constant. (0.45m and 0.6m respectively).
  5786. /// </summary>
  5787. public LSL_Vector llGetAgentSize(LSL_Key id)
  5788. {
  5789. if(!UUID.TryParse(id, out UUID avID) || avID.IsZero())
  5790. return ScriptBaseClass.ZERO_VECTOR;
  5791. ScenePresence avatar = World.GetScenePresence(avID);
  5792. if (avatar == null || avatar.IsChildAgent) // Fail if not in the same region
  5793. return ScriptBaseClass.ZERO_VECTOR;
  5794. return new LSL_Vector(avatar.Appearance.AvatarSize);
  5795. }
  5796. public LSL_Integer llSameGroup(string id)
  5797. {
  5798. if (!UUID.TryParse(id, out UUID uuid) || uuid.IsZero())
  5799. return 0;
  5800. // Check if it's a group key
  5801. if (uuid.Equals(m_host.ParentGroup.RootPart.GroupID))
  5802. return 1;
  5803. // Handle object case
  5804. SceneObjectPart part = World.GetSceneObjectPart(uuid);
  5805. if (part != null)
  5806. {
  5807. if(part.ParentGroup.IsAttachment)
  5808. {
  5809. uuid = part.ParentGroup.AttachedAvatar;
  5810. }
  5811. else
  5812. {
  5813. // This will handle both deed and non-deed and also the no
  5814. // group case
  5815. if (part.ParentGroup.RootPart.GroupID.Equals(m_host.ParentGroup.RootPart.GroupID))
  5816. return 1;
  5817. return 0;
  5818. }
  5819. }
  5820. // Handle the case where id names an avatar
  5821. ScenePresence presence = World.GetScenePresence(uuid);
  5822. if (presence != null)
  5823. {
  5824. if (presence.IsChildAgent)
  5825. return 0;
  5826. IClientAPI client = presence.ControllingClient;
  5827. if (m_host.ParentGroup.RootPart.GroupID.Equals(client.ActiveGroupId))
  5828. return 1;
  5829. return 0;
  5830. }
  5831. return 0;
  5832. }
  5833. public void llUnSit(string id)
  5834. {
  5835. if (!UUID.TryParse(id, out UUID key) || key.IsZero())
  5836. return;
  5837. ScenePresence av = World.GetScenePresence(key);
  5838. if(av == null)
  5839. return;
  5840. List<ScenePresence> sittingAvatars = m_host.ParentGroup.GetSittingAvatars();
  5841. if (sittingAvatars.Contains(av))
  5842. {
  5843. av.StandUp();
  5844. }
  5845. else
  5846. {
  5847. // If the object owner also owns the parcel
  5848. // or
  5849. // if the land is group owned and the object is group owned by the same group
  5850. // or
  5851. // if the object is owned by a person with estate access.
  5852. ILandObject parcel = World.LandChannel.GetLandObject(av.AbsolutePosition);
  5853. if (parcel != null)
  5854. {
  5855. if (m_host.OwnerID.Equals(parcel.LandData.OwnerID) ||
  5856. (m_host.OwnerID.Equals(m_host.GroupID) && m_host.GroupID.Equals(parcel.LandData.GroupID)
  5857. && parcel.LandData.IsGroupOwned) || World.Permissions.IsGod(m_host.OwnerID))
  5858. {
  5859. av.StandUp();
  5860. }
  5861. }
  5862. }
  5863. }
  5864. public LSL_Vector llGroundSlope(LSL_Vector offset)
  5865. {
  5866. //Get the slope normal. This gives us the equation of the plane tangent to the slope.
  5867. LSL_Vector vsn = llGroundNormal(offset);
  5868. //Plug the x,y coordinates of the slope normal into the equation of the plane to get
  5869. //the height of that point on the plane. The resulting vector gives the slope.
  5870. Vector3 vsl = vsn;
  5871. vsl.Z = (float)(((vsn.x * vsn.x) + (vsn.y * vsn.y)) / (-1 * vsn.z));
  5872. vsl.Normalize();
  5873. //Normalization might be overkill here
  5874. vsn.x = vsl.X;
  5875. vsn.y = vsl.Y;
  5876. vsn.z = vsl.Z;
  5877. return vsn;
  5878. }
  5879. public LSL_Vector llGroundNormal(LSL_Vector offset)
  5880. {
  5881. Vector3 pos = m_host.GetWorldPosition();
  5882. int posX = (int)(pos.X + (float)offset.x);
  5883. int posY = (int)(pos.Y + (float)offset.y);
  5884. // Clamp to valid position
  5885. if (posX < 0)
  5886. posX = 0;
  5887. else if (posX >= World.Heightmap.Width)
  5888. posX = World.Heightmap.Width - 1;
  5889. if (posY < 0)
  5890. posY = 0;
  5891. else if (posY >= World.Heightmap.Height)
  5892. posY = World.Heightmap.Height - 1;
  5893. //Find two points in addition to the position to define a plane
  5894. float h0 = (float)World.Heightmap[(int)pos.X, (int)pos.Y];
  5895. float h1;
  5896. float h2;
  5897. int posxplus = posX + 1;
  5898. if (posxplus >= World.Heightmap.Width)
  5899. h1 = h0;
  5900. else
  5901. h1 = (float)World.Heightmap[posxplus, posY];
  5902. int posyplus = posY + 1;
  5903. if (posyplus >= World.Heightmap.Height)
  5904. h2 = h0;
  5905. else
  5906. h2 = (float)World.Heightmap[posX, posyplus];
  5907. Vector3 vsn = new(h0 - h1, h0 - h2, 1.0f);
  5908. vsn.Normalize();
  5909. return new LSL_Vector(vsn);
  5910. }
  5911. public LSL_Vector llGroundContour(LSL_Vector offset)
  5912. {
  5913. LSL_Vector x = llGroundSlope(offset);
  5914. return new LSL_Vector(-x.y, x.x, 0.0);
  5915. }
  5916. public LSL_Integer llGetAttached()
  5917. {
  5918. return m_host.ParentGroup.AttachmentPoint;
  5919. }
  5920. public LSL_List llGetAttachedList(LSL_Key id)
  5921. {
  5922. if(!UUID.TryParse(id, out UUID avID) || avID.IsZero())
  5923. return new LSL_List("NOT_FOUND");
  5924. ScenePresence av = World.GetScenePresence(avID);
  5925. if (av is null || av.IsDeleted)
  5926. return new LSL_List("NOT_FOUND");
  5927. if (av.IsChildAgent || av.IsInTransit)
  5928. return new LSL_List("NOT_ON_REGION");
  5929. LSL_List AttachmentsList = new();
  5930. List<SceneObjectGroup> Attachments = av.GetAttachments();
  5931. foreach (SceneObjectGroup Attachment in Attachments)
  5932. {
  5933. if(Attachment.HasPrivateAttachmentPoint)
  5934. continue;
  5935. AttachmentsList.Add(new LSL_Key(Attachment.UUID.ToString()));
  5936. }
  5937. return AttachmentsList;
  5938. }
  5939. public virtual LSL_Integer llGetFreeMemory()
  5940. {
  5941. // Make scripts designed for Mono happy
  5942. return 65536;
  5943. }
  5944. public LSL_Integer llGetFreeURLs()
  5945. {
  5946. if (m_UrlModule != null)
  5947. return new LSL_Integer(m_UrlModule.GetFreeUrls());
  5948. return new LSL_Integer(0);
  5949. }
  5950. public LSL_String llGetRegionName()
  5951. {
  5952. return m_regionName;
  5953. }
  5954. public LSL_Float llGetRegionTimeDilation()
  5955. {
  5956. return (double)World.TimeDilation;
  5957. }
  5958. /// <summary>
  5959. /// Returns the value reported in the client Statistics window
  5960. /// </summary>
  5961. public LSL_Float llGetRegionFPS()
  5962. {
  5963. return World.StatsReporter.LastReportedSimFPS;
  5964. }
  5965. /* particle system rules should be coming into this routine as doubles, that is
  5966. rule[0] should be an integer from this list and rule[1] should be the arg
  5967. for the same integer. wiki.secondlife.com has most of this mapping, but some
  5968. came from http://www.caligari-designs.com/p4u2
  5969. We iterate through the list for 'Count' elements, incrementing by two for each
  5970. iteration and set the members of Primitive.ParticleSystem, one at a time.
  5971. */
  5972. public enum PrimitiveRule : int
  5973. {
  5974. PSYS_PART_FLAGS = 0,
  5975. PSYS_PART_START_COLOR = 1,
  5976. PSYS_PART_START_ALPHA = 2,
  5977. PSYS_PART_END_COLOR = 3,
  5978. PSYS_PART_END_ALPHA = 4,
  5979. PSYS_PART_START_SCALE = 5,
  5980. PSYS_PART_END_SCALE = 6,
  5981. PSYS_PART_MAX_AGE = 7,
  5982. PSYS_SRC_ACCEL = 8,
  5983. PSYS_SRC_PATTERN = 9,
  5984. PSYS_SRC_INNERANGLE = 10,
  5985. PSYS_SRC_OUTERANGLE = 11,
  5986. PSYS_SRC_TEXTURE = 12,
  5987. PSYS_SRC_BURST_RATE = 13,
  5988. PSYS_SRC_BURST_PART_COUNT = 15,
  5989. PSYS_SRC_BURST_RADIUS = 16,
  5990. PSYS_SRC_BURST_SPEED_MIN = 17,
  5991. PSYS_SRC_BURST_SPEED_MAX = 18,
  5992. PSYS_SRC_MAX_AGE = 19,
  5993. PSYS_SRC_TARGET_KEY = 20,
  5994. PSYS_SRC_OMEGA = 21,
  5995. PSYS_SRC_ANGLE_BEGIN = 22,
  5996. PSYS_SRC_ANGLE_END = 23,
  5997. PSYS_PART_BLEND_FUNC_SOURCE = 24,
  5998. PSYS_PART_BLEND_FUNC_DEST = 25,
  5999. PSYS_PART_START_GLOW = 26,
  6000. PSYS_PART_END_GLOW = 27
  6001. }
  6002. internal static Primitive.ParticleSystem.ParticleDataFlags ConvertUINTtoFlags(uint flags)
  6003. {
  6004. Primitive.ParticleSystem.ParticleDataFlags returnval = Primitive.ParticleSystem.ParticleDataFlags.None;
  6005. return returnval;
  6006. }
  6007. protected static Primitive.ParticleSystem getNewParticleSystemWithSLDefaultValues()
  6008. {
  6009. return new Primitive.ParticleSystem()
  6010. {
  6011. PartStartColor = new Color4(1.0f, 1.0f, 1.0f, 1.0f),
  6012. PartEndColor = new Color4(1.0f, 1.0f, 1.0f, 1.0f),
  6013. PartStartScaleX = 1.0f,
  6014. PartStartScaleY = 1.0f,
  6015. PartEndScaleX = 1.0f,
  6016. PartEndScaleY = 1.0f,
  6017. BurstSpeedMin = 1.0f,
  6018. BurstSpeedMax = 1.0f,
  6019. BurstRate = 0.1f,
  6020. PartMaxAge = 10.0f,
  6021. BurstPartCount = 1,
  6022. BlendFuncSource = ScriptBaseClass.PSYS_PART_BF_SOURCE_ALPHA,
  6023. BlendFuncDest = ScriptBaseClass.PSYS_PART_BF_ONE_MINUS_SOURCE_ALPHA,
  6024. PartStartGlow = 0.0f,
  6025. PartEndGlow = 0.0f
  6026. };
  6027. }
  6028. public void llLinkParticleSystem(int linknumber, LSL_List rules)
  6029. {
  6030. List<SceneObjectPart> parts = GetLinkParts(linknumber);
  6031. foreach (SceneObjectPart part in parts)
  6032. {
  6033. SetParticleSystem(part, rules, "llLinkParticleSystem");
  6034. }
  6035. }
  6036. public void llParticleSystem(LSL_List rules)
  6037. {
  6038. SetParticleSystem(m_host, rules, "llParticleSystem");
  6039. }
  6040. public void SetParticleSystem(SceneObjectPart part, LSL_List rules, string originFunc, bool expire = false)
  6041. {
  6042. if (rules.Length == 0)
  6043. {
  6044. part.RemoveParticleSystem();
  6045. part.ParentGroup.HasGroupChanged = true;
  6046. }
  6047. else
  6048. {
  6049. Primitive.ParticleSystem prules = getNewParticleSystemWithSLDefaultValues();
  6050. LSL_Vector tempv;
  6051. float tempf;
  6052. int tmpi;
  6053. for (int i = 0; i < rules.Length; i += 2)
  6054. {
  6055. int psystype;
  6056. try
  6057. {
  6058. psystype = rules.GetIntegerItem(i);
  6059. }
  6060. catch (InvalidCastException)
  6061. {
  6062. Error(originFunc, string.Format("Error running particle system params index #{0}: particle system parameter type must be integer", i));
  6063. return;
  6064. }
  6065. switch (psystype)
  6066. {
  6067. case ScriptBaseClass.PSYS_PART_FLAGS:
  6068. try
  6069. {
  6070. prules.PartDataFlags = (Primitive.ParticleSystem.ParticleDataFlags)(uint)rules.GetIntegerItem(i + 1);
  6071. }
  6072. catch(InvalidCastException)
  6073. {
  6074. Error(originFunc, string.Format("Error running rule PSYS_PART_FLAGS: arg #{0} - parameter 1 must be integer", i + 1));
  6075. return;
  6076. }
  6077. break;
  6078. case ScriptBaseClass.PSYS_PART_START_COLOR:
  6079. try
  6080. {
  6081. tempv = rules.GetVector3Item(i + 1);
  6082. }
  6083. catch(InvalidCastException)
  6084. {
  6085. Error(originFunc, string.Format("Error running rule PSYS_PART_START_COLOR: arg #{0} - parameter 1 must be vector", i + 1));
  6086. return;
  6087. }
  6088. prules.PartStartColor.R = (float)tempv.x;
  6089. prules.PartStartColor.G = (float)tempv.y;
  6090. prules.PartStartColor.B = (float)tempv.z;
  6091. break;
  6092. case ScriptBaseClass.PSYS_PART_START_ALPHA:
  6093. try
  6094. {
  6095. tempf = rules.GetStrictFloatItem(i + 1);
  6096. }
  6097. catch(InvalidCastException)
  6098. {
  6099. Error(originFunc, string.Format("Error running rule PSYS_PART_START_ALPHA: arg #{0} - parameter 1 must be float", i + 1));
  6100. return;
  6101. }
  6102. prules.PartStartColor.A = tempf;
  6103. break;
  6104. case ScriptBaseClass.PSYS_PART_END_COLOR:
  6105. try
  6106. {
  6107. tempv = rules.GetVector3Item(i + 1);
  6108. }
  6109. catch(InvalidCastException)
  6110. {
  6111. Error(originFunc, string.Format("Error running rule PSYS_PART_END_COLOR: arg #{0} - parameter 1 must be vector", i + 1));
  6112. return;
  6113. }
  6114. prules.PartEndColor.R = (float)tempv.x;
  6115. prules.PartEndColor.G = (float)tempv.y;
  6116. prules.PartEndColor.B = (float)tempv.z;
  6117. break;
  6118. case ScriptBaseClass.PSYS_PART_END_ALPHA:
  6119. try
  6120. {
  6121. tempf = rules.GetStrictFloatItem(i + 1);
  6122. }
  6123. catch(InvalidCastException)
  6124. {
  6125. Error(originFunc, string.Format("Error running rule PSYS_PART_END_ALPHA: arg #{0} - parameter 1 must be float", i + 1));
  6126. return;
  6127. }
  6128. prules.PartEndColor.A = tempf;
  6129. break;
  6130. case ScriptBaseClass.PSYS_PART_START_SCALE:
  6131. try
  6132. {
  6133. tempv = rules.GetVector3Item(i + 1);
  6134. }
  6135. catch(InvalidCastException)
  6136. {
  6137. Error(originFunc, string.Format("Error running rule PSYS_PART_START_SCALE: arg #{0} - parameter 1 must be vector", i + 1));
  6138. return;
  6139. }
  6140. prules.PartStartScaleX = validParticleScale((float)tempv.x);
  6141. prules.PartStartScaleY = validParticleScale((float)tempv.y);
  6142. break;
  6143. case ScriptBaseClass.PSYS_PART_END_SCALE:
  6144. try
  6145. {
  6146. tempv = rules.GetVector3Item(i + 1);
  6147. }
  6148. catch(InvalidCastException)
  6149. {
  6150. Error(originFunc, string.Format("Error running rule PSYS_PART_END_SCALE: arg #{0} - parameter 1 must be vector", i + 1));
  6151. return;
  6152. }
  6153. prules.PartEndScaleX = validParticleScale((float)tempv.x);
  6154. prules.PartEndScaleY = validParticleScale((float)tempv.y);
  6155. break;
  6156. case ScriptBaseClass.PSYS_PART_MAX_AGE:
  6157. try
  6158. {
  6159. tempf = rules.GetStrictFloatItem(i + 1);
  6160. }
  6161. catch(InvalidCastException)
  6162. {
  6163. Error(originFunc, string.Format("Error running rule PSYS_PART_MAX_AGE: arg #{0} - parameter 1 must be float", i + 1));
  6164. return;
  6165. }
  6166. prules.PartMaxAge = tempf;
  6167. break;
  6168. case ScriptBaseClass.PSYS_SRC_ACCEL:
  6169. try
  6170. {
  6171. tempv = rules.GetVector3Item(i + 1);
  6172. }
  6173. catch(InvalidCastException)
  6174. {
  6175. Error(originFunc, string.Format("Error running rule PSYS_SRC_ACCEL: arg #{0} - parameter 1 must be vector", i + 1));
  6176. return;
  6177. }
  6178. prules.PartAcceleration.X = (float)tempv.x;
  6179. prules.PartAcceleration.Y = (float)tempv.y;
  6180. prules.PartAcceleration.Z = (float)tempv.z;
  6181. break;
  6182. case ScriptBaseClass.PSYS_SRC_PATTERN:
  6183. try
  6184. {
  6185. tmpi = rules.GetIntegerItem(i + 1);
  6186. }
  6187. catch(InvalidCastException)
  6188. {
  6189. Error(originFunc, string.Format("Error running rule PSYS_SRC_PATTERN: arg #{0} - parameter 1 must be integer", i + 1));
  6190. return;
  6191. }
  6192. prules.Pattern = (Primitive.ParticleSystem.SourcePattern)tmpi;
  6193. break;
  6194. // PSYS_SRC_INNERANGLE and PSYS_SRC_ANGLE_BEGIN use the same variables. The
  6195. // PSYS_SRC_OUTERANGLE and PSYS_SRC_ANGLE_END also use the same variable. The
  6196. // client tells the difference between the two by looking at the 0x02 bit in
  6197. // the PartFlags variable.
  6198. case ScriptBaseClass.PSYS_SRC_INNERANGLE:
  6199. try
  6200. {
  6201. tempf = rules.GetStrictFloatItem(i + 1);
  6202. }
  6203. catch(InvalidCastException)
  6204. {
  6205. Error(originFunc, string.Format("Error running rule PSYS_SRC_INNERANGLE: arg #{0} - parameter 1 must be float", i + 1));
  6206. return;
  6207. }
  6208. prules.InnerAngle = tempf;
  6209. prules.PartFlags &= 0xFFFFFFFD; // Make sure new angle format is off.
  6210. break;
  6211. case ScriptBaseClass.PSYS_SRC_OUTERANGLE:
  6212. try
  6213. {
  6214. tempf = rules.GetStrictFloatItem(i + 1);
  6215. }
  6216. catch(InvalidCastException)
  6217. {
  6218. Error(originFunc, string.Format("Error running rule PSYS_SRC_OUTERANGLE: arg #{0} - parameter 1 must be float", i + 1));
  6219. return;
  6220. }
  6221. prules.OuterAngle = tempf;
  6222. prules.PartFlags &= 0xFFFFFFFD; // Make sure new angle format is off.
  6223. break;
  6224. case ScriptBaseClass.PSYS_PART_BLEND_FUNC_SOURCE:
  6225. try
  6226. {
  6227. tmpi = rules.GetIntegerItem(i + 1);
  6228. }
  6229. catch(InvalidCastException)
  6230. {
  6231. Error(originFunc, string.Format("Error running rule PSYS_PART_BLEND_FUNC_SOURCE: arg #{0} - parameter 1 must be integer", i + 1));
  6232. return;
  6233. }
  6234. prules.BlendFuncSource = (byte)tmpi;
  6235. break;
  6236. case ScriptBaseClass.PSYS_PART_BLEND_FUNC_DEST:
  6237. try
  6238. {
  6239. tmpi = rules.GetIntegerItem(i + 1);
  6240. }
  6241. catch(InvalidCastException)
  6242. {
  6243. Error(originFunc, string.Format("Error running rule PSYS_PART_BLEND_FUNC_DEST: arg #{0} - parameter 1 must be integer", i + 1));
  6244. return;
  6245. }
  6246. prules.BlendFuncDest = (byte)tmpi;
  6247. break;
  6248. case ScriptBaseClass.PSYS_PART_START_GLOW:
  6249. try
  6250. {
  6251. tempf = rules.GetStrictFloatItem(i + 1);
  6252. }
  6253. catch(InvalidCastException)
  6254. {
  6255. Error(originFunc, string.Format("Error running rule PSYS_PART_START_GLOW: arg #{0} - parameter 1 must be float", i + 1));
  6256. return;
  6257. }
  6258. prules.PartStartGlow = tempf;
  6259. break;
  6260. case ScriptBaseClass.PSYS_PART_END_GLOW:
  6261. try
  6262. {
  6263. tempf = rules.GetStrictFloatItem(i + 1);
  6264. }
  6265. catch(InvalidCastException)
  6266. {
  6267. Error(originFunc, string.Format("Error running rule PSYS_PART_END_GLOW: arg #{0} - parameter 1 must be float", i + 1));
  6268. return;
  6269. }
  6270. prules.PartEndGlow = tempf;
  6271. break;
  6272. case ScriptBaseClass.PSYS_SRC_TEXTURE:
  6273. try
  6274. {
  6275. prules.Texture = ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, rules.GetStrictStringItem(i + 1));
  6276. }
  6277. catch(InvalidCastException)
  6278. {
  6279. Error(originFunc, string.Format("Error running rule PSYS_SRC_TEXTURE: arg #{0} - parameter 1 must be string or key", i + 1));
  6280. return;
  6281. }
  6282. break;
  6283. case ScriptBaseClass.PSYS_SRC_BURST_RATE:
  6284. try
  6285. {
  6286. tempf = rules.GetStrictFloatItem(i + 1);
  6287. }
  6288. catch(InvalidCastException)
  6289. {
  6290. Error(originFunc, string.Format("Error running rule PSYS_SRC_BURST_RATE: arg #{0} - parameter 1 must be float", i + 1));
  6291. return;
  6292. }
  6293. prules.BurstRate = tempf;
  6294. break;
  6295. case ScriptBaseClass.PSYS_SRC_BURST_PART_COUNT:
  6296. try
  6297. {
  6298. prules.BurstPartCount = (byte)rules.GetIntegerItem(i + 1);
  6299. }
  6300. catch(InvalidCastException)
  6301. {
  6302. Error(originFunc, string.Format("Error running rule PSYS_SRC_BURST_PART_COUNT: arg #{0} - parameter 1 must be integer", i + 1));
  6303. return;
  6304. }
  6305. break;
  6306. case ScriptBaseClass.PSYS_SRC_BURST_RADIUS:
  6307. try
  6308. {
  6309. tempf = rules.GetStrictFloatItem(i + 1);
  6310. }
  6311. catch(InvalidCastException)
  6312. {
  6313. Error(originFunc, string.Format("Error running rule PSYS_SRC_BURST_RADIUS: arg #{0} - parameter 1 must be float", i + 1));
  6314. return;
  6315. }
  6316. prules.BurstRadius = tempf;
  6317. break;
  6318. case ScriptBaseClass.PSYS_SRC_BURST_SPEED_MIN:
  6319. try
  6320. {
  6321. tempf = rules.GetStrictFloatItem(i + 1);
  6322. }
  6323. catch(InvalidCastException)
  6324. {
  6325. Error(originFunc, string.Format("Error running rule PSYS_SRC_BURST_SPEED_MIN: arg #{0} - parameter 1 must be float", i + 1));
  6326. return;
  6327. }
  6328. prules.BurstSpeedMin = tempf;
  6329. break;
  6330. case ScriptBaseClass.PSYS_SRC_BURST_SPEED_MAX:
  6331. try
  6332. {
  6333. tempf = rules.GetStrictFloatItem(i + 1);
  6334. }
  6335. catch(InvalidCastException)
  6336. {
  6337. Error(originFunc, string.Format("Error running rule PSYS_SRC_BURST_SPEED_MAX: arg #{0} - parameter 1 must be float", i + 1));
  6338. return;
  6339. }
  6340. prules.BurstSpeedMax = tempf;
  6341. break;
  6342. case ScriptBaseClass.PSYS_SRC_MAX_AGE:
  6343. try
  6344. {
  6345. tempf = rules.GetStrictFloatItem(i + 1);
  6346. }
  6347. catch(InvalidCastException)
  6348. {
  6349. Error(originFunc, string.Format("Error running rule PSYS_SRC_MAX_AGE: arg #{0} - parameter 1 must be float", i + 1));
  6350. return;
  6351. }
  6352. prules.MaxAge = tempf;
  6353. break;
  6354. case ScriptBaseClass.PSYS_SRC_TARGET_KEY:
  6355. if (UUID.TryParse(rules.Data[i + 1].ToString(), out UUID key))
  6356. {
  6357. prules.Target = key;
  6358. }
  6359. else
  6360. {
  6361. prules.Target = part.UUID;
  6362. }
  6363. break;
  6364. case ScriptBaseClass.PSYS_SRC_OMEGA:
  6365. // AL: This is an assumption, since it is the only thing that would match.
  6366. try
  6367. {
  6368. tempv = rules.GetVector3Item(i + 1);
  6369. }
  6370. catch(InvalidCastException)
  6371. {
  6372. Error(originFunc, string.Format("Error running rule PSYS_SRC_OMEGA: arg #{0} - parameter 1 must be vector", i + 1));
  6373. return;
  6374. }
  6375. prules.AngularVelocity.X = (float)tempv.x;
  6376. prules.AngularVelocity.Y = (float)tempv.y;
  6377. prules.AngularVelocity.Z = (float)tempv.z;
  6378. break;
  6379. case ScriptBaseClass.PSYS_SRC_ANGLE_BEGIN:
  6380. try
  6381. {
  6382. tempf = rules.GetStrictFloatItem(i + 1);
  6383. }
  6384. catch(InvalidCastException)
  6385. {
  6386. Error(originFunc, string.Format("Error running rule PSYS_SRC_ANGLE_BEGIN: arg #{0} - parameter 1 must be float", i + 1));
  6387. return;
  6388. }
  6389. prules.InnerAngle = tempf;
  6390. prules.PartFlags |= 0x02; // Set new angle format.
  6391. break;
  6392. case ScriptBaseClass.PSYS_SRC_ANGLE_END:
  6393. try
  6394. {
  6395. tempf = rules.GetStrictFloatItem(i + 1);
  6396. }
  6397. catch (InvalidCastException)
  6398. {
  6399. Error(originFunc, string.Format("Error running rule PSYS_SRC_ANGLE_END: arg #{0} - parameter 1 must be float", i + 1));
  6400. return;
  6401. }
  6402. prules.OuterAngle = tempf;
  6403. prules.PartFlags |= 0x02; // Set new angle format.
  6404. break;
  6405. }
  6406. }
  6407. prules.CRC = 1;
  6408. part.AddNewParticleSystem(prules, expire);
  6409. if(!expire || prules.MaxAge != 0 || prules.MaxAge > 300)
  6410. part.ParentGroup.HasGroupChanged = true;
  6411. }
  6412. part.SendFullUpdateToAllClients();
  6413. }
  6414. private static float validParticleScale(float value)
  6415. {
  6416. return value > 7.96f ? 7.96f : value;
  6417. }
  6418. public void llGroundRepel(double height, int water, double tau)
  6419. {
  6420. if (m_host.PhysActor != null)
  6421. {
  6422. float ground = (float)llGround(new LSL_Types.Vector3(0, 0, 0));
  6423. float waterLevel = (float)llWater(new LSL_Types.Vector3(0, 0, 0));
  6424. PIDHoverType hoverType = PIDHoverType.Ground;
  6425. if (water != 0)
  6426. {
  6427. hoverType = PIDHoverType.GroundAndWater;
  6428. if (ground < waterLevel)
  6429. height += waterLevel;
  6430. else
  6431. height += ground;
  6432. }
  6433. else
  6434. {
  6435. height += ground;
  6436. }
  6437. m_host.SetHoverHeight((float)height, hoverType, (float)tau);
  6438. }
  6439. }
  6440. public void llGiveInventoryList(LSL_Key destination, LSL_String category, LSL_List inventory)
  6441. {
  6442. if (inventory.Length == 0)
  6443. return;
  6444. if (!UUID.TryParse(destination, out UUID destID) || destID.IsZero())
  6445. return;
  6446. bool isNotOwner = true;
  6447. if (!World.TryGetSceneObjectPart(destID, out SceneObjectPart destSop))
  6448. {
  6449. if (!World.TryGetScenePresence(destID, out ScenePresence sp))
  6450. {
  6451. // we could check if it is a grid user and allow the transfer as in older code
  6452. // but that increases security risk
  6453. Error("llGiveInventoryList", "Unable to give list, destination not found");
  6454. ScriptSleep(100);
  6455. return;
  6456. }
  6457. isNotOwner = sp.UUID.NotEqual(m_host.OwnerID);
  6458. }
  6459. List<UUID> itemList = new(inventory.Length);
  6460. foreach (object item in inventory.Data)
  6461. {
  6462. string rawItemString = item.ToString();
  6463. TaskInventoryItem taskItem = (UUID.TryParse(rawItemString, out UUID itemID)) ?
  6464. m_host.Inventory.GetInventoryItem(itemID) : m_host.Inventory.GetInventoryItem(rawItemString);
  6465. if(taskItem is null)
  6466. continue;
  6467. if ((taskItem.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
  6468. continue;
  6469. if (destSop is not null)
  6470. {
  6471. if(!World.Permissions.CanDoObjectInvToObjectInv(taskItem, m_host, destSop))
  6472. continue;
  6473. }
  6474. else
  6475. {
  6476. if(isNotOwner)
  6477. {
  6478. if ((taskItem.CurrentPermissions & (uint)PermissionMask.Transfer) == 0)
  6479. continue;
  6480. }
  6481. }
  6482. itemList.Add(taskItem.ItemID);
  6483. }
  6484. if (itemList.Count == 0)
  6485. {
  6486. Error("llGiveInventoryList", "Unable to give list, no items found");
  6487. ScriptSleep(100);
  6488. return;
  6489. }
  6490. UUID folderID = m_ScriptEngine.World.MoveTaskInventoryItems(destID, category, m_host, itemList, false);
  6491. if (folderID.IsZero())
  6492. {
  6493. Error("llGiveInventoryList", "Unable to give list");
  6494. ScriptSleep(100);
  6495. return;
  6496. }
  6497. if (destSop is not null)
  6498. {
  6499. ScriptSleep(100);
  6500. return;
  6501. }
  6502. if (m_TransferModule != null)
  6503. {
  6504. byte[] bucket = new byte[] { (byte)AssetType.Folder };
  6505. Vector3 pos = m_host.AbsolutePosition;
  6506. GridInstantMessage msg = new(World, m_host.OwnerID, m_host.Name, destID,
  6507. (byte)InstantMessageDialog.TaskInventoryOffered,
  6508. m_host.OwnerID.Equals(m_host.GroupID),
  6509. string.Format("'{0}'", category),
  6510. //string.Format("'{0}' ( http://slurl.com/secondlife/{1}/{2}/{3}/{4} )", category, World.Name, (int)pos.X, (int)pos.Y, (int)pos.Z),
  6511. folderID, false, pos,
  6512. bucket, false);
  6513. m_TransferModule.SendInstantMessage(msg, delegate(bool success) {});
  6514. }
  6515. ScriptSleep(3000);
  6516. }
  6517. public void llSetVehicleType(int type)
  6518. {
  6519. if (!m_host.ParentGroup.IsDeleted)
  6520. {
  6521. m_host.ParentGroup.RootPart.SetVehicleType(type);
  6522. }
  6523. }
  6524. //CFK 9/28: Most, but not all of the underlying plumbing between here and the physics modules is in
  6525. //CFK 9/28: so these are not complete yet.
  6526. public void llSetVehicleFloatParam(int param, LSL_Float value)
  6527. {
  6528. if (!m_host.ParentGroup.IsDeleted)
  6529. {
  6530. m_host.ParentGroup.RootPart.SetVehicleFloatParam(param, (float)value);
  6531. }
  6532. }
  6533. //CFK 9/28: Most, but not all of the underlying plumbing between here and the physics modules is in
  6534. //CFK 9/28: so these are not complete yet.
  6535. public void llSetVehicleVectorParam(int param, LSL_Vector vec)
  6536. {
  6537. if (!m_host.ParentGroup.IsDeleted)
  6538. {
  6539. m_host.ParentGroup.RootPart.SetVehicleVectorParam(param, vec);
  6540. }
  6541. }
  6542. //CFK 9/28: Most, but not all of the underlying plumbing between here and the physics modules is in
  6543. //CFK 9/28: so these are not complete yet.
  6544. public void llSetVehicleRotationParam(int param, LSL_Rotation rot)
  6545. {
  6546. if (!m_host.ParentGroup.IsDeleted)
  6547. {
  6548. m_host.ParentGroup.RootPart.SetVehicleRotationParam(param, rot);
  6549. }
  6550. }
  6551. public void llSetVehicleFlags(int flags)
  6552. {
  6553. if (!m_host.ParentGroup.IsDeleted)
  6554. {
  6555. m_host.ParentGroup.RootPart.SetVehicleFlags(flags, false);
  6556. }
  6557. }
  6558. public void llRemoveVehicleFlags(int flags)
  6559. {
  6560. if (!m_host.ParentGroup.IsDeleted)
  6561. {
  6562. m_host.ParentGroup.RootPart.SetVehicleFlags(flags, true);
  6563. }
  6564. }
  6565. protected static void SitTarget(SceneObjectPart part, LSL_Vector offset, LSL_Rotation rot)
  6566. {
  6567. // LSL quaternions can normalize to 0, normal Quaternions can't.
  6568. if (rot.s == 0 && rot.x == 0 && rot.y == 0 && rot.z == 0)
  6569. rot.s = 1; // ZERO_ROTATION = 0,0,0,1
  6570. part.SitTargetPosition = offset;
  6571. part.SitTargetOrientation = rot;
  6572. part.ParentGroup.HasGroupChanged = true;
  6573. }
  6574. public void llSitTarget(LSL_Vector offset, LSL_Rotation rot)
  6575. {
  6576. SitTarget(m_host, offset, rot);
  6577. }
  6578. public void llLinkSitTarget(LSL_Integer link, LSL_Vector offset, LSL_Rotation rot)
  6579. {
  6580. if (link == ScriptBaseClass.LINK_ROOT)
  6581. SitTarget(m_host.ParentGroup.RootPart, offset, rot);
  6582. else if (link == ScriptBaseClass.LINK_THIS)
  6583. SitTarget(m_host, offset, rot);
  6584. else
  6585. {
  6586. SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(link);
  6587. if (null != part)
  6588. {
  6589. SitTarget(part, offset, rot);
  6590. }
  6591. }
  6592. }
  6593. public LSL_Key llAvatarOnSitTarget()
  6594. {
  6595. return m_host.SitTargetAvatar.ToString();
  6596. }
  6597. // http://wiki.secondlife.com/wiki/LlAvatarOnLinkSitTarget
  6598. public LSL_Key llAvatarOnLinkSitTarget(LSL_Integer linknum)
  6599. {
  6600. if(linknum == ScriptBaseClass.LINK_SET ||
  6601. linknum == ScriptBaseClass.LINK_ALL_CHILDREN ||
  6602. linknum == ScriptBaseClass.LINK_ALL_OTHERS ||
  6603. linknum == 0)
  6604. return ScriptBaseClass.NULL_KEY;
  6605. List<SceneObjectPart> parts = GetLinkParts(linknum);
  6606. if (parts.Count == 0)
  6607. return ScriptBaseClass.NULL_KEY;
  6608. return parts[0].SitTargetAvatar.ToString();
  6609. }
  6610. public void llAddToLandPassList(LSL_Key avatar, LSL_Float hours)
  6611. {
  6612. if(!UUID.TryParse(avatar, out UUID key) || key.IsZero())
  6613. return;
  6614. ILandObject parcel = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
  6615. if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, parcel, GroupPowers.LandManagePasses, false))
  6616. {
  6617. int expires = (hours != 0) ? Util.UnixTimeSinceEpoch() + (int)(3600.0 * hours) : 0;
  6618. LandData land = parcel.LandData;
  6619. foreach(LandAccessEntry e in land.ParcelAccessList)
  6620. {
  6621. if (e.Flags == AccessList.Access && e.AgentID.Equals(key))
  6622. {
  6623. if (e.Expires != 0 && expires > e.Expires)
  6624. {
  6625. e.Expires = expires;
  6626. World.EventManager.TriggerLandObjectUpdated((uint)land.LocalID, parcel);
  6627. }
  6628. return;
  6629. }
  6630. }
  6631. LandAccessEntry entry = new()
  6632. {
  6633. AgentID = key,
  6634. Flags = AccessList.Access,
  6635. Expires = expires
  6636. };
  6637. land.ParcelAccessList.Add(entry);
  6638. World.EventManager.TriggerLandObjectUpdated((uint)land.LocalID, parcel);
  6639. }
  6640. ScriptSleep(m_sleepMsOnAddToLandPassList);
  6641. }
  6642. public void llSetTouchText(string text)
  6643. {
  6644. if(text.Length <= 9)
  6645. m_host.TouchName = text;
  6646. else
  6647. m_host.TouchName = text[..9];
  6648. }
  6649. public void llSetSitText(string text)
  6650. {
  6651. if (text.Length <= 9)
  6652. m_host.SitName = text;
  6653. else
  6654. m_host.SitName = text[..9];
  6655. }
  6656. public void llSetCameraEyeOffset(LSL_Vector offset)
  6657. {
  6658. m_host.SetCameraEyeOffset(offset);
  6659. }
  6660. public void llSetCameraAtOffset(LSL_Vector offset)
  6661. {
  6662. m_host.SetCameraAtOffset(offset);
  6663. }
  6664. public void llSetLinkCamera(LSL_Integer link, LSL_Vector eye, LSL_Vector at)
  6665. {
  6666. if (link == ScriptBaseClass.LINK_SET ||
  6667. link == ScriptBaseClass.LINK_ALL_CHILDREN ||
  6668. link == ScriptBaseClass.LINK_ALL_OTHERS) return;
  6669. SceneObjectPart part = (int)link switch
  6670. {
  6671. ScriptBaseClass.LINK_ROOT => m_host.ParentGroup.RootPart,
  6672. ScriptBaseClass.LINK_THIS => m_host,
  6673. _ => m_host.ParentGroup.GetLinkNumPart(link),
  6674. };
  6675. if (part is not null)
  6676. {
  6677. part.SetCameraEyeOffset(eye);
  6678. part.SetCameraAtOffset(at);
  6679. }
  6680. }
  6681. public LSL_String llDumpList2String(LSL_List src, string seperator)
  6682. {
  6683. if (src.Length == 0)
  6684. {
  6685. return LSL_String.Empty;
  6686. }
  6687. string ret = String.Empty;
  6688. foreach (object o in src.Data)
  6689. {
  6690. ret = ret + o.ToString() + seperator;
  6691. }
  6692. ret = ret[..^seperator.Length];
  6693. return ret;
  6694. }
  6695. public LSL_Integer llScriptDanger(LSL_Vector pos)
  6696. {
  6697. return World.LSLScriptDanger(m_host, pos) ? 1 : 0;
  6698. }
  6699. public void llDialog(LSL_Key avatar, LSL_String message, LSL_List buttons, int chat_channel)
  6700. {
  6701. IDialogModule dm = World.RequestModuleInterface<IDialogModule>();
  6702. if (dm == null)
  6703. return;
  6704. if (!UUID.TryParse(avatar,out UUID av) || av.IsZero())
  6705. {
  6706. Error("llDialog", "First parameter must be a valid key");
  6707. return;
  6708. }
  6709. if (!m_host.GetOwnerName(out string fname, out string lname))
  6710. return;
  6711. int length = buttons.Length;
  6712. if (length < 1)
  6713. {
  6714. buttons.Add(new LSL_String("Ok"));
  6715. length = 1;
  6716. }
  6717. else if (length > 12)
  6718. {
  6719. Error("llDialog", "No more than 12 buttons can be shown");
  6720. return;
  6721. }
  6722. if (message.Length == 0)
  6723. {
  6724. Error("llDialog", "Empty message");
  6725. }
  6726. else if (Encoding.UTF8.GetByteCount(message) > 512)
  6727. {
  6728. Error("llDialog", "Message longer than 512 bytes");
  6729. }
  6730. string[] buts = new string[length];
  6731. for (int i = 0; i < length; i++)
  6732. {
  6733. buts[i] = buttons.Data[i].ToString();
  6734. if (buts[i].Length == 0)
  6735. {
  6736. Error("llDialog", "Button label cannot be blank");
  6737. return;
  6738. }
  6739. /*
  6740. if (buttons.Data[i].ToString().Length > 24)
  6741. {
  6742. Error("llDialog", "Button label cannot be longer than 24 characters");
  6743. return;
  6744. }
  6745. */
  6746. buts[i] = buttons.Data[i].ToString();
  6747. }
  6748. dm.SendDialogToUser(
  6749. av, m_host.Name, m_host.UUID, m_host.OwnerID, fname, lname,
  6750. message, new UUID("00000000-0000-2222-3333-100000001000"), chat_channel, buts);
  6751. ScriptSleep(m_sleepMsOnDialog);
  6752. }
  6753. public void llVolumeDetect(int detect)
  6754. {
  6755. if (!m_host.ParentGroup.IsDeleted)
  6756. m_host.ParentGroup.ScriptSetVolumeDetect(detect != 0);
  6757. }
  6758. public void llRemoteLoadScript(string target, string name, int running, int start_param)
  6759. {
  6760. Deprecated("llRemoteLoadScript", "Use llRemoteLoadScriptPin instead");
  6761. ScriptSleep(m_sleepMsOnRemoteLoadScript);
  6762. }
  6763. public void llSetRemoteScriptAccessPin(int pin)
  6764. {
  6765. m_host.ScriptAccessPin = pin;
  6766. }
  6767. public void llRemoteLoadScriptPin(string target, string name, int pin, int running, int start_param)
  6768. {
  6769. if (!UUID.TryParse(target, out UUID destId) || destId.IsZero())
  6770. {
  6771. Error("llRemoteLoadScriptPin", "invalid key '" + target + "'");
  6772. return;
  6773. }
  6774. // target must be a different prim than the one containing the script
  6775. if (m_host.UUID.Equals(destId))
  6776. {
  6777. return;
  6778. }
  6779. // copy the first script found with this inventory name
  6780. TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name);
  6781. // make sure the object is a script
  6782. if (item == null || item.Type != 10)
  6783. {
  6784. Error("llRemoteLoadScriptPin", "Can't find script '" + name + "'");
  6785. return;
  6786. }
  6787. if ((item.BasePermissions & (uint)PermissionMask.Copy) == 0)
  6788. {
  6789. Error("llRemoteLoadScriptPin", "No copy rights");
  6790. return;
  6791. }
  6792. // the rest of the permission checks are done in RezScript, so check the pin there as well
  6793. World.RezScriptFromPrim(item.ItemID, m_host, destId, pin, running, start_param);
  6794. // this will cause the delay even if the script pin or permissions were wrong - seems ok
  6795. ScriptSleep(m_sleepMsOnRemoteLoadScriptPin);
  6796. }
  6797. public void llOpenRemoteDataChannel()
  6798. {
  6799. IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
  6800. if (xmlrpcMod != null && xmlrpcMod.IsEnabled())
  6801. {
  6802. UUID channelID = xmlrpcMod.OpenXMLRPCChannel(m_host.LocalId, m_item.ItemID, UUID.Zero);
  6803. IXmlRpcRouter xmlRpcRouter = m_ScriptEngine.World.RequestModuleInterface<IXmlRpcRouter>();
  6804. if (xmlRpcRouter != null)
  6805. {
  6806. string ExternalHostName = m_ScriptEngine.World.RegionInfo.ExternalHostName;
  6807. xmlRpcRouter.RegisterNewReceiver(m_ScriptEngine.ScriptModule, channelID, m_host.UUID,
  6808. m_item.ItemID, String.Format("http://{0}:{1}/", ExternalHostName,
  6809. xmlrpcMod.Port.ToString()));
  6810. }
  6811. object[] resobj = new object[]
  6812. {
  6813. new LSL_Integer(1),
  6814. new LSL_String(channelID.ToString()),
  6815. new LSL_String(ScriptBaseClass.NULL_KEY),
  6816. new LSL_String(String.Empty),
  6817. new LSL_Integer(0),
  6818. new LSL_String(String.Empty)
  6819. };
  6820. m_ScriptEngine.PostScriptEvent(m_item.ItemID, new EventParams("remote_data", resobj,
  6821. Array.Empty<DetectParams>()));
  6822. }
  6823. ScriptSleep(m_sleepMsOnOpenRemoteDataChannel);
  6824. }
  6825. public LSL_Key llSendRemoteData(string channel, string dest, int idata, string sdata)
  6826. {
  6827. IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
  6828. ScriptSleep(m_sleepMsOnSendRemoteData);
  6829. if (xmlrpcMod == null)
  6830. return "";
  6831. return (xmlrpcMod.SendRemoteData(m_host.LocalId, m_item.ItemID, channel, dest, idata, sdata)).ToString();
  6832. }
  6833. public void llRemoteDataReply(string channel, string message_id, string sdata, int idata)
  6834. {
  6835. IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
  6836. xmlrpcMod?.RemoteDataReply(channel, message_id, sdata, idata);
  6837. ScriptSleep(m_sleepMsOnRemoteDataReply);
  6838. }
  6839. public void llCloseRemoteDataChannel(string channel)
  6840. {
  6841. IXmlRpcRouter xmlRpcRouter = m_ScriptEngine.World.RequestModuleInterface<IXmlRpcRouter>();
  6842. xmlRpcRouter?.UnRegisterReceiver(channel, m_item.ItemID);
  6843. IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
  6844. xmlrpcMod?.CloseXMLRPCChannel((UUID)channel);
  6845. ScriptSleep(m_sleepMsOnCloseRemoteDataChannel);
  6846. }
  6847. public LSL_String llMD5String(string src, int nonce)
  6848. {
  6849. return Util.Md5Hash(String.Format("{0}:{1}", src, nonce.ToString()), Encoding.UTF8);
  6850. }
  6851. public LSL_String llSHA1String(string src)
  6852. {
  6853. return Util.SHA1Hash(src, Encoding.UTF8).ToLower();
  6854. }
  6855. public LSL_String llSHA256String(LSL_String input)
  6856. {
  6857. byte[] bytes;
  6858. // Create a SHA256
  6859. using (SHA256 sha256Hash = SHA256.Create())
  6860. {
  6861. // ComputeHash - returns byte array
  6862. bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(input.m_string));
  6863. }
  6864. return Util.bytesToLowcaseHexString(bytes);
  6865. }
  6866. protected static ObjectShapePacket.ObjectDataBlock SetPrimitiveBlockShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, byte profileshape, byte pathcurve)
  6867. {
  6868. float tempFloat;
  6869. ObjectShapePacket.ObjectDataBlock shapeBlock = new();
  6870. if (part is null || part.ParentGroup is null || part.ParentGroup.IsDeleted)
  6871. return shapeBlock;
  6872. if (holeshape != ScriptBaseClass.PRIM_HOLE_DEFAULT &&
  6873. holeshape != ScriptBaseClass.PRIM_HOLE_CIRCLE &&
  6874. holeshape != ScriptBaseClass.PRIM_HOLE_SQUARE &&
  6875. holeshape != ScriptBaseClass.PRIM_HOLE_TRIANGLE)
  6876. {
  6877. holeshape = ScriptBaseClass.PRIM_HOLE_DEFAULT;
  6878. }
  6879. shapeBlock.PathCurve = pathcurve;
  6880. shapeBlock.ProfileCurve = (byte)holeshape; // Set the hole shape.
  6881. shapeBlock.ProfileCurve += profileshape; // Add in the profile shape.
  6882. if (cut.x < 0f)
  6883. {
  6884. cut.x = 0f;
  6885. }
  6886. else if (cut.x > 1f)
  6887. {
  6888. cut.x = 1f;
  6889. }
  6890. if (cut.y < 0f)
  6891. {
  6892. cut.y = 0f;
  6893. }
  6894. else if (cut.y > 1f)
  6895. {
  6896. cut.y = 1f;
  6897. }
  6898. if (cut.y - cut.x < 0.02f)
  6899. {
  6900. cut.x = cut.y - 0.02f;
  6901. if (cut.x < 0.0f)
  6902. {
  6903. cut.x = 0.0f;
  6904. cut.y = 0.02f;
  6905. }
  6906. }
  6907. shapeBlock.ProfileBegin = (ushort)(50000 * cut.x);
  6908. shapeBlock.ProfileEnd = (ushort)(50000 * (1 - cut.y));
  6909. if (hollow < 0f)
  6910. {
  6911. hollow = 0f;
  6912. }
  6913. // If the prim is a Cylinder, Prism, Sphere, Torus or Ring (or not a
  6914. // Box or Tube) and the hole shape is a square, hollow is limited to
  6915. // a max of 70%. The viewer performs its own check on this value but
  6916. // we need to do it here also so llGetPrimitiveParams can have access
  6917. // to the correct value.
  6918. if (profileshape != (byte)ProfileCurve.Square &&
  6919. holeshape == ScriptBaseClass.PRIM_HOLE_SQUARE)
  6920. {
  6921. if (hollow > 0.70f)
  6922. {
  6923. hollow = 0.70f;
  6924. }
  6925. }
  6926. // Otherwise, hollow is limited to 99%.
  6927. else
  6928. {
  6929. if (hollow > 0.99f)
  6930. {
  6931. hollow = 0.99f;
  6932. }
  6933. }
  6934. shapeBlock.ProfileHollow = (ushort)(50000 * hollow);
  6935. if (twist.x < -1.0f)
  6936. {
  6937. twist.x = -1.0f;
  6938. }
  6939. else if (twist.x > 1.0f)
  6940. {
  6941. twist.x = 1.0f;
  6942. }
  6943. if (twist.y < -1.0f)
  6944. {
  6945. twist.y = -1.0f;
  6946. }
  6947. else if (twist.y > 1.0f)
  6948. {
  6949. twist.y = 1.0f;
  6950. }
  6951. tempFloat = 100.0f * (float)twist.x;
  6952. if (tempFloat >= 0)
  6953. tempFloat += 0.5f;
  6954. else
  6955. tempFloat -= 0.5f;
  6956. shapeBlock.PathTwistBegin = (sbyte)tempFloat;
  6957. tempFloat = 100.0f * (float)twist.y;
  6958. if (tempFloat >= 0)
  6959. tempFloat += 0.5f;
  6960. else
  6961. tempFloat -= 0.5f;
  6962. shapeBlock.PathTwist = (sbyte)tempFloat;
  6963. shapeBlock.ObjectLocalID = part.LocalId;
  6964. part.Shape.SculptEntry = false;
  6965. return shapeBlock;
  6966. }
  6967. // Prim type box, cylinder and prism.
  6968. protected static void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector taper_b, LSL_Vector topshear, byte profileshape, byte pathcurve)
  6969. {
  6970. if (part is null || part.ParentGroup is null || part.ParentGroup.IsDeleted)
  6971. return;
  6972. float tempFloat; // Use in float expressions below to avoid byte cast precision issues.
  6973. ObjectShapePacket.ObjectDataBlock shapeBlock;
  6974. shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist, profileshape, pathcurve);
  6975. if (taper_b.x < 0f)
  6976. {
  6977. taper_b.x = 0f;
  6978. }
  6979. else if (taper_b.x > 2f)
  6980. {
  6981. taper_b.x = 2f;
  6982. }
  6983. if (taper_b.y < 0f)
  6984. {
  6985. taper_b.y = 0f;
  6986. }
  6987. else if (taper_b.y > 2f)
  6988. {
  6989. taper_b.y = 2f;
  6990. }
  6991. tempFloat = 100.0f * (2.0f - (float)taper_b.x);
  6992. if (tempFloat >= 0)
  6993. tempFloat += 0.5f;
  6994. else
  6995. tempFloat -= 0.5f;
  6996. shapeBlock.PathScaleX = (byte)tempFloat;
  6997. tempFloat = 100.0f * (2.0f - (float)taper_b.y);
  6998. if (tempFloat >= 0)
  6999. tempFloat += 0.5f;
  7000. else
  7001. tempFloat -= 0.5f;
  7002. shapeBlock.PathScaleY = (byte)tempFloat;
  7003. if (topshear.x < -0.5f)
  7004. {
  7005. topshear.x = -0.5f;
  7006. }
  7007. else if (topshear.x > 0.5f)
  7008. {
  7009. topshear.x = 0.5f;
  7010. }
  7011. if (topshear.y < -0.5f)
  7012. {
  7013. topshear.y = -0.5f;
  7014. }
  7015. else if (topshear.y > 0.5f)
  7016. {
  7017. topshear.y = 0.5f;
  7018. }
  7019. tempFloat = 100.0f * (float)topshear.x;
  7020. if (tempFloat >= 0)
  7021. tempFloat += 0.5f;
  7022. else
  7023. tempFloat -= 0.5f;
  7024. shapeBlock.PathShearX = (byte)tempFloat;
  7025. tempFloat = 100.0f * (float)topshear.y;
  7026. if (tempFloat >= 0)
  7027. tempFloat += 0.5f;
  7028. else
  7029. tempFloat -= 0.5f;
  7030. shapeBlock.PathShearY = (byte)tempFloat;
  7031. part.Shape.SculptEntry = false;
  7032. part.UpdateShape(shapeBlock);
  7033. }
  7034. // Prim type sphere.
  7035. protected static void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector dimple, byte profileshape, byte pathcurve)
  7036. {
  7037. if (part is null || part.ParentGroup is null || part.ParentGroup.IsDeleted)
  7038. return;
  7039. ObjectShapePacket.ObjectDataBlock shapeBlock;
  7040. shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist, profileshape, pathcurve);
  7041. // profile/path swapped for a sphere
  7042. shapeBlock.PathBegin = shapeBlock.ProfileBegin;
  7043. shapeBlock.PathEnd = shapeBlock.ProfileEnd;
  7044. shapeBlock.PathScaleX = 100;
  7045. shapeBlock.PathScaleY = 100;
  7046. if (dimple.x < 0f)
  7047. {
  7048. dimple.x = 0f;
  7049. }
  7050. else if (dimple.x > 1f)
  7051. {
  7052. dimple.x = 1f;
  7053. }
  7054. if (dimple.y < 0f)
  7055. {
  7056. dimple.y = 0f;
  7057. }
  7058. else if (dimple.y > 1f)
  7059. {
  7060. dimple.y = 1f;
  7061. }
  7062. if (dimple.y - dimple.x < 0.02f)
  7063. {
  7064. dimple.x = dimple.y - 0.02f;
  7065. if (dimple.x < 0.0f)
  7066. {
  7067. dimple.x = 0.0f;
  7068. dimple.y = 0.02f;
  7069. }
  7070. }
  7071. shapeBlock.ProfileBegin = (ushort)(50000 * dimple.x);
  7072. shapeBlock.ProfileEnd = (ushort)(50000 * (1 - dimple.y));
  7073. part.Shape.SculptEntry = false;
  7074. part.UpdateShape(shapeBlock);
  7075. }
  7076. // Prim type torus, tube and ring.
  7077. protected static void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector holesize, LSL_Vector topshear, LSL_Vector profilecut, LSL_Vector taper_a, float revolutions, float radiusoffset, float skew, byte profileshape, byte pathcurve)
  7078. {
  7079. if (part is null || part.ParentGroup is null || part.ParentGroup.IsDeleted)
  7080. return;
  7081. float tempFloat; // Use in float expressions below to avoid byte cast precision issues.
  7082. ObjectShapePacket.ObjectDataBlock shapeBlock;
  7083. shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist, profileshape, pathcurve);
  7084. // profile/path swapped for a torrus, tube, ring
  7085. shapeBlock.PathBegin = shapeBlock.ProfileBegin;
  7086. shapeBlock.PathEnd = shapeBlock.ProfileEnd;
  7087. if (holesize.x < 0.01f)
  7088. {
  7089. holesize.x = 0.01f;
  7090. }
  7091. else if (holesize.x > 1f)
  7092. {
  7093. holesize.x = 1f;
  7094. }
  7095. tempFloat = 100.0f * (2.0f - (float)holesize.x) + 0.5f;
  7096. shapeBlock.PathScaleX = (byte)tempFloat;
  7097. if (holesize.y < 0.01f)
  7098. {
  7099. holesize.y = 0.01f;
  7100. }
  7101. else if (holesize.y > 0.5f)
  7102. {
  7103. holesize.y = 0.5f;
  7104. }
  7105. tempFloat = 100.0f * (2.0f - (float)holesize.y) + 0.5f;
  7106. shapeBlock.PathScaleY = (byte)tempFloat;
  7107. if (topshear.x < -0.5f)
  7108. {
  7109. topshear.x = -0.5f;
  7110. }
  7111. else if (topshear.x > 0.5f)
  7112. {
  7113. topshear.x = 0.5f;
  7114. }
  7115. tempFloat = (float)(100.0d * topshear.x);
  7116. if (tempFloat >= 0)
  7117. tempFloat += 0.5f;
  7118. else
  7119. tempFloat -= 0.5f;
  7120. shapeBlock.PathShearX = (byte)tempFloat;
  7121. if (topshear.y < -0.5f)
  7122. {
  7123. topshear.y = -0.5f;
  7124. }
  7125. else if (topshear.y > 0.5f)
  7126. {
  7127. topshear.y = 0.5f;
  7128. }
  7129. tempFloat = (float)(100.0d * topshear.y);
  7130. if (tempFloat >= 0)
  7131. tempFloat += 0.5f;
  7132. else
  7133. tempFloat -= 0.5f;
  7134. shapeBlock.PathShearY = (byte)tempFloat;
  7135. if (profilecut.x < 0f)
  7136. {
  7137. profilecut.x = 0f;
  7138. }
  7139. else if (profilecut.x > 1f)
  7140. {
  7141. profilecut.x = 1f;
  7142. }
  7143. if (profilecut.y < 0f)
  7144. {
  7145. profilecut.y = 0f;
  7146. }
  7147. else if (profilecut.y > 1f)
  7148. {
  7149. profilecut.y = 1f;
  7150. }
  7151. if (profilecut.y - profilecut.x < 0.02f)
  7152. {
  7153. profilecut.x = profilecut.y - 0.02f;
  7154. if (profilecut.x < 0.0f)
  7155. {
  7156. profilecut.x = 0.0f;
  7157. profilecut.y = 0.02f;
  7158. }
  7159. }
  7160. shapeBlock.ProfileBegin = (ushort)(50000 * profilecut.x);
  7161. shapeBlock.ProfileEnd = (ushort)(50000 * (1 - profilecut.y));
  7162. if (taper_a.x < -1f)
  7163. {
  7164. taper_a.x = -1f;
  7165. }
  7166. if (taper_a.x > 1f)
  7167. {
  7168. taper_a.x = 1f;
  7169. }
  7170. tempFloat = 100.0f * (float)taper_a.x;
  7171. if (tempFloat >= 0)
  7172. tempFloat += 0.5f;
  7173. else
  7174. tempFloat -= 0.5f;
  7175. shapeBlock.PathTaperX = (sbyte)tempFloat;
  7176. if (taper_a.y < -1f)
  7177. {
  7178. taper_a.y = -1f;
  7179. }
  7180. else if (taper_a.y > 1f)
  7181. {
  7182. taper_a.y = 1f;
  7183. }
  7184. tempFloat = 100.0f * (float)taper_a.y;
  7185. if (tempFloat >= 0)
  7186. tempFloat += 0.5f;
  7187. else
  7188. tempFloat -= 0.5f;
  7189. shapeBlock.PathTaperY = (sbyte)tempFloat;
  7190. if (revolutions < 1f)
  7191. {
  7192. revolutions = 1f;
  7193. }
  7194. if (revolutions > 4f)
  7195. {
  7196. revolutions = 4f;
  7197. }
  7198. tempFloat = 66.66667f * (revolutions - 1.0f) + 0.5f;
  7199. shapeBlock.PathRevolutions = (byte)tempFloat;
  7200. // limits on radiusoffset depend on revolutions and hole size (how?) seems like the maximum range is 0 to 1
  7201. if (radiusoffset < 0f)
  7202. {
  7203. radiusoffset = 0f;
  7204. }
  7205. if (radiusoffset > 1f)
  7206. {
  7207. radiusoffset = 1f;
  7208. }
  7209. tempFloat = 100.0f * radiusoffset + 0.5f;
  7210. shapeBlock.PathRadiusOffset = (sbyte)tempFloat;
  7211. if (skew < -0.95f)
  7212. {
  7213. skew = -0.95f;
  7214. }
  7215. if (skew > 0.95f)
  7216. {
  7217. skew = 0.95f;
  7218. }
  7219. tempFloat = 100.0f * skew;
  7220. if (tempFloat >= 0)
  7221. tempFloat += 0.5f;
  7222. else
  7223. tempFloat -= 0.5f;
  7224. shapeBlock.PathSkew = (sbyte)tempFloat;
  7225. part.Shape.SculptEntry = false;
  7226. part.UpdateShape(shapeBlock);
  7227. }
  7228. // Prim type sculpt.
  7229. protected void SetPrimitiveShapeSculptParams(SceneObjectPart part, string map, int type, byte pathcurve)
  7230. {
  7231. bool partIsMesh = part.Shape.SculptEntry && (part.Shape.SculptType & ScriptBaseClass.PRIM_SCULPT_TYPE_MASK) == ScriptBaseClass.PRIM_SCULPT_TYPE_MESH;
  7232. int base_type = type & ScriptBaseClass.PRIM_SCULPT_TYPE_MASK;
  7233. if(base_type == ScriptBaseClass.PRIM_SCULPT_TYPE_MESH)
  7234. {
  7235. if(!partIsMesh)
  7236. return;
  7237. bool animeshEnable = (type & ScriptBaseClass.PRIM_SCULPT_FLAG_ANIMESH) != 0;
  7238. if (animeshEnable != part.Shape.AnimeshEnabled)
  7239. {
  7240. part.Shape.AnimeshEnabled = animeshEnable;
  7241. part.ParentGroup.HasGroupChanged = true;
  7242. part.TriggerScriptChangedEvent(Changed.SHAPE);
  7243. part.ScheduleFullAnimUpdate();
  7244. }
  7245. return;
  7246. }
  7247. if (base_type > 5)
  7248. return;
  7249. if (partIsMesh)
  7250. return;
  7251. type &= ~ScriptBaseClass.PRIM_SCULPT_FLAG_ANIMESH;
  7252. if (!UUID.TryParse(map, out UUID sculptId))
  7253. sculptId = ScriptUtils.GetAssetIdFromItemName(m_host, map, (int)AssetType.Texture);
  7254. if (sculptId.IsZero())
  7255. return;
  7256. part.Shape.SetSculptProperties((byte)type, sculptId);
  7257. part.Shape.SculptEntry = true;
  7258. ObjectShapePacket.ObjectDataBlock shapeBlock = new()
  7259. {
  7260. PathCurve = pathcurve,
  7261. ObjectLocalID = part.LocalId,
  7262. PathScaleX = 100,
  7263. PathScaleY = 150
  7264. };
  7265. part.UpdateShape(shapeBlock);
  7266. }
  7267. public void llSetPrimitiveParams(LSL_List rules)
  7268. {
  7269. SetLinkPrimParams(ScriptBaseClass.LINK_THIS, rules, "llSetPrimitiveParams");
  7270. ScriptSleep(m_sleepMsOnSetPrimitiveParams);
  7271. }
  7272. public void llSetLinkPrimitiveParams(int linknumber, LSL_List rules)
  7273. {
  7274. SetLinkPrimParams(linknumber, rules, "llSetLinkPrimitiveParams");
  7275. ScriptSleep(m_sleepMsOnSetLinkPrimitiveParams);
  7276. }
  7277. public void llSetLinkPrimitiveParamsFast(int linknumber, LSL_List rules)
  7278. {
  7279. SetLinkPrimParams(linknumber, rules, "llSetLinkPrimitiveParamsFast");
  7280. }
  7281. private void SetLinkPrimParams(int linknumber, LSL_List rules, string originFunc)
  7282. {
  7283. List<object> parts = new();
  7284. List<SceneObjectPart> prims = GetLinkParts(linknumber);
  7285. List<ScenePresence> avatars = GetLinkAvatars(linknumber);
  7286. foreach (SceneObjectPart p in prims)
  7287. parts.Add(p);
  7288. foreach (ScenePresence p in avatars)
  7289. parts.Add(p);
  7290. LSL_List remaining = new();
  7291. uint rulesParsed = 0;
  7292. if (parts.Count > 0)
  7293. {
  7294. foreach (object part in parts)
  7295. {
  7296. if (part is SceneObjectPart sop)
  7297. remaining = SetPrimParams(sop, rules, originFunc, ref rulesParsed);
  7298. else
  7299. remaining = SetPrimParams((ScenePresence)part, rules, originFunc, ref rulesParsed);
  7300. }
  7301. while (remaining.Length > 2)
  7302. {
  7303. linknumber = remaining.GetIntegerItem(0);
  7304. rules = remaining.GetSublist(1, -1);
  7305. parts.Clear();
  7306. prims = GetLinkParts(linknumber);
  7307. avatars = GetLinkAvatars(linknumber);
  7308. foreach (SceneObjectPart p in prims)
  7309. parts.Add(p);
  7310. foreach (ScenePresence p in avatars)
  7311. parts.Add(p);
  7312. remaining = new LSL_List();
  7313. foreach (object part in parts)
  7314. {
  7315. if (part is SceneObjectPart sop)
  7316. remaining = SetPrimParams(sop, rules, originFunc, ref rulesParsed);
  7317. else
  7318. remaining = SetPrimParams((ScenePresence)part, rules, originFunc, ref rulesParsed);
  7319. }
  7320. }
  7321. }
  7322. }
  7323. public void llSetKeyframedMotion(LSL_List frames, LSL_List options)
  7324. {
  7325. SceneObjectGroup group = m_host.ParentGroup;
  7326. if (group.RootPart.PhysActor != null && group.RootPart.PhysActor.IsPhysical)
  7327. return;
  7328. if (group.IsAttachment)
  7329. return;
  7330. if (frames.Data.Length > 0) // We are getting a new motion
  7331. {
  7332. group.RootPart.KeyframeMotion?.Delete();
  7333. group.RootPart.KeyframeMotion = null;
  7334. int idx = 0;
  7335. KeyframeMotion.PlayMode mode = KeyframeMotion.PlayMode.Forward;
  7336. KeyframeMotion.DataFormat data = KeyframeMotion.DataFormat.Translation | KeyframeMotion.DataFormat.Rotation;
  7337. while (idx < options.Data.Length)
  7338. {
  7339. int option = options.GetIntegerItem(idx++);
  7340. int remain = options.Data.Length - idx;
  7341. switch (option)
  7342. {
  7343. case ScriptBaseClass.KFM_MODE:
  7344. if (remain < 1)
  7345. break;
  7346. int modeval = options.GetIntegerItem(idx++);
  7347. switch(modeval)
  7348. {
  7349. case ScriptBaseClass.KFM_FORWARD:
  7350. mode = KeyframeMotion.PlayMode.Forward;
  7351. break;
  7352. case ScriptBaseClass.KFM_REVERSE:
  7353. mode = KeyframeMotion.PlayMode.Reverse;
  7354. break;
  7355. case ScriptBaseClass.KFM_LOOP:
  7356. mode = KeyframeMotion.PlayMode.Loop;
  7357. break;
  7358. case ScriptBaseClass.KFM_PING_PONG:
  7359. mode = KeyframeMotion.PlayMode.PingPong;
  7360. break;
  7361. }
  7362. break;
  7363. case ScriptBaseClass.KFM_DATA:
  7364. if (remain < 1)
  7365. break;
  7366. int dataval = options.GetIntegerItem(idx++);
  7367. data = (KeyframeMotion.DataFormat)dataval;
  7368. break;
  7369. }
  7370. }
  7371. group.RootPart.KeyframeMotion = new KeyframeMotion(group, mode, data);
  7372. idx = 0;
  7373. int elemLength = 2;
  7374. if (data == (KeyframeMotion.DataFormat.Translation | KeyframeMotion.DataFormat.Rotation))
  7375. elemLength = 3;
  7376. List<KeyframeMotion.Keyframe> keyframes = new();
  7377. bool hasTranslation = (data & KeyframeMotion.DataFormat.Translation) != 0;
  7378. bool hasRotation = (data & KeyframeMotion.DataFormat.Rotation) != 0;
  7379. while (idx < frames.Data.Length)
  7380. {
  7381. int remain = frames.Data.Length - idx;
  7382. if (remain < elemLength)
  7383. break;
  7384. KeyframeMotion.Keyframe frame = new()
  7385. {
  7386. Position = null,
  7387. Rotation = null
  7388. };
  7389. if (hasTranslation)
  7390. {
  7391. LSL_Types.Vector3 tempv = frames.GetVector3Item(idx++);
  7392. frame.Position = new Vector3((float)tempv.x, (float)tempv.y, (float)tempv.z);
  7393. }
  7394. if (hasRotation)
  7395. {
  7396. LSL_Types.Quaternion tempq = frames.GetQuaternionItem(idx++);
  7397. Quaternion q = new((float)tempq.x, (float)tempq.y, (float)tempq.z, (float)tempq.s);
  7398. frame.Rotation = q;
  7399. }
  7400. float tempf = frames.GetStrictFloatItem(idx++);
  7401. frame.TimeMS = (int)(tempf * 1000.0f);
  7402. keyframes.Add(frame);
  7403. }
  7404. group.RootPart.KeyframeMotion.SetKeyframes(keyframes.ToArray());
  7405. group.RootPart.KeyframeMotion.Start();
  7406. }
  7407. else
  7408. {
  7409. if (group.RootPart.KeyframeMotion == null)
  7410. return;
  7411. if (options.Data.Length == 0)
  7412. {
  7413. group.RootPart.KeyframeMotion.Stop();
  7414. return;
  7415. }
  7416. int idx = 0;
  7417. while (idx < options.Data.Length)
  7418. {
  7419. int option = options.GetIntegerItem(idx++);
  7420. switch (option)
  7421. {
  7422. case ScriptBaseClass.KFM_COMMAND:
  7423. int cmd = options.GetIntegerItem(idx++);
  7424. switch (cmd)
  7425. {
  7426. case ScriptBaseClass.KFM_CMD_PLAY:
  7427. group.RootPart.KeyframeMotion.Start();
  7428. break;
  7429. case ScriptBaseClass.KFM_CMD_STOP:
  7430. group.RootPart.KeyframeMotion.Stop();
  7431. break;
  7432. case ScriptBaseClass.KFM_CMD_PAUSE:
  7433. group.RootPart.KeyframeMotion.Pause();
  7434. break;
  7435. }
  7436. break;
  7437. }
  7438. }
  7439. }
  7440. }
  7441. public LSL_List llGetPhysicsMaterial()
  7442. {
  7443. LSL_List result = new();
  7444. result.Add(new LSL_Float(m_host.GravityModifier));
  7445. result.Add(new LSL_Float(m_host.Restitution));
  7446. result.Add(new LSL_Float(m_host.Friction));
  7447. result.Add(new LSL_Float(m_host.Density));
  7448. return result;
  7449. }
  7450. private static void SetPhysicsMaterial(SceneObjectPart part, int material_bits,
  7451. float material_density, float material_friction,
  7452. float material_restitution, float material_gravity_modifier)
  7453. {
  7454. ExtraPhysicsData physdata = new()
  7455. {
  7456. PhysShapeType = (PhysShapeType)part.PhysicsShapeType,
  7457. Density = part.Density,
  7458. Friction = part.Friction,
  7459. Bounce = part.Restitution,
  7460. GravitationModifier = part.GravityModifier
  7461. };
  7462. if ((material_bits & ScriptBaseClass.DENSITY) != 0)
  7463. physdata.Density = material_density;
  7464. if ((material_bits & ScriptBaseClass.FRICTION) != 0)
  7465. physdata.Friction = material_friction;
  7466. if ((material_bits & ScriptBaseClass.RESTITUTION) != 0)
  7467. physdata.Bounce = material_restitution;
  7468. if ((material_bits & ScriptBaseClass.GRAVITY_MULTIPLIER) != 0)
  7469. physdata.GravitationModifier = material_gravity_modifier;
  7470. part.UpdateExtraPhysics(physdata);
  7471. }
  7472. public void llSetPhysicsMaterial(int material_bits,
  7473. LSL_Float material_gravity_modifier, LSL_Float material_restitution,
  7474. LSL_Float material_friction, LSL_Float material_density)
  7475. {
  7476. SetPhysicsMaterial(m_host, material_bits, (float)material_density, (float)material_friction, (float)material_restitution, (float)material_gravity_modifier);
  7477. }
  7478. // vector up using libomv (c&p from sop )
  7479. // vector up rotated by r
  7480. private static Vector3 Zrot(Quaternion r)
  7481. {
  7482. double x, y, z, m;
  7483. m = r.X * r.X + r.Y * r.Y + r.Z * r.Z + r.W * r.W;
  7484. if (Math.Abs(1.0 - m) > 0.000001)
  7485. {
  7486. m = 1.0 / Math.Sqrt(m);
  7487. r.X *= (float)m;
  7488. r.Y *= (float)m;
  7489. r.Z *= (float)m;
  7490. r.W *= (float)m;
  7491. }
  7492. x = 2 * (r.X * r.Z + r.Y * r.W);
  7493. y = 2 * (-r.X * r.W + r.Y * r.Z);
  7494. z = -r.X * r.X - r.Y * r.Y + r.Z * r.Z + r.W * r.W;
  7495. return new Vector3((float)x, (float)y, (float)z);
  7496. }
  7497. protected LSL_List SetPrimParams(SceneObjectPart part, LSL_List rules, string originFunc, ref uint rulesParsed)
  7498. {
  7499. if (part is null || part.ParentGroup is null || part.ParentGroup.IsDeleted)
  7500. return new LSL_List();
  7501. int idx = 0;
  7502. int idxStart = 0;
  7503. bool positionChanged = false;
  7504. bool materialChanged = false;
  7505. LSL_Vector currentPosition = GetPartLocalPos(part);
  7506. try
  7507. {
  7508. while (idx < rules.Length)
  7509. {
  7510. ++rulesParsed;
  7511. int code = rules.GetIntegerItem(idx++);
  7512. int remain = rules.Length - idx;
  7513. idxStart = idx;
  7514. int face;
  7515. LSL_Vector v;
  7516. switch (code)
  7517. {
  7518. case ScriptBaseClass.PRIM_POSITION:
  7519. case ScriptBaseClass.PRIM_POS_LOCAL:
  7520. if (remain < 1)
  7521. return new LSL_List();
  7522. try
  7523. {
  7524. v = rules.GetVector3Item(idx++);
  7525. }
  7526. catch(InvalidCastException)
  7527. {
  7528. if(code == ScriptBaseClass.PRIM_POSITION)
  7529. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_POSITION: arg #{1} - parameter 1 must be vector", rulesParsed, idx - idxStart - 1));
  7530. else
  7531. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_POS_LOCAL: arg #{1} - parameter 1 must be vector", rulesParsed, idx - idxStart - 1));
  7532. return new LSL_List();
  7533. }
  7534. if (part.IsRoot && !part.ParentGroup.IsAttachment)
  7535. currentPosition = GetSetPosTarget(part, v, currentPosition, true);
  7536. else
  7537. currentPosition = GetSetPosTarget(part, v, currentPosition, false);
  7538. positionChanged = true;
  7539. break;
  7540. case ScriptBaseClass.PRIM_SIZE:
  7541. if (remain < 1)
  7542. return new LSL_List();
  7543. v=rules.GetVector3Item(idx++);
  7544. SetScale(part, v);
  7545. break;
  7546. case ScriptBaseClass.PRIM_ROTATION:
  7547. if (remain < 1)
  7548. return new LSL_List();
  7549. LSL_Rotation q;
  7550. try
  7551. {
  7552. q = rules.GetQuaternionItem(idx++);
  7553. }
  7554. catch(InvalidCastException)
  7555. {
  7556. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_ROTATION: arg #{1} - parameter 1 must be rotation", rulesParsed, idx - idxStart - 1));
  7557. return new LSL_List();
  7558. }
  7559. // try to let this work as in SL...
  7560. if (part.ParentID == 0 || (part.ParentGroup != null && part == part.ParentGroup.RootPart))
  7561. {
  7562. // special case: If we are root, rotate complete SOG to new rotation
  7563. SetRot(part, q);
  7564. }
  7565. else
  7566. {
  7567. // we are a child. The rotation values will be set to the one of root modified by rot, as in SL. Don't ask.
  7568. SceneObjectPart rootPart = part.ParentGroup.RootPart;
  7569. SetRot(part, rootPart.RotationOffset * (Quaternion)q);
  7570. }
  7571. break;
  7572. case ScriptBaseClass.PRIM_TYPE:
  7573. if (remain < 3)
  7574. return new LSL_List();
  7575. try
  7576. {
  7577. code = rules.GetIntegerItem(idx++);
  7578. }
  7579. catch(InvalidCastException)
  7580. {
  7581. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE: arg #{1} - parameter 1 must be integer", rulesParsed, idx - idxStart - 1));
  7582. return new LSL_List();
  7583. }
  7584. remain = rules.Length - idx;
  7585. float hollow;
  7586. LSL_Vector twist;
  7587. LSL_Vector taper_b;
  7588. LSL_Vector topshear;
  7589. float revolutions;
  7590. float radiusoffset;
  7591. float skew;
  7592. LSL_Vector holesize;
  7593. LSL_Vector profilecut;
  7594. switch (code)
  7595. {
  7596. case ScriptBaseClass.PRIM_TYPE_BOX:
  7597. if (remain < 6)
  7598. return new LSL_List();
  7599. try
  7600. {
  7601. face = rules.GetIntegerItem(idx++);
  7602. }
  7603. catch(InvalidCastException)
  7604. {
  7605. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_BOX: arg #{1} - parameter 2 must be integer", rulesParsed, idx - idxStart - 1));
  7606. return new LSL_List();
  7607. }
  7608. try
  7609. {
  7610. v = rules.GetVector3Item(idx++); // cut
  7611. }
  7612. catch(InvalidCastException)
  7613. {
  7614. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_BOX: arg #{1} - parameter 3 must be vector", rulesParsed, idx - idxStart - 1));
  7615. return new LSL_List();
  7616. }
  7617. try
  7618. {
  7619. hollow = rules.GetStrictFloatItem(idx++);
  7620. }
  7621. catch(InvalidCastException)
  7622. {
  7623. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_BOX: arg #{1} - parameter 4 must be float", rulesParsed, idx - idxStart - 1));
  7624. return new LSL_List();
  7625. }
  7626. try
  7627. {
  7628. twist = rules.GetVector3Item(idx++);
  7629. }
  7630. catch(InvalidCastException)
  7631. {
  7632. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_BOX: arg #{1} - parameter 5 must be vector", rulesParsed, idx - idxStart - 1));
  7633. return new LSL_List();
  7634. }
  7635. try
  7636. {
  7637. taper_b = rules.GetVector3Item(idx++);
  7638. }
  7639. catch(InvalidCastException)
  7640. {
  7641. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_BOX: arg #{1} - parameter 6 must be vector", rulesParsed, idx - idxStart - 1));
  7642. return new LSL_List();
  7643. }
  7644. try
  7645. {
  7646. topshear = rules.GetVector3Item(idx++);
  7647. }
  7648. catch(InvalidCastException)
  7649. {
  7650. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_BOX: arg #{1} - parameter 7 must be vector", rulesParsed, idx - idxStart - 1));
  7651. return new LSL_List();
  7652. }
  7653. SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b, topshear,
  7654. (byte)ProfileShape.Square, (byte)Extrusion.Straight);
  7655. break;
  7656. case ScriptBaseClass.PRIM_TYPE_CYLINDER:
  7657. if (remain < 6)
  7658. return new LSL_List();
  7659. try
  7660. {
  7661. face = rules.GetIntegerItem(idx++); // holeshape
  7662. }
  7663. catch(InvalidCastException)
  7664. {
  7665. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_CYLINDER: arg #{1} - parameter 3 must be integer", rulesParsed, idx - idxStart - 1));
  7666. return new LSL_List();
  7667. }
  7668. try
  7669. {
  7670. v = rules.GetVector3Item(idx++); // cut
  7671. }
  7672. catch(InvalidCastException)
  7673. {
  7674. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_CYLINDER: arg #{1} - parameter 4 must be vector", rulesParsed, idx - idxStart - 1));
  7675. return new LSL_List();
  7676. }
  7677. try
  7678. {
  7679. hollow = rules.GetStrictFloatItem(idx++);
  7680. }
  7681. catch(InvalidCastException)
  7682. {
  7683. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_CYLINDER: arg #{1} - parameter 5 must be float", rulesParsed, idx - idxStart - 1));
  7684. return new LSL_List();
  7685. }
  7686. try
  7687. {
  7688. twist = rules.GetVector3Item(idx++);
  7689. }
  7690. catch(InvalidCastException)
  7691. {
  7692. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_CYLINDER: arg #{1} - parameter 6 must be vector", rulesParsed, idx - idxStart - 1));
  7693. return new LSL_List();
  7694. }
  7695. try
  7696. {
  7697. taper_b = rules.GetVector3Item(idx++);
  7698. }
  7699. catch(InvalidCastException)
  7700. {
  7701. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_CYLINDER: arg #{1} - parameter 7 must be vector", rulesParsed, idx - idxStart - 1));
  7702. return new LSL_List();
  7703. }
  7704. try
  7705. {
  7706. topshear = rules.GetVector3Item(idx++);
  7707. }
  7708. catch(InvalidCastException)
  7709. {
  7710. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_CYLINDER: arg #{1} - parameter 8 must be vector", rulesParsed, idx - idxStart - 1));
  7711. return new LSL_List();
  7712. }
  7713. SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b, topshear,
  7714. (byte)ProfileShape.Circle, (byte)Extrusion.Straight);
  7715. break;
  7716. case ScriptBaseClass.PRIM_TYPE_PRISM:
  7717. if (remain < 6)
  7718. return new LSL_List();
  7719. try
  7720. {
  7721. face = rules.GetIntegerItem(idx++); // holeshape
  7722. }
  7723. catch(InvalidCastException)
  7724. {
  7725. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_PRISM: arg #{1} - parameter 3 must be integer", rulesParsed, idx - idxStart - 1));
  7726. return new LSL_List();
  7727. }
  7728. try
  7729. {
  7730. v = rules.GetVector3Item(idx++); //cut
  7731. }
  7732. catch(InvalidCastException)
  7733. {
  7734. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_PRISM: arg #{1} - parameter 4 must be vector", rulesParsed, idx - idxStart - 1));
  7735. return new LSL_List();
  7736. }
  7737. try
  7738. {
  7739. hollow = rules.GetStrictFloatItem(idx++);
  7740. }
  7741. catch(InvalidCastException)
  7742. {
  7743. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_PRISM: arg #{1} - parameter 5 must be float", rulesParsed, idx - idxStart - 1));
  7744. return new LSL_List();
  7745. }
  7746. try
  7747. {
  7748. twist = rules.GetVector3Item(idx++);
  7749. }
  7750. catch(InvalidCastException)
  7751. {
  7752. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_PRISM: arg #{1} - parameter 6 must be vector", rulesParsed, idx - idxStart - 1));
  7753. return new LSL_List();
  7754. }
  7755. try
  7756. {
  7757. taper_b = rules.GetVector3Item(idx++);
  7758. }
  7759. catch(InvalidCastException)
  7760. {
  7761. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_PRISM: arg #{1} - parameter 7 must be vector", rulesParsed, idx - idxStart - 1));
  7762. return new LSL_List();
  7763. }
  7764. try
  7765. {
  7766. topshear = rules.GetVector3Item(idx++);
  7767. }
  7768. catch(InvalidCastException)
  7769. {
  7770. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_PRISM: arg #{1} - parameter 8 must be vector", rulesParsed, idx - idxStart - 1));
  7771. return new LSL_List();
  7772. }
  7773. SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b, topshear,
  7774. (byte)ProfileShape.EquilateralTriangle, (byte)Extrusion.Straight);
  7775. break;
  7776. case ScriptBaseClass.PRIM_TYPE_SPHERE:
  7777. if (remain < 5)
  7778. return new LSL_List();
  7779. try
  7780. {
  7781. face = rules.GetIntegerItem(idx++); // holeshape
  7782. }
  7783. catch(InvalidCastException)
  7784. {
  7785. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_SPHERE: arg #{1} - parameter 3 must be integer", rulesParsed, idx - idxStart - 1));
  7786. return new LSL_List();
  7787. }
  7788. try
  7789. {
  7790. v = rules.GetVector3Item(idx++); // cut
  7791. }
  7792. catch(InvalidCastException)
  7793. {
  7794. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_SPHERE: arg #{1} - parameter 4 must be vector", rulesParsed, idx - idxStart - 1));
  7795. return new LSL_List();
  7796. }
  7797. try
  7798. {
  7799. hollow = rules.GetStrictFloatItem(idx++);
  7800. }
  7801. catch(InvalidCastException)
  7802. {
  7803. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_SPHERE: arg #{1} - parameter 5 must be float", rulesParsed, idx - idxStart - 1));
  7804. return new LSL_List();
  7805. }
  7806. try
  7807. {
  7808. twist = rules.GetVector3Item(idx++);
  7809. }
  7810. catch(InvalidCastException)
  7811. {
  7812. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_SPHERE: arg #{1} - parameter 6 must be vector", rulesParsed, idx - idxStart - 1));
  7813. return new LSL_List();
  7814. }
  7815. try
  7816. {
  7817. taper_b = rules.GetVector3Item(idx++); // dimple
  7818. }
  7819. catch(InvalidCastException)
  7820. {
  7821. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_SPHERE: arg #{1} - parameter 7 must be vector", rulesParsed, idx - idxStart - 1));
  7822. return new LSL_List();
  7823. }
  7824. SetPrimitiveShapeParams(part, face, v, hollow, twist, taper_b,
  7825. (byte)ProfileShape.HalfCircle, (byte)Extrusion.Curve1);
  7826. break;
  7827. case ScriptBaseClass.PRIM_TYPE_TORUS:
  7828. if (remain < 11)
  7829. return new LSL_List();
  7830. try
  7831. {
  7832. face = rules.GetIntegerItem(idx++); // holeshape
  7833. }
  7834. catch(InvalidCastException)
  7835. {
  7836. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TORUS: arg #{1} - parameter 3 must be integer", rulesParsed, idx - idxStart - 1));
  7837. return new LSL_List();
  7838. }
  7839. try
  7840. {
  7841. v = rules.GetVector3Item(idx++); //cut
  7842. }
  7843. catch(InvalidCastException)
  7844. {
  7845. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TORUS: arg #{1} - parameter 4 must be vector", rulesParsed, idx - idxStart - 1));
  7846. return new LSL_List();
  7847. }
  7848. try
  7849. {
  7850. hollow = rules.GetStrictFloatItem(idx++);
  7851. }
  7852. catch(InvalidCastException)
  7853. {
  7854. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TORUS: arg #{1} - parameter 5 must be float", rulesParsed, idx - idxStart - 1));
  7855. return new LSL_List();
  7856. }
  7857. try
  7858. {
  7859. twist = rules.GetVector3Item(idx++);
  7860. }
  7861. catch(InvalidCastException)
  7862. {
  7863. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TORUS: arg #{1} - parameter 6 must be vector", rulesParsed, idx - idxStart - 1));
  7864. return new LSL_List();
  7865. }
  7866. try
  7867. {
  7868. holesize = rules.GetVector3Item(idx++);
  7869. }
  7870. catch(InvalidCastException)
  7871. {
  7872. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TORUS: arg #{1} - parameter 7 must be vector", rulesParsed, idx - idxStart - 1));
  7873. return new LSL_List();
  7874. }
  7875. try
  7876. {
  7877. topshear = rules.GetVector3Item(idx++);
  7878. }
  7879. catch(InvalidCastException)
  7880. {
  7881. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TORUS: arg #{1} - parameter 8 must be vector", rulesParsed, idx - idxStart - 1));
  7882. return new LSL_List();
  7883. }
  7884. try
  7885. {
  7886. profilecut = rules.GetVector3Item(idx++);
  7887. }
  7888. catch(InvalidCastException)
  7889. {
  7890. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TORUS: arg #{1} - parameter 9 must be vector", rulesParsed, idx - idxStart - 1));
  7891. return new LSL_List();
  7892. }
  7893. try
  7894. {
  7895. taper_b = rules.GetVector3Item(idx++); // taper_a
  7896. }
  7897. catch(InvalidCastException)
  7898. {
  7899. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TORUS: arg #{1} - parameter 10 must be vector", rulesParsed, idx - idxStart - 1));
  7900. return new LSL_List();
  7901. }
  7902. try
  7903. {
  7904. revolutions = rules.GetStrictFloatItem(idx++);
  7905. }
  7906. catch(InvalidCastException)
  7907. {
  7908. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TORUS: arg #{1} - parameter 11 must be float", rulesParsed, idx - idxStart - 1));
  7909. return new LSL_List();
  7910. }
  7911. try
  7912. {
  7913. radiusoffset = rules.GetStrictFloatItem(idx++);
  7914. }
  7915. catch(InvalidCastException)
  7916. {
  7917. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TORUS: arg #{1} - parameter 12 must be float", rulesParsed, idx - idxStart - 1));
  7918. return new LSL_List();
  7919. }
  7920. try
  7921. {
  7922. skew = rules.GetStrictFloatItem(idx++);
  7923. }
  7924. catch(InvalidCastException)
  7925. {
  7926. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TORUS: arg #{1} - parameter 13 must be vector", rulesParsed, idx - idxStart - 1));
  7927. return new LSL_List();
  7928. }
  7929. SetPrimitiveShapeParams(part, face, v, hollow, twist, holesize, topshear, profilecut, taper_b,
  7930. revolutions, radiusoffset, skew, (byte)ProfileShape.Circle, (byte)Extrusion.Curve1);
  7931. break;
  7932. case ScriptBaseClass.PRIM_TYPE_TUBE:
  7933. if (remain < 11)
  7934. return new LSL_List();
  7935. try
  7936. {
  7937. face = rules.GetIntegerItem(idx++); // holeshape
  7938. }
  7939. catch(InvalidCastException)
  7940. {
  7941. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TUBE: arg #{1} - parameter 3 must be integer", rulesParsed, idx - idxStart - 1));
  7942. return new LSL_List();
  7943. }
  7944. try
  7945. {
  7946. v = rules.GetVector3Item(idx++); //cut
  7947. }
  7948. catch(InvalidCastException)
  7949. {
  7950. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TUBE: arg #{1} - parameter 4 must be vector", rulesParsed, idx - idxStart - 1));
  7951. return new LSL_List();
  7952. }
  7953. try
  7954. {
  7955. hollow = rules.GetStrictFloatItem(idx++);
  7956. }
  7957. catch(InvalidCastException)
  7958. {
  7959. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TUBE: arg #{1} - parameter 5 must be float", rulesParsed, idx - idxStart - 1));
  7960. return new LSL_List();
  7961. }
  7962. try
  7963. {
  7964. twist = rules.GetVector3Item(idx++);
  7965. }
  7966. catch(InvalidCastException)
  7967. {
  7968. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TUBE: arg #{1} - parameter 6 must be vector", rulesParsed, idx - idxStart - 1));
  7969. return new LSL_List();
  7970. }
  7971. try
  7972. {
  7973. holesize = rules.GetVector3Item(idx++);
  7974. }
  7975. catch(InvalidCastException)
  7976. {
  7977. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TUBE: arg #{1} - parameter 7 must be vector", rulesParsed, idx - idxStart - 1));
  7978. return new LSL_List();
  7979. }
  7980. try
  7981. {
  7982. topshear = rules.GetVector3Item(idx++);
  7983. }
  7984. catch(InvalidCastException)
  7985. {
  7986. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TUBE: arg #{1} - parameter 8 must be vector", rulesParsed, idx - idxStart - 1));
  7987. return new LSL_List();
  7988. }
  7989. try
  7990. {
  7991. profilecut = rules.GetVector3Item(idx++);
  7992. }
  7993. catch(InvalidCastException)
  7994. {
  7995. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TUBE: arg #{1} - parameter 9 must be vector", rulesParsed, idx - idxStart - 1));
  7996. return new LSL_List();
  7997. }
  7998. try
  7999. {
  8000. taper_b = rules.GetVector3Item(idx++); // taper_a
  8001. }
  8002. catch(InvalidCastException)
  8003. {
  8004. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TUBE: arg #{1} - parameter 10 must be vector", rulesParsed, idx - idxStart - 1));
  8005. return new LSL_List();
  8006. }
  8007. try
  8008. {
  8009. revolutions = rules.GetStrictFloatItem(idx++);
  8010. }
  8011. catch(InvalidCastException)
  8012. {
  8013. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TUBE: arg #{1} - parameter 11 must be float", rulesParsed, idx - idxStart - 1));
  8014. return new LSL_List();
  8015. }
  8016. try
  8017. {
  8018. radiusoffset = rules.GetStrictFloatItem(idx++);
  8019. }
  8020. catch(InvalidCastException)
  8021. {
  8022. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TUBE: arg #{1} - parameter 12 must be float", rulesParsed, idx - idxStart - 1));
  8023. return new LSL_List();
  8024. }
  8025. try
  8026. {
  8027. skew = rules.GetStrictFloatItem(idx++);
  8028. }
  8029. catch(InvalidCastException)
  8030. {
  8031. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_TUBE: arg #{1} - parameter 13 must be float", rulesParsed, idx - idxStart - 1));
  8032. return new LSL_List();
  8033. }
  8034. SetPrimitiveShapeParams(part, face, v, hollow, twist, holesize, topshear, profilecut, taper_b,
  8035. revolutions, radiusoffset, skew, (byte)ProfileShape.Square, (byte)Extrusion.Curve1);
  8036. break;
  8037. case ScriptBaseClass.PRIM_TYPE_RING:
  8038. if (remain < 11)
  8039. return new LSL_List();
  8040. try
  8041. {
  8042. face = rules.GetIntegerItem(idx++); // holeshape
  8043. }
  8044. catch(InvalidCastException)
  8045. {
  8046. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_RING: arg #{1} - parameter 3 must be integer", rulesParsed, idx - idxStart - 1));
  8047. return new LSL_List();
  8048. }
  8049. try
  8050. {
  8051. v = rules.GetVector3Item(idx++); //cut
  8052. }
  8053. catch(InvalidCastException)
  8054. {
  8055. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_RING: arg #{1} - parameter 4 must be vector", rulesParsed, idx - idxStart - 1));
  8056. return new LSL_List();
  8057. }
  8058. try
  8059. {
  8060. hollow = rules.GetStrictFloatItem(idx++);
  8061. }
  8062. catch(InvalidCastException)
  8063. {
  8064. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_RING: arg #{1} - parameter 5 must be float", rulesParsed, idx - idxStart - 1));
  8065. return new LSL_List();
  8066. }
  8067. try
  8068. {
  8069. twist = rules.GetVector3Item(idx++);
  8070. }
  8071. catch(InvalidCastException)
  8072. {
  8073. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_RING: arg #{1} - parameter 6 must be vector", rulesParsed, idx - idxStart - 1));
  8074. return new LSL_List();
  8075. }
  8076. try
  8077. {
  8078. holesize = rules.GetVector3Item(idx++);
  8079. }
  8080. catch(InvalidCastException)
  8081. {
  8082. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_RING: arg #{1} - parameter 7 must be vector", rulesParsed, idx - idxStart - 1));
  8083. return new LSL_List();
  8084. }
  8085. try
  8086. {
  8087. topshear = rules.GetVector3Item(idx++);
  8088. }
  8089. catch(InvalidCastException)
  8090. {
  8091. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_RING: arg #{1} - parameter 8 must be vector", rulesParsed, idx - idxStart - 1));
  8092. return new LSL_List();
  8093. }
  8094. try
  8095. {
  8096. profilecut = rules.GetVector3Item(idx++);
  8097. }
  8098. catch(InvalidCastException)
  8099. {
  8100. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_RING: arg #{1} - parameter 9 must be vector", rulesParsed, idx - idxStart - 1));
  8101. return new LSL_List();
  8102. }
  8103. try
  8104. {
  8105. taper_b = rules.GetVector3Item(idx++); // taper_a
  8106. }
  8107. catch(InvalidCastException)
  8108. {
  8109. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_RING: arg #{1} - parameter 10 must be vector", rulesParsed, idx - idxStart - 1));
  8110. return new LSL_List();
  8111. }
  8112. try
  8113. {
  8114. revolutions = rules.GetStrictFloatItem(idx++);
  8115. }
  8116. catch(InvalidCastException)
  8117. {
  8118. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_RING: arg #{1} - parameter 11 must be float", rulesParsed, idx - idxStart - 1));
  8119. return new LSL_List();
  8120. }
  8121. try
  8122. {
  8123. radiusoffset = rules.GetStrictFloatItem(idx++);
  8124. }
  8125. catch(InvalidCastException)
  8126. {
  8127. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_RING: arg #{1} - parameter 12 must be float", rulesParsed, idx - idxStart - 1));
  8128. return new LSL_List();
  8129. }
  8130. try
  8131. {
  8132. skew = rules.GetStrictFloatItem(idx++);
  8133. }
  8134. catch(InvalidCastException)
  8135. {
  8136. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_RING: arg #{1} - parameter 13 must be float", rulesParsed, idx - idxStart - 1));
  8137. return new LSL_List();
  8138. }
  8139. SetPrimitiveShapeParams(part, face, v, hollow, twist, holesize, topshear, profilecut, taper_b,
  8140. revolutions, radiusoffset, skew, (byte)ProfileShape.EquilateralTriangle, (byte)Extrusion.Curve1);
  8141. break;
  8142. case ScriptBaseClass.PRIM_TYPE_SCULPT:
  8143. if (remain < 2)
  8144. return new LSL_List();
  8145. string map = rules.Data[idx++].ToString();
  8146. try
  8147. {
  8148. face = rules.GetIntegerItem(idx++); // type
  8149. }
  8150. catch(InvalidCastException)
  8151. {
  8152. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TYPE, PRIM_TYPE_SCULPT: arg #{1} - parameter 4 must be integer", rulesParsed, idx - idxStart - 1));
  8153. return new LSL_List();
  8154. }
  8155. SetPrimitiveShapeSculptParams(part, map, face, (byte)Extrusion.Curve1);
  8156. break;
  8157. }
  8158. break;
  8159. case ScriptBaseClass.PRIM_TEXTURE:
  8160. if (remain < 5)
  8161. return new LSL_List();
  8162. face=rules.GetIntegerItem(idx++);
  8163. string tex;
  8164. LSL_Vector repeats;
  8165. LSL_Vector offsets;
  8166. double rotation;
  8167. tex = rules.Data[idx++].ToString();
  8168. try
  8169. {
  8170. repeats = rules.GetVector3Item(idx++);
  8171. }
  8172. catch(InvalidCastException)
  8173. {
  8174. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TEXTURE: arg #{1} - parameter 3 must be vector", rulesParsed, idx - idxStart - 1));
  8175. return new LSL_List();
  8176. }
  8177. try
  8178. {
  8179. offsets = rules.GetVector3Item(idx++);
  8180. }
  8181. catch(InvalidCastException)
  8182. {
  8183. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TEXTURE: arg #{1} - parameter 4 must be vector", rulesParsed, idx - idxStart - 1));
  8184. return new LSL_List();
  8185. }
  8186. try
  8187. {
  8188. rotation = rules.GetStrictFloatItem(idx++);
  8189. }
  8190. catch(InvalidCastException)
  8191. {
  8192. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TEXTURE: arg #{1} - parameter 5 must be float", rulesParsed, idx - idxStart - 1));
  8193. return new LSL_List();
  8194. }
  8195. SetTextureParams(part, tex, repeats.x, repeats.y, offsets.x, offsets.y, rotation, face);
  8196. break;
  8197. case ScriptBaseClass.PRIM_COLOR:
  8198. if (remain < 3)
  8199. return new LSL_List();
  8200. LSL_Vector color;
  8201. float alpha;
  8202. try
  8203. {
  8204. face = rules.GetIntegerItem(idx++);
  8205. }
  8206. catch(InvalidCastException)
  8207. {
  8208. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_COLOR: arg #{1} - parameter 2 must be integer", rulesParsed, idx - idxStart - 1));
  8209. return new LSL_List();
  8210. }
  8211. try
  8212. {
  8213. color = rules.GetVector3Item(idx++);
  8214. }
  8215. catch(InvalidCastException)
  8216. {
  8217. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_COLOR: arg #{1} - parameter 3 must be vector", rulesParsed, idx - idxStart - 1));
  8218. return new LSL_List();
  8219. }
  8220. try
  8221. {
  8222. alpha = rules.GetStrictFloatItem(idx++);
  8223. }
  8224. catch(InvalidCastException)
  8225. {
  8226. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_COLOR: arg #{1} - parameter 4 must be float", rulesParsed, idx - idxStart - 1));
  8227. return new LSL_List();
  8228. }
  8229. part.SetFaceColorAlpha(face, color, alpha);
  8230. break;
  8231. case ScriptBaseClass.PRIM_FLEXIBLE:
  8232. if (remain < 7)
  8233. return new LSL_List();
  8234. bool flexi;
  8235. int softness;
  8236. float gravity;
  8237. float friction;
  8238. float wind;
  8239. float tension;
  8240. LSL_Vector force;
  8241. try
  8242. {
  8243. flexi = rules.GetIntegerItem(idx++) != 0;
  8244. }
  8245. catch(InvalidCastException)
  8246. {
  8247. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_FLEXIBLE: arg #{1} - parameter 2 must be integer", rulesParsed, idx - idxStart - 1));
  8248. return new LSL_List();
  8249. }
  8250. try
  8251. {
  8252. softness = rules.GetIntegerItem(idx++);
  8253. }
  8254. catch(InvalidCastException)
  8255. {
  8256. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_FLEXIBLE: arg #{1} - parameter 3 must be integer", rulesParsed, idx - idxStart - 1));
  8257. return new LSL_List();
  8258. }
  8259. try
  8260. {
  8261. gravity = rules.GetStrictFloatItem(idx++);
  8262. }
  8263. catch(InvalidCastException)
  8264. {
  8265. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_FLEXIBLE: arg #{1} - parameter 4 must be float", rulesParsed, idx - idxStart - 1));
  8266. return new LSL_List();
  8267. }
  8268. try
  8269. {
  8270. friction = rules.GetStrictFloatItem(idx++);
  8271. }
  8272. catch(InvalidCastException)
  8273. {
  8274. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_FLEXIBLE: arg #{1} - parameter 5 must be float", rulesParsed, idx - idxStart - 1));
  8275. return new LSL_List();
  8276. }
  8277. try
  8278. {
  8279. wind = rules.GetStrictFloatItem(idx++);
  8280. }
  8281. catch(InvalidCastException)
  8282. {
  8283. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_FLEXIBLE: arg #{1} - parameter 6 must be float", rulesParsed, idx - idxStart - 1));
  8284. return new LSL_List();
  8285. }
  8286. try
  8287. {
  8288. tension = rules.GetStrictFloatItem(idx++);
  8289. }
  8290. catch(InvalidCastException)
  8291. {
  8292. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_FLEXIBLE: arg #{1} - parameter 7 must be float", rulesParsed, idx - idxStart - 1));
  8293. return new LSL_List();
  8294. }
  8295. try
  8296. {
  8297. force = rules.GetVector3Item(idx++);
  8298. }
  8299. catch(InvalidCastException)
  8300. {
  8301. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_FLEXIBLE: arg #{1} - parameter 8 must be vector", rulesParsed, idx - idxStart - 1));
  8302. return new LSL_List();
  8303. }
  8304. SetFlexi(part, flexi, softness, gravity, friction, wind, tension, force);
  8305. break;
  8306. case ScriptBaseClass.PRIM_POINT_LIGHT:
  8307. if (remain < 5)
  8308. return new LSL_List();
  8309. bool light;
  8310. LSL_Vector lightcolor;
  8311. float intensity;
  8312. float radius;
  8313. float falloff;
  8314. try
  8315. {
  8316. light = rules.GetIntegerItem(idx++) != 0;
  8317. }
  8318. catch(InvalidCastException)
  8319. {
  8320. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_POINT_LIGHT: arg #{1} - parameter 2 must be integer", rulesParsed, idx - idxStart - 1));
  8321. return new LSL_List();
  8322. }
  8323. try
  8324. {
  8325. lightcolor = rules.GetVector3Item(idx++);
  8326. }
  8327. catch(InvalidCastException)
  8328. {
  8329. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_POINT_LIGHT: arg #{1} - parameter 3 must be vector", rulesParsed, idx - idxStart - 1));
  8330. return new LSL_List();
  8331. }
  8332. try
  8333. {
  8334. intensity = rules.GetStrictFloatItem(idx++);
  8335. }
  8336. catch(InvalidCastException)
  8337. {
  8338. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_POINT_LIGHT: arg #{1} - parameter 4 must be float", rulesParsed, idx - idxStart - 1));
  8339. return new LSL_List();
  8340. }
  8341. try
  8342. {
  8343. radius = rules.GetStrictFloatItem(idx++);
  8344. }
  8345. catch(InvalidCastException)
  8346. {
  8347. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_POINT_LIGHT: arg #{1} - parameter 5 must be float", rulesParsed, idx - idxStart - 1));
  8348. return new LSL_List();
  8349. }
  8350. try
  8351. {
  8352. falloff = rules.GetStrictFloatItem(idx++);
  8353. }
  8354. catch(InvalidCastException)
  8355. {
  8356. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_POINT_LIGHT: arg #{1} - parameter 6 must be float", rulesParsed, idx - idxStart - 1));
  8357. return new LSL_List();
  8358. }
  8359. SetPointLight(part, light, lightcolor, intensity, radius, falloff);
  8360. break;
  8361. case ScriptBaseClass.PRIM_REFLECTION_PROBE:
  8362. if (remain < 4)
  8363. return new LSL_List();
  8364. bool reflection_probe_active;
  8365. float reflection_probe_ambiance;
  8366. float reflection_probe_clip_distance;
  8367. int reflection_probe_flags;
  8368. try
  8369. {
  8370. reflection_probe_active = rules.GetIntegerItem(idx++) != 0;
  8371. }
  8372. catch (InvalidCastException)
  8373. {
  8374. Error(originFunc, $"Error running rule #{rulesParsed} -> PRIM_REFLECTION_PROBE: arg #{idx - idxStart - 1} - parameter 1 (active) must be integer");
  8375. return new LSL_List();
  8376. }
  8377. try
  8378. {
  8379. reflection_probe_ambiance = rules.GetStrictFloatItem(idx++);
  8380. }
  8381. catch (InvalidCastException)
  8382. {
  8383. Error(originFunc, $"Error running rule #{rulesParsed} -> PRIM_REFLECTION_PROBE: arg #{idx - idxStart - 1} - parameter 2 (ambiance) must be float");
  8384. return new LSL_List();
  8385. }
  8386. try
  8387. {
  8388. reflection_probe_clip_distance = rules.GetStrictFloatItem(idx++);
  8389. }
  8390. catch (InvalidCastException)
  8391. {
  8392. Error(originFunc, $"Error running rule #{rulesParsed} -> PRIM_REFLECTION_PROBE: arg #{idx - idxStart - 1} - parameter 3 (clip_distance) must be float");
  8393. return new LSL_List();
  8394. }
  8395. try
  8396. {
  8397. reflection_probe_flags = rules.GetIntegerItem(idx++);
  8398. }
  8399. catch (InvalidCastException)
  8400. {
  8401. Error(originFunc, $"Error running rule #{rulesParsed} -> PRIM_REFLECTION_PROBE: arg #{idx - idxStart - 1} - parameter 4 (flags) must be integer");
  8402. return new LSL_List();
  8403. }
  8404. bool probechanged;
  8405. if(reflection_probe_active)
  8406. {
  8407. probechanged = part.Shape.ReflectionProbe is null;
  8408. if(probechanged)
  8409. part.Shape.ReflectionProbe = new();
  8410. reflection_probe_ambiance = Utils.Clamp(reflection_probe_ambiance, 0f, 100f);
  8411. probechanged |= part.Shape.ReflectionProbe.Ambiance != reflection_probe_ambiance;
  8412. part.Shape.ReflectionProbe.Ambiance = reflection_probe_ambiance;
  8413. reflection_probe_clip_distance = Utils.Clamp(reflection_probe_clip_distance, 0f, 1024f);
  8414. probechanged |= part.Shape.ReflectionProbe.ClipDistance != reflection_probe_clip_distance;
  8415. part.Shape.ReflectionProbe.ClipDistance = reflection_probe_clip_distance;
  8416. probechanged |= part.Shape.ReflectionProbe.Flags != reflection_probe_flags;
  8417. part.Shape.ReflectionProbe.Flags = (byte)reflection_probe_flags;
  8418. }
  8419. else
  8420. {
  8421. probechanged = part.Shape.ReflectionProbe is not null;
  8422. part.Shape.ReflectionProbe = null;
  8423. }
  8424. if(probechanged)
  8425. {
  8426. part.ParentGroup.HasGroupChanged = true;
  8427. part.ScheduleFullUpdate();
  8428. }
  8429. break;
  8430. case ScriptBaseClass.PRIM_GLOW:
  8431. if (remain < 2)
  8432. return new LSL_List();
  8433. float glow;
  8434. try
  8435. {
  8436. face = rules.GetIntegerItem(idx++);
  8437. }
  8438. catch(InvalidCastException)
  8439. {
  8440. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_GLOW: arg #{1} - parameter 2 must be integer", rulesParsed, idx - idxStart - 1));
  8441. return new LSL_List();
  8442. }
  8443. try
  8444. {
  8445. glow = rules.GetStrictFloatItem(idx++);
  8446. }
  8447. catch(InvalidCastException)
  8448. {
  8449. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_GLOW: arg #{1} - parameter 3 must be float", rulesParsed, idx - idxStart - 1));
  8450. return new LSL_List();
  8451. }
  8452. SetGlow(part, face, glow);
  8453. break;
  8454. case ScriptBaseClass.PRIM_BUMP_SHINY:
  8455. if (remain < 3)
  8456. return new LSL_List();
  8457. int shiny;
  8458. Bumpiness bump;
  8459. try
  8460. {
  8461. face = rules.GetIntegerItem(idx++);
  8462. }
  8463. catch(InvalidCastException)
  8464. {
  8465. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_BUMP_SHINY: arg #{1} - parameter 2 must be integer", rulesParsed, idx - idxStart - 1));
  8466. return new LSL_List();
  8467. }
  8468. try
  8469. {
  8470. shiny = rules.GetIntegerItem(idx++);
  8471. }
  8472. catch(InvalidCastException)
  8473. {
  8474. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_BUMP_SHINY: arg #{1} - parameter 3 must be integer", rulesParsed, idx - idxStart - 1));
  8475. return new LSL_List();
  8476. }
  8477. try
  8478. {
  8479. bump = (Bumpiness)rules.GetIntegerItem(idx++);
  8480. }
  8481. catch(InvalidCastException)
  8482. {
  8483. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_BUMP_SHINY: arg #{1} - parameter 4 must be integer", rulesParsed, idx - idxStart - 1));
  8484. return new LSL_List();
  8485. }
  8486. SetShiny(part, face, shiny, bump);
  8487. break;
  8488. case ScriptBaseClass.PRIM_FULLBRIGHT:
  8489. if (remain < 2)
  8490. return new LSL_List();
  8491. bool st;
  8492. try
  8493. {
  8494. face = rules.GetIntegerItem(idx++);
  8495. }
  8496. catch(InvalidCastException)
  8497. {
  8498. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_FULLBRIGHT: arg #{1} - parameter 2 must be integer", rulesParsed, idx - idxStart - 1));
  8499. return new LSL_List();
  8500. }
  8501. try
  8502. {
  8503. st = rules.GetIntegerItem(idx++) != 0;
  8504. }
  8505. catch(InvalidCastException)
  8506. {
  8507. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_FULLBRIGHT: arg #{1} - parameter 4 must be integer", rulesParsed, idx - idxStart - 1));
  8508. return new LSL_List();
  8509. }
  8510. SetFullBright(part, face , st);
  8511. break;
  8512. case ScriptBaseClass.PRIM_MATERIAL:
  8513. if (remain < 1)
  8514. return new LSL_List();
  8515. int mat;
  8516. try
  8517. {
  8518. mat = rules.GetIntegerItem(idx++);
  8519. }
  8520. catch(InvalidCastException)
  8521. {
  8522. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_MATERIAL: arg #{1} - parameter 2 must be integer", rulesParsed, idx - idxStart - 1));
  8523. return new LSL_List();
  8524. }
  8525. if (mat < 0 || mat > 7)
  8526. return new LSL_List();
  8527. part.Material = Convert.ToByte(mat);
  8528. break;
  8529. case ScriptBaseClass.PRIM_PHANTOM:
  8530. if (remain < 1)
  8531. return new LSL_List();
  8532. string ph = rules.Data[idx++].ToString();
  8533. part.ParentGroup.ScriptSetPhantomStatus(ph.Equals("1"));
  8534. break;
  8535. case ScriptBaseClass.PRIM_PHYSICS:
  8536. if (remain < 1)
  8537. return new LSL_List();
  8538. string phy = rules.Data[idx++].ToString();
  8539. part.ScriptSetPhysicsStatus(phy.Equals("1"));
  8540. break;
  8541. case ScriptBaseClass.PRIM_PHYSICS_SHAPE_TYPE:
  8542. if (remain < 1)
  8543. return new LSL_List();
  8544. int shape_type;
  8545. try
  8546. {
  8547. shape_type = rules.GetIntegerItem(idx++);
  8548. }
  8549. catch(InvalidCastException)
  8550. {
  8551. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_PHYSICS_SHAPE_TYPE: arg #{1} - parameter 2 must be integer", rulesParsed, idx - idxStart - 1));
  8552. return new LSL_List();
  8553. }
  8554. ExtraPhysicsData physdata = new()
  8555. {
  8556. Density = part.Density,
  8557. Bounce = part.Restitution,
  8558. GravitationModifier = part.GravityModifier,
  8559. PhysShapeType = (PhysShapeType)shape_type
  8560. };
  8561. part.UpdateExtraPhysics(physdata);
  8562. break;
  8563. case ScriptBaseClass.PRIM_PHYSICS_MATERIAL:
  8564. if (remain < 5)
  8565. return new LSL_List();
  8566. int material_bits = rules.GetIntegerItem(idx++);
  8567. float material_density = rules.GetFloatItem(idx++);
  8568. float material_friction = rules.GetFloatItem(idx++);
  8569. float material_restitution = rules.GetFloatItem(idx++);
  8570. float material_gravity_modifier = rules.GetFloatItem(idx++);
  8571. SetPhysicsMaterial(part, material_bits, material_density, material_friction, material_restitution, material_gravity_modifier);
  8572. break;
  8573. case ScriptBaseClass.PRIM_TEMP_ON_REZ:
  8574. if (remain < 1)
  8575. return new LSL_List();
  8576. string temp = rules.Data[idx++].ToString();
  8577. part.ParentGroup.ScriptSetTemporaryStatus(temp.Equals("1"));
  8578. break;
  8579. case ScriptBaseClass.PRIM_TEXGEN:
  8580. if (remain < 2)
  8581. return new LSL_List();
  8582. //face,type
  8583. int style;
  8584. try
  8585. {
  8586. face = rules.GetIntegerItem(idx++);
  8587. }
  8588. catch(InvalidCastException)
  8589. {
  8590. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TEXGEN: arg #{1} - parameter 2 must be integer", rulesParsed, idx - idxStart - 1));
  8591. return new LSL_List();
  8592. }
  8593. try
  8594. {
  8595. style = rules.GetIntegerItem(idx++);
  8596. }
  8597. catch(InvalidCastException)
  8598. {
  8599. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TEXGEN: arg #{1} - parameter 3 must be integer", rulesParsed, idx - idxStart - 1));
  8600. return new LSL_List();
  8601. }
  8602. SetTexGen(part, face, style);
  8603. break;
  8604. case ScriptBaseClass.PRIM_TEXT:
  8605. if (remain < 3)
  8606. return new LSL_List();
  8607. string primText;
  8608. LSL_Vector primTextColor;
  8609. float primTextAlpha;
  8610. try
  8611. {
  8612. primText = rules.GetStrictStringItem(idx++);
  8613. }
  8614. catch(InvalidCastException)
  8615. {
  8616. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TEXT: arg #{1} - parameter 2 must be string", rulesParsed, idx - idxStart - 1));
  8617. return new LSL_List();
  8618. }
  8619. try
  8620. {
  8621. primTextColor = rules.GetVector3Item(idx++);
  8622. }
  8623. catch(InvalidCastException)
  8624. {
  8625. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TEXT: arg #{1} - parameter 3 must be vector", rulesParsed, idx - idxStart - 1));
  8626. return new LSL_List();
  8627. }
  8628. try
  8629. {
  8630. primTextAlpha = rules.GetStrictFloatItem(idx++);
  8631. }
  8632. catch(InvalidCastException)
  8633. {
  8634. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_TEXT: arg #{1} - parameter 4 must be float", rulesParsed, idx - idxStart - 1));
  8635. return new LSL_List();
  8636. }
  8637. Vector3 av3 = Vector3.Clamp(primTextColor, 0.0f, 1.0f);
  8638. part.SetText(primText, av3, Utils.Clamp(primTextAlpha, 0.0f, 1.0f));
  8639. break;
  8640. case ScriptBaseClass.PRIM_NAME:
  8641. if (remain < 1)
  8642. return new LSL_List();
  8643. try
  8644. {
  8645. string primName = rules.GetStrictStringItem(idx++);
  8646. part.Name = primName;
  8647. }
  8648. catch(InvalidCastException)
  8649. {
  8650. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_NAME: arg #{1} - parameter 2 must be string", rulesParsed, idx - idxStart - 1));
  8651. return new LSL_List();
  8652. }
  8653. break;
  8654. case ScriptBaseClass.PRIM_DESC:
  8655. if (remain < 1)
  8656. return new LSL_List();
  8657. try
  8658. {
  8659. string primDesc = rules.GetStrictStringItem(idx++);
  8660. part.Description = primDesc;
  8661. }
  8662. catch(InvalidCastException)
  8663. {
  8664. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_DESC: arg #{1} - parameter 2 must be string", rulesParsed, idx - idxStart - 1));
  8665. return new LSL_List();
  8666. }
  8667. break;
  8668. case ScriptBaseClass.PRIM_ROT_LOCAL:
  8669. if (remain < 1)
  8670. return new LSL_List();
  8671. LSL_Rotation rot;
  8672. try
  8673. {
  8674. rot = rules.GetQuaternionItem(idx++);
  8675. }
  8676. catch(InvalidCastException)
  8677. {
  8678. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_ROT_LOCAL: arg #{1} - parameter 2 must be rotation", rulesParsed, idx - idxStart - 1));
  8679. return new LSL_List();
  8680. }
  8681. SetRot(part, rot);
  8682. break;
  8683. case ScriptBaseClass.PRIM_OMEGA:
  8684. if (remain < 3)
  8685. return new LSL_List();
  8686. LSL_Vector axis;
  8687. float spinrate;
  8688. float gain;
  8689. try
  8690. {
  8691. axis = rules.GetVector3Item(idx++);
  8692. }
  8693. catch(InvalidCastException)
  8694. {
  8695. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_OMEGA: arg #{1} - parameter 2 must be vector", rulesParsed, idx - idxStart - 1));
  8696. return new LSL_List();
  8697. }
  8698. try
  8699. {
  8700. spinrate = rules.GetStrictFloatItem(idx++);
  8701. }
  8702. catch(InvalidCastException)
  8703. {
  8704. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_OMEGA: arg #{1} - parameter 3 must be float", rulesParsed, idx - idxStart - 1));
  8705. return new LSL_List();
  8706. }
  8707. try
  8708. {
  8709. gain = rules.GetStrictFloatItem(idx++);
  8710. }
  8711. catch(InvalidCastException)
  8712. {
  8713. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_OMEGA: arg #{1} - parameter 4 must be float", rulesParsed, idx - idxStart - 1));
  8714. return new LSL_List();
  8715. }
  8716. TargetOmega(part, axis, spinrate, gain);
  8717. break;
  8718. case ScriptBaseClass.PRIM_SLICE:
  8719. if (remain < 1)
  8720. return new LSL_List();
  8721. LSL_Vector slice;
  8722. try
  8723. {
  8724. slice = rules.GetVector3Item(idx++);
  8725. }
  8726. catch(InvalidCastException)
  8727. {
  8728. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_SLICE: arg #{1} - parameter 2 must be vector", rulesParsed, idx - idxStart - 1));
  8729. return new LSL_List();
  8730. }
  8731. part.UpdateSlice((float)slice.x, (float)slice.y);
  8732. break;
  8733. case ScriptBaseClass.PRIM_SIT_TARGET:
  8734. if (remain < 3)
  8735. return new LSL_List();
  8736. int active;
  8737. try
  8738. {
  8739. active = rules.GetIntegerItem(idx++);
  8740. }
  8741. catch(InvalidCastException)
  8742. {
  8743. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_SIT_TARGET: arg #{1} - parameter 1 must be integer", rulesParsed, idx - idxStart - 1));
  8744. return new LSL_List();
  8745. }
  8746. LSL_Vector offset;
  8747. try
  8748. {
  8749. offset = rules.GetVector3Item(idx++);
  8750. }
  8751. catch(InvalidCastException)
  8752. {
  8753. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_SIT_TARGET: arg #{1} - parameter 2 must be vector", rulesParsed, idx - idxStart - 1));
  8754. return new LSL_List();
  8755. }
  8756. LSL_Rotation sitrot;
  8757. try
  8758. {
  8759. sitrot = rules.GetQuaternionItem(idx++);
  8760. }
  8761. catch(InvalidCastException)
  8762. {
  8763. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_SIT_TARGET: arg #{1} - parameter 3 must be rotation", rulesParsed, idx - idxStart - 1));
  8764. return new LSL_List();
  8765. }
  8766. // not SL compatible since we don't have a independent flag to control active target but use the values of offset and rotation
  8767. if(active == 1)
  8768. {
  8769. if(offset.x == 0 && offset.y == 0 && offset.z == 0 && sitrot.s == 1.0)
  8770. offset.z = 1e-5f; // hack
  8771. SitTarget(part,offset,sitrot);
  8772. }
  8773. else if(active == 0)
  8774. SitTarget(part, Vector3.Zero , Quaternion.Identity);
  8775. break;
  8776. case ScriptBaseClass.PRIM_ALPHA_MODE:
  8777. if (remain < 3)
  8778. return new LSL_List();
  8779. try
  8780. {
  8781. face = rules.GetIntegerItem(idx++);
  8782. }
  8783. catch(InvalidCastException)
  8784. {
  8785. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_ALPHA_MODE: arg #{1} - must be integer", rulesParsed, idx - idxStart - 1));
  8786. return new LSL_List();
  8787. }
  8788. int materialAlphaMode;
  8789. try
  8790. {
  8791. materialAlphaMode = rules.GetIntegerItem(idx++);
  8792. }
  8793. catch(InvalidCastException)
  8794. {
  8795. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_ALPHA_MODE: arg #{1} - must be integer", rulesParsed, idx - idxStart - 1));
  8796. return new LSL_List();
  8797. }
  8798. if(materialAlphaMode < 0 || materialAlphaMode > 3)
  8799. {
  8800. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_ALPHA_MODE: arg #{1} - must be 0 to 3", rulesParsed, idx - idxStart - 1));
  8801. return new LSL_List();
  8802. }
  8803. int materialMaskCutoff;
  8804. try
  8805. {
  8806. materialMaskCutoff = rules.GetIntegerItem(idx++);
  8807. }
  8808. catch(InvalidCastException)
  8809. {
  8810. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_ALPHA_MODE: arg #{1} - must be integer", rulesParsed, idx - idxStart - 1));
  8811. return new LSL_List();
  8812. }
  8813. if(materialMaskCutoff < 0 || materialMaskCutoff > 255)
  8814. {
  8815. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_ALPHA_MODE: arg #{1} - must be 0 to 255", rulesParsed, idx - idxStart - 1));
  8816. return new LSL_List();
  8817. }
  8818. materialChanged |= SetMaterialAlphaMode(part, face, materialAlphaMode, materialMaskCutoff);
  8819. break;
  8820. case ScriptBaseClass.PRIM_NORMAL:
  8821. if (remain < 5)
  8822. return new LSL_List();
  8823. try
  8824. {
  8825. face = rules.GetIntegerItem(idx++);
  8826. }
  8827. catch(InvalidCastException)
  8828. {
  8829. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_NORMAL: arg #{1} - must be integer", rulesParsed, idx - idxStart - 1));
  8830. return new LSL_List();
  8831. }
  8832. string mapname = rules.Data[idx++].ToString();
  8833. UUID mapID = UUID.Zero;
  8834. if (!string.IsNullOrEmpty(mapname))
  8835. {
  8836. mapID = ScriptUtils.GetAssetIdFromItemName(m_host, mapname, (int)AssetType.Texture);
  8837. if (mapID.IsZero())
  8838. {
  8839. if (!UUID.TryParse(mapname, out mapID))
  8840. {
  8841. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_NORMAL: arg #{1} - must be a UUID or a texture name on object inventory", rulesParsed, idx - idxStart - 1));
  8842. return new LSL_List();
  8843. }
  8844. }
  8845. }
  8846. LSL_Vector mnrepeat;
  8847. try
  8848. {
  8849. mnrepeat = rules.GetVector3Item(idx++);
  8850. }
  8851. catch(InvalidCastException)
  8852. {
  8853. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_NORMAL: arg #{1} - must be vector", rulesParsed, idx - idxStart - 1));
  8854. return new LSL_List();
  8855. }
  8856. LSL_Vector mnoffset;
  8857. try
  8858. {
  8859. mnoffset = rules.GetVector3Item(idx++);
  8860. }
  8861. catch(InvalidCastException)
  8862. {
  8863. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_NORMAL: arg #{1} - must be vector", rulesParsed, idx - idxStart - 1));
  8864. return new LSL_List();
  8865. }
  8866. float mnrot;
  8867. try
  8868. {
  8869. mnrot = rules.GetStrictFloatItem(idx++);
  8870. }
  8871. catch(InvalidCastException)
  8872. {
  8873. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_NORMAL: arg #{1} - must be float", rulesParsed, idx - idxStart - 1));
  8874. return new LSL_List();
  8875. }
  8876. float repeatX = Math.Clamp((float)mnrepeat.x,-100.0f, 100.0f);
  8877. float repeatY = Math.Clamp((float)mnrepeat.y,-100.0f, 100.0f);
  8878. float offsetX = Math.Clamp((float)mnoffset.x, 0f, 1.0f);
  8879. float offsetY = Math.Clamp((float)mnoffset.y, 0f, 1.0f);
  8880. materialChanged |= SetMaterialNormalMap(part, face, mapID, repeatX, repeatY, offsetX, offsetY, mnrot);
  8881. break;
  8882. case ScriptBaseClass.PRIM_SPECULAR:
  8883. if (remain < 8)
  8884. return new LSL_List();
  8885. try
  8886. {
  8887. face = rules.GetIntegerItem(idx++);
  8888. }
  8889. catch(InvalidCastException)
  8890. {
  8891. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_SPECULAR: arg #{1} - must be integer", rulesParsed, idx - idxStart - 1));
  8892. return new LSL_List();
  8893. }
  8894. string smapname = rules.Data[idx++].ToString();
  8895. UUID smapID = UUID.Zero;
  8896. if(!string.IsNullOrEmpty(smapname))
  8897. {
  8898. smapID = ScriptUtils.GetAssetIdFromItemName(m_host, smapname, (int)AssetType.Texture);
  8899. if (smapID.IsZero())
  8900. {
  8901. if (!UUID.TryParse(smapname, out smapID))
  8902. {
  8903. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_SPECULAR: arg #{1} - must be a UUID or a texture name on object inventory", rulesParsed, idx - idxStart - 1));
  8904. return new LSL_List();
  8905. }
  8906. }
  8907. }
  8908. LSL_Vector msrepeat;
  8909. try
  8910. {
  8911. msrepeat = rules.GetVector3Item(idx++);
  8912. }
  8913. catch(InvalidCastException)
  8914. {
  8915. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_SPECULAR: arg #{1} - must be vector", rulesParsed, idx - idxStart - 1));
  8916. return new LSL_List();
  8917. }
  8918. LSL_Vector msoffset;
  8919. try
  8920. {
  8921. msoffset = rules.GetVector3Item(idx++);
  8922. }
  8923. catch(InvalidCastException)
  8924. {
  8925. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_SPECULAR: arg #{1} - must be vector", rulesParsed, idx - idxStart - 1));
  8926. return new LSL_List();
  8927. }
  8928. float msrot;
  8929. try
  8930. {
  8931. msrot = rules.GetStrictFloatItem(idx++);
  8932. }
  8933. catch(InvalidCastException)
  8934. {
  8935. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_SPECULAR: arg #{1} - must be float", rulesParsed, idx - idxStart - 1));
  8936. return new LSL_List();
  8937. }
  8938. LSL_Vector mscolor;
  8939. try
  8940. {
  8941. mscolor = rules.GetVector3Item(idx++);
  8942. }
  8943. catch(InvalidCastException)
  8944. {
  8945. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_SPECULAR: arg #{1} - must be vector", rulesParsed, idx - idxStart - 1));
  8946. return new LSL_List();
  8947. }
  8948. LSL_Integer msgloss;
  8949. try
  8950. {
  8951. msgloss = rules.GetIntegerItem(idx++);
  8952. }
  8953. catch(InvalidCastException)
  8954. {
  8955. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_SPECULAR: arg #{1} - must be integer", rulesParsed, idx - idxStart - 1));
  8956. return new LSL_List();
  8957. }
  8958. LSL_Integer msenv;
  8959. try
  8960. {
  8961. msenv = rules.GetIntegerItem(idx++);
  8962. }
  8963. catch(InvalidCastException)
  8964. {
  8965. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_SPECULAR: arg #{1} - must be integer", rulesParsed, idx - idxStart - 1));
  8966. return new LSL_List();
  8967. }
  8968. float srepeatX = Math.Clamp((float)msrepeat.x, -100.0f, 100.0f);
  8969. float srepeatY = Math.Clamp((float)msrepeat.y, -100.0f, 100.0f);
  8970. float soffsetX = Math.Clamp((float)msoffset.x, -1.0f, 1.0f);
  8971. float soffsetY = Math.Clamp((float)msoffset.y, -1.0f, 1.0f);
  8972. byte colorR = (byte)(255.0f * Math.Clamp((float)mscolor.x, 0f, 1.0f) + 0.5f);
  8973. byte colorG = (byte)(255.0f * Math.Clamp((float)mscolor.y, 0f, 1.0f) + 0.5f);
  8974. byte colorB = (byte)(255.0f * Math.Clamp((float)mscolor.z, 0f, 1.0f) + 0.5f);
  8975. byte gloss = (byte)Math.Clamp((int)msgloss, 0, 255);
  8976. byte env = (byte)Math.Clamp((int)msenv, 0, 255);
  8977. materialChanged |= SetMaterialSpecMap(part, face, smapID, srepeatX, srepeatY, soffsetX, soffsetY,
  8978. msrot, colorR, colorG, colorB, gloss, env);
  8979. break;
  8980. case ScriptBaseClass.PRIM_LINK_TARGET:
  8981. if (remain < 3) // setting to 3 on the basis that parsing any usage of PRIM_LINK_TARGET that has nothing following it is pointless.
  8982. return new LSL_List();
  8983. return rules.GetSublist(idx, -1);
  8984. case ScriptBaseClass.PRIM_PROJECTOR:
  8985. if (remain < 4)
  8986. return new LSL_List();
  8987. string stexname = rules.Data[idx++].ToString();
  8988. UUID stexID = UUID.Zero;
  8989. if(!string.IsNullOrEmpty(stexname))
  8990. {
  8991. stexID = ScriptUtils.GetAssetIdFromItemName(m_host, stexname, (int)AssetType.Texture);
  8992. if (stexID.IsZero())
  8993. {
  8994. if (!UUID.TryParse(stexname, out stexID))
  8995. {
  8996. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_PROJECTOR: arg #{1} - must be a UUID or a texture name on object inventory", rulesParsed, idx - idxStart - 1));
  8997. return new LSL_List();
  8998. }
  8999. }
  9000. }
  9001. float fov;
  9002. try
  9003. {
  9004. fov = rules.GetStrictFloatItem(idx++);
  9005. }
  9006. catch(InvalidCastException)
  9007. {
  9008. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_PROJECTOR: arg #{1} - must be float", rulesParsed, idx - idxStart - 1));
  9009. return new LSL_List();
  9010. }
  9011. float focus;
  9012. try
  9013. {
  9014. focus = rules.GetStrictFloatItem(idx++);
  9015. }
  9016. catch(InvalidCastException)
  9017. {
  9018. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_PROJECTOR: arg #{1} - must be float", rulesParsed, idx - idxStart - 1));
  9019. return new LSL_List();
  9020. }
  9021. float amb;
  9022. try
  9023. {
  9024. amb = rules.GetStrictFloatItem(idx++);
  9025. }
  9026. catch(InvalidCastException)
  9027. {
  9028. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_PROJECTOR: arg #{1} - must be float", rulesParsed, idx - idxStart - 1));
  9029. return new LSL_List();
  9030. }
  9031. if(stexID.IsNotZero())
  9032. {
  9033. part.Shape.ProjectionEntry = true;
  9034. part.Shape.ProjectionTextureUUID = stexID;
  9035. part.Shape.ProjectionFOV = Math.Clamp(fov, 0, 3.0f);
  9036. part.Shape.ProjectionFocus = Math.Clamp(focus, -20.0f, 20.0f);
  9037. part.Shape.ProjectionAmbiance = Math.Clamp(amb, 0, 1.0f);
  9038. part.ParentGroup.HasGroupChanged = true;
  9039. part.ScheduleFullUpdate();
  9040. }
  9041. else if(part.Shape.ProjectionEntry)
  9042. {
  9043. part.Shape.ProjectionEntry = false;
  9044. part.ParentGroup.HasGroupChanged = true;
  9045. part.ScheduleFullUpdate();
  9046. }
  9047. break;
  9048. default:
  9049. Error(originFunc, string.Format("Error running rule #{0}: arg #{1} - unsupported parameter", rulesParsed, idx - idxStart));
  9050. return new LSL_List();
  9051. }
  9052. }
  9053. }
  9054. catch (InvalidCastException e)
  9055. {
  9056. Error(originFunc, string.Format("Error running rule #{0}: arg #{1} - ", rulesParsed, idx - idxStart) + e.Message);
  9057. }
  9058. finally
  9059. {
  9060. if (positionChanged)
  9061. {
  9062. if (part.ParentGroup.RootPart == part)
  9063. {
  9064. SceneObjectGroup parent = part.ParentGroup;
  9065. // Util.FireAndForget(delegate(object x) {
  9066. parent.UpdateGroupPosition(currentPosition);
  9067. // });
  9068. }
  9069. else
  9070. {
  9071. part.OffsetPosition = currentPosition;
  9072. // SceneObjectGroup parent = part.ParentGroup;
  9073. // parent.HasGroupChanged = true;
  9074. // parent.ScheduleGroupForTerseUpdate();
  9075. part.ScheduleTerseUpdate();
  9076. }
  9077. }
  9078. if(materialChanged)
  9079. {
  9080. if (part.ParentGroup != null && !part.ParentGroup.IsDeleted)
  9081. {
  9082. part.TriggerScriptChangedEvent(Changed.TEXTURE);
  9083. part.ScheduleFullUpdate();
  9084. part.ParentGroup.HasGroupChanged = true;
  9085. }
  9086. }
  9087. }
  9088. return new LSL_List();
  9089. }
  9090. protected bool SetMaterialAlphaMode(SceneObjectPart part, int face, int materialAlphaMode, int materialMaskCutoff)
  9091. {
  9092. if(m_materialsModule == null)
  9093. return false;
  9094. int nsides = part.GetNumberOfSides();
  9095. if(face == ScriptBaseClass.ALL_SIDES)
  9096. {
  9097. bool changed = false;
  9098. for(int i = 0; i < nsides; i++)
  9099. changed |= SetFaceMaterialAlphaMode(part, i, materialAlphaMode, materialMaskCutoff);
  9100. return changed;
  9101. }
  9102. if( face >= 0 && face < nsides)
  9103. return SetFaceMaterialAlphaMode(part, face, materialAlphaMode, materialMaskCutoff);
  9104. return false;
  9105. }
  9106. protected bool SetFaceMaterialAlphaMode(SceneObjectPart part, int face, int materialAlphaMode, int materialMaskCutoff)
  9107. {
  9108. Primitive.TextureEntry tex = part.Shape.Textures;
  9109. Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
  9110. if(texface == null)
  9111. return false;
  9112. FaceMaterial mat = null;
  9113. UUID oldid = texface.MaterialID;
  9114. if (oldid.IsZero())
  9115. {
  9116. if (materialAlphaMode == 1)
  9117. return false;
  9118. }
  9119. else
  9120. mat = m_materialsModule.GetMaterialCopy(oldid);
  9121. mat ??= new FaceMaterial();
  9122. mat.DiffuseAlphaMode = (byte)materialAlphaMode;
  9123. mat.AlphaMaskCutoff = (byte)materialMaskCutoff;
  9124. UUID id = m_materialsModule.AddNewMaterial(mat); // id is a hash of entire material hash, so this means no change
  9125. if(oldid.Equals(id))
  9126. return false;
  9127. texface.MaterialID = id;
  9128. part.Shape.TextureEntry = tex.GetBytes(9);
  9129. m_materialsModule.RemoveMaterial(oldid);
  9130. return true;
  9131. }
  9132. protected bool SetMaterialNormalMap(SceneObjectPart part, int face, UUID mapID, float repeatX, float repeatY,
  9133. float offsetX, float offsetY, float rot)
  9134. {
  9135. if(m_materialsModule == null)
  9136. return false;
  9137. int nsides = part.GetNumberOfSides();
  9138. if(face == ScriptBaseClass.ALL_SIDES)
  9139. {
  9140. bool changed = false;
  9141. for(int i = 0; i < nsides; i++)
  9142. changed |= SetFaceMaterialNormalMap(part, i, mapID, repeatX, repeatY, offsetX, offsetY, rot);
  9143. return changed;
  9144. }
  9145. if( face >= 0 && face < nsides)
  9146. return SetFaceMaterialNormalMap(part, face, mapID, repeatX, repeatY, offsetX, offsetY, rot);
  9147. return false;
  9148. }
  9149. protected bool SetFaceMaterialNormalMap(SceneObjectPart part, int face, UUID mapID, float repeatX, float repeatY,
  9150. float offsetX, float offsetY, float rot)
  9151. {
  9152. Primitive.TextureEntry tex = part.Shape.Textures;
  9153. Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
  9154. if(texface == null)
  9155. return false;
  9156. FaceMaterial mat = null;
  9157. UUID oldid = texface.MaterialID;
  9158. if (oldid.IsZero())
  9159. {
  9160. if (mapID.IsZero())
  9161. return false;
  9162. }
  9163. else
  9164. mat = m_materialsModule.GetMaterialCopy(oldid);
  9165. mat ??= new FaceMaterial();
  9166. mat.NormalMapID = mapID;
  9167. mat.NormalOffsetX = offsetX;
  9168. mat.NormalOffsetY = offsetY;
  9169. mat.NormalRepeatX = repeatX;
  9170. mat.NormalRepeatY = repeatY;
  9171. mat.NormalRotation = rot;
  9172. mapID = m_materialsModule.AddNewMaterial(mat);
  9173. if(oldid.Equals(mapID))
  9174. return false;
  9175. texface.MaterialID = mapID;
  9176. part.Shape.TextureEntry = tex.GetBytes(9);
  9177. m_materialsModule.RemoveMaterial(oldid);
  9178. return true;
  9179. }
  9180. protected bool SetMaterialSpecMap(SceneObjectPart part, int face, UUID mapID, float repeatX, float repeatY,
  9181. float offsetX, float offsetY, float rot,
  9182. byte colorR, byte colorG, byte colorB,
  9183. byte gloss, byte env)
  9184. {
  9185. if(m_materialsModule == null)
  9186. return false;
  9187. int nsides = part.GetNumberOfSides();
  9188. if(face == ScriptBaseClass.ALL_SIDES)
  9189. {
  9190. bool changed = false;
  9191. for(int i = 0; i < nsides; i++)
  9192. changed |= SetFaceMaterialSpecMap(part, i, mapID, repeatX, repeatY, offsetX, offsetY, rot,
  9193. colorR, colorG, colorB, gloss, env);
  9194. return changed;
  9195. }
  9196. if( face >= 0 && face < nsides)
  9197. return SetFaceMaterialSpecMap(part, face, mapID, repeatX, repeatY, offsetX, offsetY, rot,
  9198. colorR, colorG, colorB, gloss, env);
  9199. return false;
  9200. }
  9201. protected bool SetFaceMaterialSpecMap(SceneObjectPart part, int face, UUID mapID, float repeatX, float repeatY,
  9202. float offsetX, float offsetY, float rot,
  9203. byte colorR, byte colorG, byte colorB,
  9204. byte gloss, byte env)
  9205. {
  9206. Primitive.TextureEntry tex = part.Shape.Textures;
  9207. Primitive.TextureEntryFace texface = tex.CreateFace((uint)face);
  9208. if(texface == null)
  9209. return false;
  9210. FaceMaterial mat = null;
  9211. UUID oldid = texface.MaterialID;
  9212. if(oldid.IsZero())
  9213. {
  9214. if(mapID.IsZero())
  9215. return false;
  9216. }
  9217. else
  9218. mat = m_materialsModule.GetMaterialCopy(oldid);
  9219. mat ??= new FaceMaterial();
  9220. mat.SpecularMapID = mapID;
  9221. mat.SpecularOffsetX = offsetX;
  9222. mat.SpecularOffsetY = offsetY;
  9223. mat.SpecularRepeatX = repeatX;
  9224. mat.SpecularRepeatY = repeatY;
  9225. mat.SpecularRotation = rot;
  9226. mat.SpecularLightColorR = colorR;
  9227. mat.SpecularLightColorG = colorG;
  9228. mat.SpecularLightColorB = colorB;
  9229. mat.SpecularLightExponent = gloss;
  9230. mat.EnvironmentIntensity = env;
  9231. mapID = m_materialsModule.AddNewMaterial(mat);
  9232. if(oldid.Equals(mapID))
  9233. return false;
  9234. texface.MaterialID = mapID;
  9235. part.Shape.TextureEntry = tex.GetBytes(9);
  9236. m_materialsModule.RemoveMaterial(oldid);
  9237. return true;
  9238. }
  9239. protected LSL_List SetAgentParams(ScenePresence sp, LSL_List rules, string originFunc, ref uint rulesParsed)
  9240. {
  9241. int idx = 0;
  9242. int idxStart = 0;
  9243. try
  9244. {
  9245. while (idx < rules.Length)
  9246. {
  9247. ++rulesParsed;
  9248. int code = rules.GetIntegerItem(idx++);
  9249. int remain = rules.Length - idx;
  9250. idxStart = idx;
  9251. switch (code)
  9252. {
  9253. case ScriptBaseClass.PRIM_POSITION:
  9254. case ScriptBaseClass.PRIM_POS_LOCAL:
  9255. if (remain < 1)
  9256. return new LSL_List();
  9257. try
  9258. {
  9259. sp.OffsetPosition = rules.GetVector3Item(idx++);
  9260. }
  9261. catch(InvalidCastException)
  9262. {
  9263. if (code == ScriptBaseClass.PRIM_POSITION)
  9264. {
  9265. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_POSITION: arg #{1} - parameter 2 must be vector", rulesParsed, idx - idxStart - 1));
  9266. }
  9267. else
  9268. {
  9269. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_POS_LOCAL: arg #{1} - parameter 2 must be vector", rulesParsed, idx - idxStart - 1));
  9270. }
  9271. return new LSL_List();
  9272. }
  9273. break;
  9274. case ScriptBaseClass.PRIM_ROTATION:
  9275. if (remain < 1)
  9276. return new LSL_List();
  9277. Quaternion inRot;
  9278. try
  9279. {
  9280. inRot = rules.GetQuaternionItem(idx++);
  9281. }
  9282. catch(InvalidCastException)
  9283. {
  9284. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_ROTATION: arg #{1} - parameter 2 must be rotation", rulesParsed, idx - idxStart - 1));
  9285. return new LSL_List();
  9286. }
  9287. SceneObjectPart parentPart = sp.ParentPart;
  9288. if (parentPart != null)
  9289. sp.Rotation = m_host.GetWorldRotation() * inRot;
  9290. break;
  9291. case ScriptBaseClass.PRIM_ROT_LOCAL:
  9292. if (remain < 1)
  9293. return new LSL_List();
  9294. try
  9295. {
  9296. sp.Rotation = rules.GetQuaternionItem(idx++);
  9297. }
  9298. catch(InvalidCastException)
  9299. {
  9300. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_ROT_LOCAL: arg #{1} - parameter 2 must be rotation", rulesParsed, idx - idxStart - 1));
  9301. return new LSL_List();
  9302. }
  9303. break;
  9304. case ScriptBaseClass.PRIM_TYPE:
  9305. Error(originFunc, "PRIM_TYPE disallowed on agent");
  9306. return new LSL_List();
  9307. case ScriptBaseClass.PRIM_OMEGA:
  9308. Error(originFunc, "PRIM_OMEGA disallowed on agent");
  9309. return new LSL_List();
  9310. case ScriptBaseClass.PRIM_LINK_TARGET:
  9311. if (remain < 3) // setting to 3 on the basis that parsing any usage of PRIM_LINK_TARGET that has nothing following it is pointless.
  9312. return new LSL_List();
  9313. return rules.GetSublist(idx, -1);
  9314. default:
  9315. Error(originFunc,
  9316. string.Format("Error running rule #{0} on agent: arg #{1} - disallowed on agent", rulesParsed, idx - idxStart));
  9317. return new LSL_List();
  9318. }
  9319. }
  9320. }
  9321. catch (InvalidCastException e)
  9322. {
  9323. Error(
  9324. originFunc,
  9325. string.Format("Error running rule #{0}: arg #{1} - ", rulesParsed, idx - idxStart) + e.Message);
  9326. }
  9327. return new LSL_List();
  9328. }
  9329. public LSL_String llStringToBase64(string str)
  9330. {
  9331. try
  9332. {
  9333. byte[] encData_byte;
  9334. encData_byte = Util.UTF8.GetBytes(str);
  9335. string encodedData = Convert.ToBase64String(encData_byte);
  9336. return encodedData;
  9337. }
  9338. catch
  9339. {
  9340. Error("llBase64ToString", "Error encoding string");
  9341. return LSL_String.Empty;
  9342. }
  9343. }
  9344. public LSL_String llBase64ToString(string str)
  9345. {
  9346. try
  9347. {
  9348. byte[] b = Convert.FromBase64String(str);
  9349. return Encoding.UTF8.GetString(b);
  9350. }
  9351. catch
  9352. {
  9353. Error("llBase64ToString", "Error decoding string");
  9354. return LSL_String.Empty;
  9355. }
  9356. }
  9357. public void llRemoteDataSetRegion()
  9358. {
  9359. Deprecated("llRemoteDataSetRegion", "Use llOpenRemoteDataChannel instead");
  9360. }
  9361. public LSL_Float llLog10(double val)
  9362. {
  9363. return (double)Math.Log10(val);
  9364. }
  9365. public LSL_Float llLog(double val)
  9366. {
  9367. return (double)Math.Log(val);
  9368. }
  9369. public LSL_List llGetAnimationList(LSL_Key id)
  9370. {
  9371. if(!UUID.TryParse(id, out UUID avID) || avID.IsZero())
  9372. return new LSL_List();
  9373. ScenePresence av = World.GetScenePresence(avID);
  9374. if (av == null || av.IsChildAgent) // only if in the region
  9375. return new LSL_List();
  9376. UUID[] anims = av.Animator.GetAnimationArray();
  9377. LSL_List l = new();
  9378. foreach (UUID foo in anims)
  9379. l.Add(new LSL_Key(foo.ToString()));
  9380. return l;
  9381. }
  9382. public void llSetParcelMusicURL(string url)
  9383. {
  9384. ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
  9385. if (land.LandData.OwnerID != m_host.OwnerID)
  9386. return;
  9387. land.SetMusicUrl(url);
  9388. ScriptSleep(m_sleepMsOnSetParcelMusicURL);
  9389. }
  9390. public LSL_String llGetParcelMusicURL()
  9391. {
  9392. ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
  9393. if (land.LandData.OwnerID != m_host.OwnerID)
  9394. return LSL_String.Empty;
  9395. return land.GetMusicUrl();
  9396. }
  9397. public LSL_Vector llGetRootPosition()
  9398. {
  9399. return new LSL_Vector(m_host.ParentGroup.AbsolutePosition);
  9400. }
  9401. /// <summary>
  9402. /// http://lslwiki.net/lslwiki/wakka.php?wakka=llGetRot
  9403. /// http://lslwiki.net/lslwiki/wakka.php?wakka=ChildRotation
  9404. /// Also tested in sl in regards to the behaviour in attachments/mouselook
  9405. /// In the root prim:-
  9406. /// Returns the object rotation if not attached
  9407. /// Returns the avatars rotation if attached
  9408. /// Returns the camera rotation if attached and the avatar is in mouselook
  9409. /// </summary>
  9410. public LSL_Rotation llGetRootRotation()
  9411. {
  9412. Quaternion q;
  9413. if (m_host.ParentGroup.AttachmentPoint != 0)
  9414. {
  9415. ScenePresence avatar = World.GetScenePresence(m_host.ParentGroup.AttachedAvatar);
  9416. if (avatar != null)
  9417. if ((avatar.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0)
  9418. q = avatar.CameraRotation; // Mouselook
  9419. else
  9420. q = avatar.GetWorldRotation(); // Currently infrequently updated so may be inaccurate
  9421. else
  9422. q = m_host.ParentGroup.GroupRotation; // Likely never get here but just in case
  9423. }
  9424. else
  9425. q = m_host.ParentGroup.GroupRotation; // just the group rotation
  9426. return new LSL_Rotation(q);
  9427. }
  9428. public LSL_String llGetObjectDesc()
  9429. {
  9430. return m_host.Description ?? String.Empty;
  9431. }
  9432. public void llSetObjectDesc(string desc)
  9433. {
  9434. m_host.Description = desc ?? String.Empty;
  9435. }
  9436. public LSL_Key llGetCreator()
  9437. {
  9438. return m_host.CreatorID.ToString();
  9439. }
  9440. public LSL_String llGetTimestamp()
  9441. {
  9442. return DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffffffZ");
  9443. }
  9444. public LSL_Integer llGetNumberOfPrims()
  9445. {
  9446. return m_host.ParentGroup.PrimCount + m_host.ParentGroup.GetSittingAvatarsCount();
  9447. }
  9448. /// <summary>
  9449. /// Full implementation of llGetBoundingBox according to SL 2015-04-15.
  9450. /// http://wiki.secondlife.com/wiki/LlGetBoundingBox
  9451. /// http://lslwiki.net/lslwiki/wakka.php?wakka=llGetBoundingBox
  9452. /// Returns local bounding box of avatar without attachments
  9453. /// if target is non-seated avatar or prim/mesh in avatar attachment.
  9454. /// Returns local bounding box of object
  9455. /// if target is seated avatar or prim/mesh in object.
  9456. /// Uses less accurate box models for speed.
  9457. /// </summary>
  9458. public LSL_List llGetBoundingBox(string obj)
  9459. {
  9460. LSL_List result = new();
  9461. // If the ID is not valid, return null result
  9462. if (!UUID.TryParse(obj, out UUID objID) || objID.IsZero())
  9463. {
  9464. result.Add(new LSL_Vector());
  9465. result.Add(new LSL_Vector());
  9466. return result;
  9467. }
  9468. // Check if this is an attached prim. If so, replace
  9469. // the UUID with the avatar UUID and report it's bounding box
  9470. SceneObjectPart part = World.GetSceneObjectPart(objID);
  9471. if (part != null && part.ParentGroup.IsAttachment)
  9472. objID = part.ParentGroup.AttachedAvatar;
  9473. // Find out if this is an avatar ID. If so, return it's box
  9474. ScenePresence presence = World.GetScenePresence(objID);
  9475. if (presence != null)
  9476. {
  9477. LSL_Vector lower;
  9478. LSL_Vector upper;
  9479. Vector3 box = presence.Appearance.AvatarBoxSize * 0.5f;
  9480. if (presence.Animator.Animations.ImplicitDefaultAnimation.AnimID.Equals(
  9481. DefaultAvatarAnimations.AnimsUUIDbyName["SIT_GROUND_CONSTRAINED"]))
  9482. {
  9483. // This is for ground sitting avatars TODO!
  9484. lower = new LSL_Vector(-box.X - 0.1125, -box.Y, box.Z * -1.0f);
  9485. upper = new LSL_Vector(box.X + 0.1125, box.Y, box.Z * -1.0f);
  9486. }
  9487. else
  9488. {
  9489. // This is for standing/flying avatars
  9490. lower = new LSL_Vector(-box.X, -box.Y, -box.Z);
  9491. upper = new LSL_Vector(box.X, box.Y, box.Z);
  9492. }
  9493. if (lower.x > upper.x)
  9494. lower.x = upper.x;
  9495. if (lower.y > upper.y)
  9496. lower.y = upper.y;
  9497. if (lower.z > upper.z)
  9498. lower.z = upper.z;
  9499. result.Add(lower);
  9500. result.Add(upper);
  9501. return result;
  9502. }
  9503. part = World.GetSceneObjectPart(objID);
  9504. // Currently only works for single prims without a sitting avatar
  9505. if (part == null)
  9506. {
  9507. result.Add(new LSL_Vector());
  9508. result.Add(new LSL_Vector());
  9509. return result;
  9510. }
  9511. SceneObjectGroup sog = part.ParentGroup;
  9512. if(sog.IsDeleted)
  9513. {
  9514. result.Add(new LSL_Vector());
  9515. result.Add(new LSL_Vector());
  9516. return result;
  9517. }
  9518. sog.GetBoundingBox(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ);
  9519. result.Add(new LSL_Vector(minX, minY, minZ));
  9520. result.Add(new LSL_Vector(maxX, maxY, maxZ));
  9521. return result;
  9522. }
  9523. /// <summary>
  9524. /// Helper to calculate bounding box of an avatar.
  9525. /// </summary>
  9526. private void BoundingBoxOfScenePresence(ScenePresence sp, out Vector3 lower, out Vector3 upper)
  9527. {
  9528. // Adjust from OS model
  9529. // avatar height = visual height - 0.2, bounding box height = visual height
  9530. // to SL model
  9531. // avatar height = visual height, bounding box height = visual height + 0.2
  9532. float height = sp.Appearance.AvatarHeight + m_avatarHeightCorrection;
  9533. // According to avatar bounding box in SL 2015-04-18:
  9534. // standing = <-0.275,-0.35,-0.1-0.5*h> : <0.275,0.35,0.1+0.5*h>
  9535. // groundsitting = <-0.3875,-0.5,-0.05-0.375*h> : <0.3875,0.5,0.5>
  9536. // sitting = <-0.5875,-0.35,-0.35-0.375*h> : <0.1875,0.35,-0.25+0.25*h>
  9537. // When avatar is sitting
  9538. if (sp.ParentPart != null)
  9539. {
  9540. lower = new Vector3(m_lABB1SitX0, m_lABB1SitY0, m_lABB1SitZ0 + m_lABB1SitZ1 * height);
  9541. upper = new Vector3(m_lABB2SitX0, m_lABB2SitY0, m_lABB2SitZ0 + m_lABB2SitZ1 * height);
  9542. }
  9543. // When avatar is groundsitting
  9544. else if (sp.Animator.Animations.ImplicitDefaultAnimation.AnimID.Equals(DefaultAvatarAnimations.AnimsUUIDbyName["SIT_GROUND_CONSTRAINED"]))
  9545. {
  9546. lower = new Vector3(m_lABB1GrsX0, m_lABB1GrsY0, m_lABB1GrsZ0 + m_lABB1GrsZ1 * height);
  9547. upper = new Vector3(m_lABB2GrsX0, m_lABB2GrsY0, m_lABB2GrsZ0 + m_lABB2GrsZ1 * height);
  9548. }
  9549. // When avatar is standing or flying
  9550. else
  9551. {
  9552. lower = new Vector3(m_lABB1StdX0, m_lABB1StdY0, m_lABB1StdZ0 + m_lABB1StdZ1 * height);
  9553. upper = new Vector3(m_lABB2StdX0, m_lABB2StdY0, m_lABB2StdZ0 + m_lABB2StdZ1 * height);
  9554. }
  9555. }
  9556. public LSL_Vector llGetGeometricCenter()
  9557. {
  9558. return new LSL_Vector(m_host.GetGeometricCenter());
  9559. }
  9560. public LSL_List llGetPrimitiveParams(LSL_List rules)
  9561. {
  9562. LSL_List result = new();
  9563. LSL_List remaining = GetPrimParams(m_host, rules, ref result);
  9564. while (remaining is not null && remaining.Length > 1)
  9565. {
  9566. int linknumber = remaining.GetIntegerItem(0);
  9567. rules = remaining.GetSublist(1, -1);
  9568. List<SceneObjectPart> parts = GetLinkParts(linknumber);
  9569. if(parts.Count == 0)
  9570. break;
  9571. foreach (SceneObjectPart part in parts)
  9572. remaining = GetPrimParams(part, rules, ref result);
  9573. }
  9574. return result;
  9575. }
  9576. public LSL_List llGetLinkPrimitiveParams(int linknumber, LSL_List rules)
  9577. {
  9578. // according to SL wiki this must indicate a single link number or link_root or link_this.
  9579. // keep other options as before
  9580. List<SceneObjectPart> parts;
  9581. List<ScenePresence> avatars;
  9582. LSL_List res = new();
  9583. LSL_List remaining;
  9584. while (rules.Length > 0)
  9585. {
  9586. parts = GetLinkParts(linknumber);
  9587. avatars = GetLinkAvatars(linknumber);
  9588. remaining = new LSL_List();
  9589. foreach (SceneObjectPart part in parts)
  9590. {
  9591. remaining = GetPrimParams(part, rules, ref res);
  9592. }
  9593. foreach (ScenePresence avatar in avatars)
  9594. {
  9595. remaining = GetPrimParams(avatar, rules, ref res);
  9596. }
  9597. if (remaining.Length > 0)
  9598. {
  9599. linknumber = remaining.GetIntegerItem(0);
  9600. rules = remaining.GetSublist(1, -1);
  9601. }
  9602. else
  9603. break;
  9604. }
  9605. return res;
  9606. }
  9607. public LSL_List GetPrimParams(SceneObjectPart part, LSL_List rules, ref LSL_List res)
  9608. {
  9609. int idx = 0;
  9610. int face;
  9611. Primitive.TextureEntry tex;
  9612. int nsides = GetNumberOfSides(part);
  9613. while (idx < rules.Length)
  9614. {
  9615. int code = rules.GetIntegerItem(idx++);
  9616. int remain = rules.Length - idx;
  9617. switch (code)
  9618. {
  9619. case ScriptBaseClass.PRIM_MATERIAL:
  9620. res.Add(new LSL_Integer(part.Material));
  9621. break;
  9622. case ScriptBaseClass.PRIM_PHYSICS:
  9623. if ((part.GetEffectiveObjectFlags() & (uint)PrimFlags.Physics) != 0)
  9624. res.Add(new LSL_Integer(1));
  9625. else
  9626. res.Add(new LSL_Integer(0));
  9627. break;
  9628. case ScriptBaseClass.PRIM_TEMP_ON_REZ:
  9629. if ((part.GetEffectiveObjectFlags() & (uint)PrimFlags.TemporaryOnRez) != 0)
  9630. res.Add(new LSL_Integer(1));
  9631. else
  9632. res.Add(new LSL_Integer(0));
  9633. break;
  9634. case ScriptBaseClass.PRIM_PHANTOM:
  9635. if ((part.GetEffectiveObjectFlags() & (uint)PrimFlags.Phantom) != 0)
  9636. res.Add(new LSL_Integer(1));
  9637. else
  9638. res.Add(new LSL_Integer(0));
  9639. break;
  9640. case ScriptBaseClass.PRIM_POSITION:
  9641. LSL_Vector v = new(part.AbsolutePosition);
  9642. res.Add(v);
  9643. break;
  9644. case ScriptBaseClass.PRIM_SIZE:
  9645. res.Add(new LSL_Vector(part.Scale));
  9646. break;
  9647. case ScriptBaseClass.PRIM_ROTATION:
  9648. res.Add(GetPartRot(part));
  9649. break;
  9650. case ScriptBaseClass.PRIM_PHYSICS_SHAPE_TYPE:
  9651. res.Add(new LSL_Integer((int)part.PhysicsShapeType));
  9652. break;
  9653. case ScriptBaseClass.PRIM_TYPE:
  9654. // implementing box
  9655. PrimitiveBaseShape Shape = part.Shape;
  9656. int primType = (int)part.GetPrimType();
  9657. res.Add(new LSL_Integer(primType));
  9658. double topshearx = (double)(sbyte)Shape.PathShearX / 100.0; // Fix negative values for PathShearX
  9659. double topsheary = (double)(sbyte)Shape.PathShearY / 100.0; // and PathShearY.
  9660. switch (primType)
  9661. {
  9662. case ScriptBaseClass.PRIM_TYPE_BOX:
  9663. case ScriptBaseClass.PRIM_TYPE_CYLINDER:
  9664. case ScriptBaseClass.PRIM_TYPE_PRISM:
  9665. res.Add(new LSL_Integer(Shape.ProfileCurve) & 0xf0); // Isolate hole shape nibble.
  9666. res.Add(new LSL_Vector(Shape.ProfileBegin / 50000.0, 1 - Shape.ProfileEnd / 50000.0, 0));
  9667. res.Add(new LSL_Float(Shape.ProfileHollow / 50000.0));
  9668. res.Add(new LSL_Vector(Shape.PathTwistBegin / 100.0, Shape.PathTwist / 100.0, 0));
  9669. res.Add(new LSL_Vector(1 - (Shape.PathScaleX / 100.0 - 1), 1 - (Shape.PathScaleY / 100.0 - 1), 0));
  9670. res.Add(new LSL_Vector(topshearx, topsheary, 0));
  9671. break;
  9672. case ScriptBaseClass.PRIM_TYPE_SPHERE:
  9673. res.Add(new LSL_Integer(Shape.ProfileCurve) & 0xf0); // Isolate hole shape nibble.
  9674. res.Add(new LSL_Vector(Shape.PathBegin / 50000.0, 1 - Shape.PathEnd / 50000.0, 0));
  9675. res.Add(new LSL_Float(Shape.ProfileHollow / 50000.0));
  9676. res.Add(new LSL_Vector(Shape.PathTwistBegin / 100.0, Shape.PathTwist / 100.0, 0));
  9677. res.Add(new LSL_Vector(Shape.ProfileBegin / 50000.0, 1 - Shape.ProfileEnd / 50000.0, 0));
  9678. break;
  9679. case ScriptBaseClass.PRIM_TYPE_SCULPT:
  9680. res.Add(new LSL_String(Shape.SculptTexture.ToString()));
  9681. int stype = Shape.SculptType;
  9682. if (Shape.AnimeshEnabled)
  9683. stype |= ScriptBaseClass.PRIM_SCULPT_FLAG_ANIMESH;
  9684. else
  9685. stype &= ~ScriptBaseClass.PRIM_SCULPT_FLAG_ANIMESH;
  9686. res.Add(new LSL_Integer(stype));
  9687. break;
  9688. case ScriptBaseClass.PRIM_TYPE_RING:
  9689. case ScriptBaseClass.PRIM_TYPE_TUBE:
  9690. case ScriptBaseClass.PRIM_TYPE_TORUS:
  9691. // holeshape
  9692. res.Add(new LSL_Integer(Shape.ProfileCurve) & 0xf0); // Isolate hole shape nibble.
  9693. // cut
  9694. res.Add(new LSL_Vector(Shape.PathBegin / 50000.0, 1 - Shape.PathEnd / 50000.0, 0));
  9695. // hollow
  9696. res.Add(new LSL_Float(Shape.ProfileHollow / 50000.0));
  9697. // twist
  9698. res.Add(new LSL_Vector(Shape.PathTwistBegin / 100.0, Shape.PathTwist / 100.0, 0));
  9699. // vector holesize
  9700. res.Add(new LSL_Vector(1 - (Shape.PathScaleX / 100.0 - 1), 1 - (Shape.PathScaleY / 100.0 - 1), 0));
  9701. // vector topshear
  9702. res.Add(new LSL_Vector(topshearx, topsheary, 0));
  9703. // vector profilecut
  9704. res.Add(new LSL_Vector(Shape.ProfileBegin / 50000.0, 1 - Shape.ProfileEnd / 50000.0, 0));
  9705. // vector tapera
  9706. res.Add(new LSL_Vector(Shape.PathTaperX / 100.0, Shape.PathTaperY / 100.0, 0));
  9707. // float revolutions
  9708. res.Add(new LSL_Float(Math.Round(Shape.PathRevolutions * 0.015d, 2, MidpointRounding.AwayFromZero)) + 1.0d);
  9709. // Slightly inaccurate, because an unsigned byte is being used to represent
  9710. // the entire range of floating-point values from 1.0 through 4.0 (which is how
  9711. // SL does it).
  9712. //
  9713. // Using these formulas to store and retrieve PathRevolutions, it is not
  9714. // possible to use all values between 1.00 and 4.00. For instance, you can't
  9715. // represent 1.10. You can represent 1.09 and 1.11, but not 1.10. So, if you
  9716. // use llSetPrimitiveParams to set revolutions to 1.10 and then retreive them
  9717. // with llGetPrimitiveParams, you'll retrieve 1.09. You can also see a similar
  9718. // behavior in the viewer as you cannot set 1.10. The viewer jumps to 1.11.
  9719. // In SL, llSetPrimitveParams and llGetPrimitiveParams can set and get a value
  9720. // such as 1.10. So, SL must store and retreive the actual user input rather
  9721. // than only storing the encoded value.
  9722. // float radiusoffset
  9723. res.Add(new LSL_Float(Shape.PathRadiusOffset / 100.0));
  9724. // float skew
  9725. res.Add(new LSL_Float(Shape.PathSkew / 100.0));
  9726. break;
  9727. }
  9728. break;
  9729. case ScriptBaseClass.PRIM_TEXTURE:
  9730. if (remain < 1)
  9731. return new LSL_List();
  9732. face = rules.GetIntegerItem(idx++);
  9733. tex = part.Shape.Textures;
  9734. if (face == ScriptBaseClass.ALL_SIDES)
  9735. {
  9736. for (face = 0; face < nsides; face++)
  9737. {
  9738. Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
  9739. res.Add(new LSL_String(texface.TextureID.ToString()));
  9740. res.Add(new LSL_Vector(texface.RepeatU,
  9741. texface.RepeatV,
  9742. 0));
  9743. res.Add(new LSL_Vector(texface.OffsetU,
  9744. texface.OffsetV,
  9745. 0));
  9746. res.Add(new LSL_Float(texface.Rotation));
  9747. }
  9748. }
  9749. else
  9750. {
  9751. if (face >= 0 && face < nsides)
  9752. {
  9753. Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
  9754. res.Add(new LSL_String(texface.TextureID.ToString()));
  9755. res.Add(new LSL_Vector(texface.RepeatU,
  9756. texface.RepeatV,
  9757. 0));
  9758. res.Add(new LSL_Vector(texface.OffsetU,
  9759. texface.OffsetV,
  9760. 0));
  9761. res.Add(new LSL_Float(texface.Rotation));
  9762. }
  9763. }
  9764. break;
  9765. case ScriptBaseClass.PRIM_COLOR:
  9766. if (remain < 1)
  9767. return new LSL_List();
  9768. face = rules.GetIntegerItem(idx++);
  9769. tex = part.Shape.Textures;
  9770. Color4 texcolor;
  9771. if (face == ScriptBaseClass.ALL_SIDES)
  9772. {
  9773. for (face = 0; face < nsides; face++)
  9774. {
  9775. texcolor = tex.GetFace((uint)face).RGBA;
  9776. res.Add(new LSL_Vector(texcolor.R,
  9777. texcolor.G,
  9778. texcolor.B));
  9779. res.Add(new LSL_Float(texcolor.A));
  9780. }
  9781. }
  9782. else
  9783. {
  9784. texcolor = tex.GetFace((uint)face).RGBA;
  9785. res.Add(new LSL_Vector(texcolor.R,
  9786. texcolor.G,
  9787. texcolor.B));
  9788. res.Add(new LSL_Float(texcolor.A));
  9789. }
  9790. break;
  9791. case ScriptBaseClass.PRIM_BUMP_SHINY:
  9792. {
  9793. if (remain < 1)
  9794. return new LSL_List();
  9795. face = rules.GetIntegerItem(idx++);
  9796. tex = part.Shape.Textures;
  9797. int shiny;
  9798. if (face == ScriptBaseClass.ALL_SIDES)
  9799. {
  9800. for (face = 0; face < nsides; face++)
  9801. {
  9802. Shininess shinyness = tex.GetFace((uint)face).Shiny;
  9803. if (shinyness == Shininess.High)
  9804. {
  9805. shiny = ScriptBaseClass.PRIM_SHINY_HIGH;
  9806. }
  9807. else if (shinyness == Shininess.Medium)
  9808. {
  9809. shiny = ScriptBaseClass.PRIM_SHINY_MEDIUM;
  9810. }
  9811. else if (shinyness == Shininess.Low)
  9812. {
  9813. shiny = ScriptBaseClass.PRIM_SHINY_LOW;
  9814. }
  9815. else
  9816. {
  9817. shiny = ScriptBaseClass.PRIM_SHINY_NONE;
  9818. }
  9819. res.Add(new LSL_Integer(shiny));
  9820. res.Add(new LSL_Integer((int)tex.GetFace((uint)face).Bump));
  9821. }
  9822. }
  9823. else
  9824. {
  9825. Shininess shinyness = tex.GetFace((uint)face).Shiny;
  9826. if (shinyness == Shininess.High)
  9827. {
  9828. shiny = ScriptBaseClass.PRIM_SHINY_HIGH;
  9829. }
  9830. else if (shinyness == Shininess.Medium)
  9831. {
  9832. shiny = ScriptBaseClass.PRIM_SHINY_MEDIUM;
  9833. }
  9834. else if (shinyness == Shininess.Low)
  9835. {
  9836. shiny = ScriptBaseClass.PRIM_SHINY_LOW;
  9837. }
  9838. else
  9839. {
  9840. shiny = ScriptBaseClass.PRIM_SHINY_NONE;
  9841. }
  9842. res.Add(new LSL_Integer(shiny));
  9843. res.Add(new LSL_Integer((int)tex.GetFace((uint)face).Bump));
  9844. }
  9845. break;
  9846. }
  9847. case ScriptBaseClass.PRIM_FULLBRIGHT:
  9848. {
  9849. if (remain < 1)
  9850. return new LSL_List();
  9851. face = rules.GetIntegerItem(idx++);
  9852. tex = part.Shape.Textures;
  9853. int fullbright;
  9854. if (face == ScriptBaseClass.ALL_SIDES)
  9855. {
  9856. for (face = 0; face < nsides; face++)
  9857. {
  9858. if (tex.GetFace((uint)face).Fullbright == true)
  9859. {
  9860. fullbright = ScriptBaseClass.TRUE;
  9861. }
  9862. else
  9863. {
  9864. fullbright = ScriptBaseClass.FALSE;
  9865. }
  9866. res.Add(new LSL_Integer(fullbright));
  9867. }
  9868. }
  9869. else
  9870. {
  9871. if (tex.GetFace((uint)face).Fullbright == true)
  9872. {
  9873. fullbright = ScriptBaseClass.TRUE;
  9874. }
  9875. else
  9876. {
  9877. fullbright = ScriptBaseClass.FALSE;
  9878. }
  9879. res.Add(new LSL_Integer(fullbright));
  9880. }
  9881. break;
  9882. }
  9883. case ScriptBaseClass.PRIM_FLEXIBLE:
  9884. PrimitiveBaseShape shape = part.Shape;
  9885. // at sl this does not return true state, but if data was set
  9886. if (shape.FlexiEntry)
  9887. // correct check should had been:
  9888. //if (shape.PathCurve == (byte)Extrusion.Flexible)
  9889. res.Add(new LSL_Integer(1)); // active
  9890. else
  9891. res.Add(new LSL_Integer(0));
  9892. res.Add(new LSL_Integer(shape.FlexiSoftness));// softness
  9893. res.Add(new LSL_Float(shape.FlexiGravity)); // gravity
  9894. res.Add(new LSL_Float(shape.FlexiDrag)); // friction
  9895. res.Add(new LSL_Float(shape.FlexiWind)); // wind
  9896. res.Add(new LSL_Float(shape.FlexiTension)); // tension
  9897. res.Add(new LSL_Vector(shape.FlexiForceX, // force
  9898. shape.FlexiForceY,
  9899. shape.FlexiForceZ));
  9900. break;
  9901. case ScriptBaseClass.PRIM_TEXGEN:
  9902. // (PRIM_TEXGEN_DEFAULT, PRIM_TEXGEN_PLANAR)
  9903. if (remain < 1)
  9904. return new LSL_List();
  9905. face = rules.GetIntegerItem(idx++);
  9906. tex = part.Shape.Textures;
  9907. if (face == ScriptBaseClass.ALL_SIDES)
  9908. {
  9909. for (face = 0; face < nsides; face++)
  9910. {
  9911. if (tex.GetFace((uint)face).TexMapType == MappingType.Planar)
  9912. {
  9913. res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TEXGEN_PLANAR));
  9914. }
  9915. else
  9916. {
  9917. res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TEXGEN_DEFAULT));
  9918. }
  9919. }
  9920. }
  9921. else
  9922. {
  9923. if (tex.GetFace((uint)face).TexMapType == MappingType.Planar)
  9924. {
  9925. res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TEXGEN_PLANAR));
  9926. }
  9927. else
  9928. {
  9929. res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TEXGEN_DEFAULT));
  9930. }
  9931. }
  9932. break;
  9933. case ScriptBaseClass.PRIM_POINT_LIGHT:
  9934. shape = part.Shape;
  9935. if (shape.LightEntry)
  9936. res.Add(new LSL_Integer(1)); // active
  9937. else
  9938. res.Add(new LSL_Integer(0));
  9939. res.Add(new LSL_Vector(shape.LightColorR, // color
  9940. shape.LightColorG,
  9941. shape.LightColorB));
  9942. res.Add(new LSL_Float(shape.LightIntensity)); // intensity
  9943. res.Add(new LSL_Float(shape.LightRadius)); // radius
  9944. res.Add(new LSL_Float(shape.LightFalloff)); // falloff
  9945. break;
  9946. case ScriptBaseClass.PRIM_REFLECTION_PROBE:
  9947. shape = part.Shape;
  9948. if (shape.ReflectionProbe is null)
  9949. {
  9950. res.Add(new LSL_Integer(0));
  9951. res.Add(new LSL_Float(0f)); // ambiance
  9952. res.Add(new LSL_Float(0f)); // clip
  9953. res.Add(new LSL_Float(0f)); // flags
  9954. }
  9955. else
  9956. {
  9957. res.Add(new LSL_Integer(1));
  9958. res.Add(new LSL_Float(shape.ReflectionProbe.Ambiance)); // ambiance
  9959. res.Add(new LSL_Float(shape.ReflectionProbe.ClipDistance)); // clip
  9960. res.Add(new LSL_Float(shape.ReflectionProbe.Flags)); // flags
  9961. }
  9962. break;
  9963. case ScriptBaseClass.PRIM_GLOW:
  9964. if (remain < 1)
  9965. return new LSL_List();
  9966. face = rules.GetIntegerItem(idx++);
  9967. tex = part.Shape.Textures;
  9968. float primglow;
  9969. if (face == ScriptBaseClass.ALL_SIDES)
  9970. {
  9971. for (face = 0; face < nsides; face++)
  9972. {
  9973. primglow = tex.GetFace((uint)face).Glow;
  9974. res.Add(new LSL_Float(primglow));
  9975. }
  9976. }
  9977. else
  9978. {
  9979. primglow = tex.GetFace((uint)face).Glow;
  9980. res.Add(new LSL_Float(primglow));
  9981. }
  9982. break;
  9983. case ScriptBaseClass.PRIM_TEXT:
  9984. Color4 textColor = part.GetTextColor();
  9985. res.Add(new LSL_String(part.Text));
  9986. res.Add(new LSL_Vector(textColor.R,
  9987. textColor.G,
  9988. textColor.B));
  9989. res.Add(new LSL_Float(textColor.A));
  9990. break;
  9991. case ScriptBaseClass.PRIM_NAME:
  9992. res.Add(new LSL_String(part.Name));
  9993. break;
  9994. case ScriptBaseClass.PRIM_DESC:
  9995. res.Add(new LSL_String(part.Description));
  9996. break;
  9997. case ScriptBaseClass.PRIM_ROT_LOCAL:
  9998. res.Add(new LSL_Rotation(part.RotationOffset));
  9999. break;
  10000. case ScriptBaseClass.PRIM_POS_LOCAL:
  10001. res.Add(new LSL_Vector(GetPartLocalPos(part)));
  10002. break;
  10003. case ScriptBaseClass.PRIM_SLICE:
  10004. PrimType prim_type = part.GetPrimType();
  10005. bool useProfileBeginEnd = (prim_type == PrimType.SPHERE || prim_type == PrimType.TORUS || prim_type == PrimType.TUBE || prim_type == PrimType.RING);
  10006. res.Add(new LSL_Vector(
  10007. (useProfileBeginEnd ? part.Shape.ProfileBegin : part.Shape.PathBegin) / 50000.0,
  10008. 1 - (useProfileBeginEnd ? part.Shape.ProfileEnd : part.Shape.PathEnd) / 50000.0,
  10009. 0
  10010. ));
  10011. break;
  10012. case ScriptBaseClass.PRIM_OMEGA:
  10013. // this may return values diferent from SL since we don't handle set the same way
  10014. float gain = 1.0f; // we don't use gain and don't store it
  10015. Vector3 axis = part.AngularVelocity;
  10016. float spin = axis.Length();
  10017. if(spin < 1.0e-6)
  10018. {
  10019. axis = Vector3.Zero;
  10020. gain = 0.0f;
  10021. spin = 0.0f;
  10022. }
  10023. else
  10024. {
  10025. axis *= (1.0f/spin);
  10026. }
  10027. res.Add(new LSL_Vector(axis));
  10028. res.Add(new LSL_Float(spin));
  10029. res.Add(new LSL_Float(gain));
  10030. break;
  10031. case ScriptBaseClass.PRIM_SIT_TARGET:
  10032. if(part.IsSitTargetSet)
  10033. {
  10034. res.Add(new LSL_Integer(1));
  10035. res.Add(new LSL_Vector(part.SitTargetPosition));
  10036. res.Add(new LSL_Rotation(part.SitTargetOrientation));
  10037. }
  10038. else
  10039. {
  10040. res.Add(new LSL_Integer(0));
  10041. res.Add(LSL_Vector.Zero);
  10042. res.Add(LSL_Rotation.Identity);
  10043. }
  10044. break;
  10045. case ScriptBaseClass.PRIM_NORMAL:
  10046. case ScriptBaseClass.PRIM_SPECULAR:
  10047. case ScriptBaseClass.PRIM_ALPHA_MODE:
  10048. if (remain < 1)
  10049. return new LSL_List();
  10050. face = rules.GetIntegerItem(idx++);
  10051. tex = part.Shape.Textures;
  10052. if (face == ScriptBaseClass.ALL_SIDES)
  10053. {
  10054. for (face = 0; face < nsides; face++)
  10055. {
  10056. Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
  10057. getLSLFaceMaterial(ref res, code, part, texface);
  10058. }
  10059. }
  10060. else
  10061. {
  10062. if (face >= 0 && face < nsides)
  10063. {
  10064. Primitive.TextureEntryFace texface = tex.GetFace((uint)face);
  10065. getLSLFaceMaterial(ref res, code, part, texface);
  10066. }
  10067. }
  10068. break;
  10069. case ScriptBaseClass.PRIM_LINK_TARGET:
  10070. // TODO: Should be issuing a runtime script warning in this case.
  10071. if (remain < 2)
  10072. return new LSL_List();
  10073. return rules.GetSublist(idx, -1);
  10074. case ScriptBaseClass.PRIM_PROJECTOR:
  10075. if (part.Shape.ProjectionEntry)
  10076. {
  10077. res.Add(new LSL_String(part.Shape.ProjectionTextureUUID.ToString()));
  10078. res.Add(new LSL_Float(part.Shape.ProjectionFOV));
  10079. res.Add(new LSL_Float(part.Shape.ProjectionFocus));
  10080. res.Add(new LSL_Float(part.Shape.ProjectionAmbiance));
  10081. }
  10082. else
  10083. {
  10084. res.Add(new LSL_String(ScriptBaseClass.NULL_KEY));
  10085. res.Add(new LSL_Float(0));
  10086. res.Add(new LSL_Float(0));
  10087. res.Add(new LSL_Float(0));
  10088. }
  10089. break;
  10090. }
  10091. }
  10092. return new LSL_List();
  10093. }
  10094. private string GetMaterialTextureUUIDbyRights(UUID origID, SceneObjectPart part)
  10095. {
  10096. if(World.Permissions.CanEditObject(m_host.ParentGroup.UUID, m_host.ParentGroup.RootPart.OwnerID))
  10097. return origID.ToString();
  10098. lock(part.TaskInventory)
  10099. {
  10100. foreach(KeyValuePair<UUID, TaskInventoryItem> inv in part.TaskInventory)
  10101. {
  10102. if(inv.Value.InvType == (int)InventoryType.Texture && inv.Value.AssetID.Equals(origID))
  10103. return origID.ToString();
  10104. }
  10105. }
  10106. return ScriptBaseClass.NULL_KEY;
  10107. }
  10108. private void getLSLFaceMaterial(ref LSL_List res, int code, SceneObjectPart part, Primitive.TextureEntryFace texface)
  10109. {
  10110. UUID matID = UUID.Zero;
  10111. if(m_materialsModule != null)
  10112. matID = texface.MaterialID;
  10113. if(!matID.IsZero())
  10114. {
  10115. FaceMaterial mat = m_materialsModule.GetMaterial(matID);
  10116. if(mat != null)
  10117. {
  10118. if(code == ScriptBaseClass.PRIM_NORMAL)
  10119. {
  10120. res.Add(new LSL_String(GetMaterialTextureUUIDbyRights(mat.NormalMapID, part)));
  10121. res.Add(new LSL_Vector(mat.NormalRepeatX, mat.NormalRepeatY, 0));
  10122. res.Add(new LSL_Vector(mat.NormalOffsetX, mat.NormalOffsetY, 0));
  10123. res.Add(new LSL_Float(mat.NormalRotation));
  10124. }
  10125. else if(code == ScriptBaseClass.PRIM_SPECULAR)
  10126. {
  10127. const float colorScale = 1.0f / 255f;
  10128. res.Add(new LSL_String(GetMaterialTextureUUIDbyRights(mat.SpecularMapID, part)));
  10129. res.Add(new LSL_Vector(mat.SpecularRepeatX, mat.SpecularRepeatY, 0));
  10130. res.Add(new LSL_Vector(mat.SpecularOffsetX, mat.SpecularOffsetY, 0));
  10131. res.Add(new LSL_Float(mat.SpecularRotation));
  10132. res.Add(new LSL_Vector(mat.SpecularLightColorR * colorScale,
  10133. mat.SpecularLightColorG * colorScale,
  10134. mat.SpecularLightColorB * colorScale));
  10135. res.Add(new LSL_Integer(mat.SpecularLightExponent));
  10136. res.Add(new LSL_Integer(mat.EnvironmentIntensity));
  10137. }
  10138. else if(code == ScriptBaseClass.PRIM_ALPHA_MODE)
  10139. {
  10140. res.Add(new LSL_Integer(mat.DiffuseAlphaMode));
  10141. res.Add(new LSL_Integer(mat.AlphaMaskCutoff));
  10142. }
  10143. return;
  10144. }
  10145. }
  10146. // material not found
  10147. if(code == ScriptBaseClass.PRIM_NORMAL || code == ScriptBaseClass.PRIM_SPECULAR)
  10148. {
  10149. res.Add(new LSL_String(ScriptBaseClass.NULL_KEY));
  10150. res.Add(new LSL_Vector(1.0, 1.0, 0));
  10151. res.Add(new LSL_Vector(0, 0, 0));
  10152. res.Add(new LSL_Float(0));
  10153. if(code == ScriptBaseClass.PRIM_SPECULAR)
  10154. {
  10155. res.Add(new LSL_Vector(1.0, 1.0, 1.0));
  10156. res.Add(new LSL_Integer(51));
  10157. res.Add(new LSL_Integer(0));
  10158. }
  10159. }
  10160. else if(code == ScriptBaseClass.PRIM_ALPHA_MODE)
  10161. {
  10162. res.Add(new LSL_Integer(1));
  10163. res.Add(new LSL_Integer(0));
  10164. }
  10165. }
  10166. public LSL_List llGetPrimMediaParams(int face, LSL_List rules)
  10167. {
  10168. ScriptSleep(m_sleepMsOnGetPrimMediaParams);
  10169. return GetPrimMediaParams(m_host, face, rules);
  10170. }
  10171. public LSL_List llGetLinkMedia(LSL_Integer link, LSL_Integer face, LSL_List rules)
  10172. {
  10173. ScriptSleep(m_sleepMsOnGetLinkMedia);
  10174. if (link == ScriptBaseClass.LINK_ROOT)
  10175. return GetPrimMediaParams(m_host.ParentGroup.RootPart, face, rules);
  10176. else if (link == ScriptBaseClass.LINK_THIS)
  10177. return GetPrimMediaParams(m_host, face, rules);
  10178. else
  10179. {
  10180. SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(link);
  10181. if (null != part)
  10182. return GetPrimMediaParams(part, face, rules);
  10183. }
  10184. return new LSL_List();
  10185. }
  10186. private LSL_List GetPrimMediaParams(SceneObjectPart part, int face, LSL_List rules)
  10187. {
  10188. // LSL Spec http://wiki.secondlife.com/wiki/LlGetPrimMediaParams says to fail silently if face is invalid
  10189. // TODO: Need to correctly handle case where a face has no media (which gives back an empty list).
  10190. // Assuming silently fail means give back an empty list. Ideally, need to check this.
  10191. if (face < 0 || face > part.GetNumberOfSides() - 1)
  10192. return new LSL_List();
  10193. IMoapModule module = m_ScriptEngine.World.RequestModuleInterface<IMoapModule>();
  10194. if (null == module)
  10195. return new LSL_List();
  10196. MediaEntry me = module.GetMediaEntry(part, face);
  10197. // As per http://wiki.secondlife.com/wiki/LlGetPrimMediaParams
  10198. if (null == me)
  10199. return new LSL_List();
  10200. LSL_List res = new();
  10201. for (int i = 0; i < rules.Length; i++)
  10202. {
  10203. int code = rules.GetIntegerItem(i);
  10204. switch (code)
  10205. {
  10206. case ScriptBaseClass.PRIM_MEDIA_ALT_IMAGE_ENABLE:
  10207. // Not implemented
  10208. res.Add(new LSL_Integer(0));
  10209. break;
  10210. case ScriptBaseClass.PRIM_MEDIA_CONTROLS:
  10211. if (me.Controls == MediaControls.Standard)
  10212. res.Add(new LSL_Integer(ScriptBaseClass.PRIM_MEDIA_CONTROLS_STANDARD));
  10213. else
  10214. res.Add(new LSL_Integer(ScriptBaseClass.PRIM_MEDIA_CONTROLS_MINI));
  10215. break;
  10216. case ScriptBaseClass.PRIM_MEDIA_CURRENT_URL:
  10217. res.Add(new LSL_String(me.CurrentURL));
  10218. break;
  10219. case ScriptBaseClass.PRIM_MEDIA_HOME_URL:
  10220. res.Add(new LSL_String(me.HomeURL));
  10221. break;
  10222. case ScriptBaseClass.PRIM_MEDIA_AUTO_LOOP:
  10223. res.Add(me.AutoLoop ? ScriptBaseClass.TRUE : ScriptBaseClass.FALSE);
  10224. break;
  10225. case ScriptBaseClass.PRIM_MEDIA_AUTO_PLAY:
  10226. res.Add(me.AutoPlay ? ScriptBaseClass.TRUE : ScriptBaseClass.FALSE);
  10227. break;
  10228. case ScriptBaseClass.PRIM_MEDIA_AUTO_SCALE:
  10229. res.Add(me.AutoScale ? ScriptBaseClass.TRUE : ScriptBaseClass.FALSE);
  10230. break;
  10231. case ScriptBaseClass.PRIM_MEDIA_AUTO_ZOOM:
  10232. res.Add(me.AutoZoom ? ScriptBaseClass.TRUE : ScriptBaseClass.FALSE);
  10233. break;
  10234. case ScriptBaseClass.PRIM_MEDIA_FIRST_CLICK_INTERACT:
  10235. res.Add(me.InteractOnFirstClick ? ScriptBaseClass.TRUE : ScriptBaseClass.FALSE);
  10236. break;
  10237. case ScriptBaseClass.PRIM_MEDIA_WIDTH_PIXELS:
  10238. res.Add(new LSL_Integer(me.Width));
  10239. break;
  10240. case ScriptBaseClass.PRIM_MEDIA_HEIGHT_PIXELS:
  10241. res.Add(new LSL_Integer(me.Height));
  10242. break;
  10243. case ScriptBaseClass.PRIM_MEDIA_WHITELIST_ENABLE:
  10244. res.Add(me.EnableWhiteList ? ScriptBaseClass.TRUE : ScriptBaseClass.FALSE);
  10245. break;
  10246. case ScriptBaseClass.PRIM_MEDIA_WHITELIST:
  10247. string[] urls = (string[])me.WhiteList.Clone();
  10248. for (int j = 0; j < urls.Length; j++)
  10249. urls[j] = Uri.EscapeDataString(urls[j]);
  10250. res.Add(new LSL_String(string.Join(", ", urls)));
  10251. break;
  10252. case ScriptBaseClass.PRIM_MEDIA_PERMS_INTERACT:
  10253. res.Add(new LSL_Integer((int)me.InteractPermissions));
  10254. break;
  10255. case ScriptBaseClass.PRIM_MEDIA_PERMS_CONTROL:
  10256. res.Add(new LSL_Integer((int)me.ControlPermissions));
  10257. break;
  10258. default: return ScriptBaseClass.LSL_STATUS_MALFORMED_PARAMS;
  10259. }
  10260. }
  10261. return res;
  10262. }
  10263. public LSL_Integer llSetPrimMediaParams(LSL_Integer face, LSL_List rules)
  10264. {
  10265. ScriptSleep(m_sleepMsOnSetPrimMediaParams);
  10266. return SetPrimMediaParams(m_host, face, rules);
  10267. }
  10268. public LSL_Integer llSetLinkMedia(LSL_Integer link, LSL_Integer face, LSL_List rules)
  10269. {
  10270. ScriptSleep(m_sleepMsOnSetLinkMedia);
  10271. if (link == ScriptBaseClass.LINK_ROOT)
  10272. return SetPrimMediaParams(m_host.ParentGroup.RootPart, face, rules);
  10273. else if (link == ScriptBaseClass.LINK_THIS)
  10274. return SetPrimMediaParams(m_host, face, rules);
  10275. else
  10276. {
  10277. SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(link);
  10278. if (null != part)
  10279. return SetPrimMediaParams(part, face, rules);
  10280. }
  10281. return ScriptBaseClass.LSL_STATUS_NOT_FOUND;
  10282. }
  10283. private LSL_Integer SetPrimMediaParams(SceneObjectPart part, LSL_Integer face, LSL_List rules)
  10284. {
  10285. // LSL Spec http://wiki.secondlife.com/wiki/LlSetPrimMediaParams says to fail silently if face is invalid
  10286. // Assuming silently fail means sending back LSL_STATUS_OK. Ideally, need to check this.
  10287. // Don't perform the media check directly
  10288. if (face < 0 || face > part.GetNumberOfSides() - 1)
  10289. return ScriptBaseClass.LSL_STATUS_NOT_FOUND;
  10290. IMoapModule module = m_ScriptEngine.World.RequestModuleInterface<IMoapModule>();
  10291. if (null == module)
  10292. return ScriptBaseClass.LSL_STATUS_NOT_SUPPORTED;
  10293. MediaEntry me = module.GetMediaEntry(part, face);
  10294. if (null == me)
  10295. me = new MediaEntry();
  10296. int i = 0;
  10297. while (i < rules.Length - 1)
  10298. {
  10299. int code = rules.GetIntegerItem(i++);
  10300. switch (code)
  10301. {
  10302. case ScriptBaseClass.PRIM_MEDIA_ALT_IMAGE_ENABLE:
  10303. me.EnableAlterntiveImage = rules.GetIntegerItem(i++) != 0;
  10304. break;
  10305. case ScriptBaseClass.PRIM_MEDIA_CONTROLS:
  10306. int v = rules.GetIntegerItem(i++);
  10307. if (ScriptBaseClass.PRIM_MEDIA_CONTROLS_STANDARD == v)
  10308. me.Controls = MediaControls.Standard;
  10309. else
  10310. me.Controls = MediaControls.Mini;
  10311. break;
  10312. case ScriptBaseClass.PRIM_MEDIA_CURRENT_URL:
  10313. me.CurrentURL = rules.GetStringItem(i++);
  10314. break;
  10315. case ScriptBaseClass.PRIM_MEDIA_HOME_URL:
  10316. me.HomeURL = rules.GetStringItem(i++);
  10317. break;
  10318. case ScriptBaseClass.PRIM_MEDIA_AUTO_LOOP:
  10319. me.AutoLoop = rules.GetIntegerItem(i++) != 0;
  10320. break;
  10321. case ScriptBaseClass.PRIM_MEDIA_AUTO_PLAY:
  10322. me.AutoPlay = rules.GetIntegerItem(i++) != 0;
  10323. break;
  10324. case ScriptBaseClass.PRIM_MEDIA_AUTO_SCALE:
  10325. me.AutoScale = rules.GetIntegerItem(i++) != 0;
  10326. break;
  10327. case ScriptBaseClass.PRIM_MEDIA_AUTO_ZOOM:
  10328. me.AutoZoom = rules.GetIntegerItem(i++) != 0;
  10329. break;
  10330. case ScriptBaseClass.PRIM_MEDIA_FIRST_CLICK_INTERACT:
  10331. me.InteractOnFirstClick = rules.GetIntegerItem(i++) != 0;
  10332. break;
  10333. case ScriptBaseClass.PRIM_MEDIA_WIDTH_PIXELS:
  10334. me.Width = rules.GetIntegerItem(i++);
  10335. break;
  10336. case ScriptBaseClass.PRIM_MEDIA_HEIGHT_PIXELS:
  10337. me.Height = rules.GetIntegerItem(i++);
  10338. break;
  10339. case ScriptBaseClass.PRIM_MEDIA_WHITELIST_ENABLE:
  10340. me.EnableWhiteList = rules.GetIntegerItem(i++) != 0;
  10341. break;
  10342. case ScriptBaseClass.PRIM_MEDIA_WHITELIST:
  10343. string[] rawWhiteListUrls = rules.GetStringItem(i++).Split(new char[] { ',' });
  10344. List<string> whiteListUrls = new();
  10345. Array.ForEach(
  10346. rawWhiteListUrls, delegate(string rawUrl) { whiteListUrls.Add(rawUrl.Trim()); });
  10347. me.WhiteList = whiteListUrls.ToArray();
  10348. break;
  10349. case ScriptBaseClass.PRIM_MEDIA_PERMS_INTERACT:
  10350. me.InteractPermissions = (MediaPermission)(byte)rules.GetIntegerItem(i++);
  10351. break;
  10352. case ScriptBaseClass.PRIM_MEDIA_PERMS_CONTROL:
  10353. me.ControlPermissions = (MediaPermission)(byte)rules.GetIntegerItem(i++);
  10354. break;
  10355. default: return ScriptBaseClass.LSL_STATUS_MALFORMED_PARAMS;
  10356. }
  10357. }
  10358. module.SetMediaEntry(part, face, me);
  10359. return ScriptBaseClass.LSL_STATUS_OK;
  10360. }
  10361. public LSL_Integer llClearPrimMedia(LSL_Integer face)
  10362. {
  10363. ScriptSleep(m_sleepMsOnClearPrimMedia);
  10364. return ClearPrimMedia(m_host, face);
  10365. }
  10366. public LSL_Integer llClearLinkMedia(LSL_Integer link, LSL_Integer face)
  10367. {
  10368. ScriptSleep(m_sleepMsOnClearLinkMedia);
  10369. if (link == ScriptBaseClass.LINK_ROOT)
  10370. return ClearPrimMedia(m_host.ParentGroup.RootPart, face);
  10371. else if (link == ScriptBaseClass.LINK_THIS)
  10372. return ClearPrimMedia(m_host, face);
  10373. else
  10374. {
  10375. SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(link);
  10376. if (null != part)
  10377. return ClearPrimMedia(part, face);
  10378. }
  10379. return ScriptBaseClass.LSL_STATUS_NOT_FOUND;
  10380. }
  10381. private LSL_Integer ClearPrimMedia(SceneObjectPart part, LSL_Integer face)
  10382. {
  10383. // LSL Spec http://wiki.secondlife.com/wiki/LlClearPrimMedia says to fail silently if face is invalid
  10384. // Assuming silently fail means sending back LSL_STATUS_OK. Ideally, need to check this.
  10385. // FIXME: Don't perform the media check directly
  10386. if (face < 0 || face > part.GetNumberOfSides() - 1)
  10387. return ScriptBaseClass.LSL_STATUS_NOT_FOUND;
  10388. IMoapModule module = m_ScriptEngine.World.RequestModuleInterface<IMoapModule>();
  10389. if (null == module)
  10390. return ScriptBaseClass.LSL_STATUS_NOT_SUPPORTED;
  10391. module.ClearMediaEntry(part, face);
  10392. return ScriptBaseClass.LSL_STATUS_OK;
  10393. }
  10394. // <remarks>
  10395. // <para>
  10396. // The .NET definition of base 64 is:
  10397. // <list>
  10398. // <item>
  10399. // Significant: A-Z a-z 0-9 + -
  10400. // </item>
  10401. // <item>
  10402. // Whitespace: \t \n \r ' '
  10403. // </item>
  10404. // <item>
  10405. // Valueless: =
  10406. // </item>
  10407. // <item>
  10408. // End-of-string: \0 or '=='
  10409. // </item>
  10410. // </list>
  10411. // </para>
  10412. // <para>
  10413. // Each point in a base-64 string represents
  10414. // a 6 bit value. A 32-bit integer can be
  10415. // represented using 6 characters (with some
  10416. // redundancy).
  10417. // </para>
  10418. // <para>
  10419. // LSL also uses '/'
  10420. // rather than '-' (MIME compliant).
  10421. // </para>
  10422. // <para>
  10423. // RFC 1341 used as a reference (as specified
  10424. // by the SecondLife Wiki).
  10425. // </para>
  10426. // <para>
  10427. // SL do not record any kind of exception for
  10428. // these functions, so the string to integer
  10429. // conversion returns '0' if an invalid
  10430. // character is encountered during conversion.
  10431. // </para>
  10432. // <para>
  10433. // References
  10434. // <list>
  10435. // <item>
  10436. // http://lslwiki.net/lslwiki/wakka.php?wakka=Base64
  10437. // </item>
  10438. // <item>
  10439. // </item>
  10440. // </list>
  10441. // </para>
  10442. // </remarks>
  10443. // <summary>
  10444. // Table for converting 6-bit integers into
  10445. // base-64 characters
  10446. // </summary>
  10447. protected static readonly char[] i2ctable =
  10448. {
  10449. 'A','B','C','D','E','F','G','H',
  10450. 'I','J','K','L','M','N','O','P',
  10451. 'Q','R','S','T','U','V','W','X',
  10452. 'Y','Z',
  10453. 'a','b','c','d','e','f','g','h',
  10454. 'i','j','k','l','m','n','o','p',
  10455. 'q','r','s','t','u','v','w','x',
  10456. 'y','z',
  10457. '0','1','2','3','4','5','6','7',
  10458. '8','9',
  10459. '+','/'
  10460. };
  10461. // <summary>
  10462. // Table for converting base-64 characters
  10463. // into 6-bit integers.
  10464. // </summary>
  10465. protected static readonly int[] c2itable =
  10466. {
  10467. -1,-1,-1,-1,-1,-1,-1,-1, // 0x
  10468. -1,-1,-1,-1,-1,-1,-1,-1,
  10469. -1,-1,-1,-1,-1,-1,-1,-1, // 1x
  10470. -1,-1,-1,-1,-1,-1,-1,-1,
  10471. -1,-1,-1,-1,-1,-1,-1,-1, // 2x
  10472. -1,-1,-1,63,-1,-1,-1,64,
  10473. 53,54,55,56,57,58,59,60, // 3x
  10474. 61,62,-1,-1,-1,0,-1,-1,
  10475. -1,1,2,3,4,5,6,7, // 4x
  10476. 8,9,10,11,12,13,14,15,
  10477. 16,17,18,19,20,21,22,23, // 5x
  10478. 24,25,26,-1,-1,-1,-1,-1,
  10479. -1,27,28,29,30,31,32,33, // 6x
  10480. 34,35,36,37,38,39,40,41,
  10481. 42,43,44,45,46,47,48,49, // 7x
  10482. 50,51,52,-1,-1,-1,-1,-1,
  10483. -1,-1,-1,-1,-1,-1,-1,-1, // 8x
  10484. -1,-1,-1,-1,-1,-1,-1,-1,
  10485. -1,-1,-1,-1,-1,-1,-1,-1, // 9x
  10486. -1,-1,-1,-1,-1,-1,-1,-1,
  10487. -1,-1,-1,-1,-1,-1,-1,-1, // Ax
  10488. -1,-1,-1,-1,-1,-1,-1,-1,
  10489. -1,-1,-1,-1,-1,-1,-1,-1, // Bx
  10490. -1,-1,-1,-1,-1,-1,-1,-1,
  10491. -1,-1,-1,-1,-1,-1,-1,-1, // Cx
  10492. -1,-1,-1,-1,-1,-1,-1,-1,
  10493. -1,-1,-1,-1,-1,-1,-1,-1, // Dx
  10494. -1,-1,-1,-1,-1,-1,-1,-1,
  10495. -1,-1,-1,-1,-1,-1,-1,-1, // Ex
  10496. -1,-1,-1,-1,-1,-1,-1,-1,
  10497. -1,-1,-1,-1,-1,-1,-1,-1, // Fx
  10498. -1,-1,-1,-1,-1,-1,-1,-1
  10499. };
  10500. // <summary>
  10501. // Converts a 32-bit integer into a Base64
  10502. // character string. Base64 character strings
  10503. // are always 8 characters long. All iinteger
  10504. // values are acceptable.
  10505. // </summary>
  10506. // <param name="number">
  10507. // 32-bit integer to be converted.
  10508. // </param>
  10509. // <returns>
  10510. // 8 character string. The 1st six characters
  10511. // contain the encoded number, the last two
  10512. // characters are padded with "=".
  10513. // </returns>
  10514. public LSL_String llIntegerToBase64(int number)
  10515. {
  10516. // uninitialized string
  10517. char[] imdt = new char[8];
  10518. // Manually unroll the loop
  10519. imdt[7] = '=';
  10520. imdt[6] = '=';
  10521. imdt[5] = i2ctable[number<<4 & 0x3F];
  10522. imdt[4] = i2ctable[number>>2 & 0x3F];
  10523. imdt[3] = i2ctable[number>>8 & 0x3F];
  10524. imdt[2] = i2ctable[number>>14 & 0x3F];
  10525. imdt[1] = i2ctable[number>>20 & 0x3F];
  10526. imdt[0] = i2ctable[number>>26 & 0x3F];
  10527. return new string(imdt);
  10528. }
  10529. // <summary>
  10530. // Converts an eight character base-64 string
  10531. // into a 32-bit integer.
  10532. // </summary>
  10533. // <param name="str">
  10534. // 8 characters string to be converted. Other
  10535. // length strings return zero.
  10536. // </param>
  10537. // <returns>
  10538. // Returns an integer representing the
  10539. // encoded value providedint he 1st 6
  10540. // characters of the string.
  10541. // </returns>
  10542. // <remarks>
  10543. // This is coded to behave like LSL's
  10544. // implementation (I think), based upon the
  10545. // information available at the Wiki.
  10546. // If more than 8 characters are supplied,
  10547. // zero is returned.
  10548. // If a NULL string is supplied, zero will
  10549. // be returned.
  10550. // If fewer than 6 characters are supplied, then
  10551. // the answer will reflect a partial
  10552. // accumulation of full bytes
  10553. // <para>
  10554. // The 6-bit segments are
  10555. // extracted left-to-right in big-endian mode,
  10556. // which means that segment 6 only contains the
  10557. // two low-order bits of the 32 bit integer as
  10558. // its high order 2 bits. A short string therefore
  10559. // means loss of low-order information. E.g.
  10560. //
  10561. // |<---------------------- 32-bit integer ----------------------->|<-Pad->|
  10562. // |<--Byte 0----->|<--Byte 1----->|<--Byte 2----->|<--Byte 3----->|<-Pad->|
  10563. // |3|3|2|2|2|2|2|2|2|2|2|2|1|1|1|1|1|1|1|1|1|1| | | | | | | | | | |P|P|P|P|
  10564. // |1|0|9|8|7|6|5|4|3|2|1|0|9|8|7|6|5|4|3|2|1|0|9|8|7|6|5|4|3|2|1|0|P|P|P|P|
  10565. // | str[0] | str[1] | str[2] | str[3] | str[4] | str[6] |
  10566. //
  10567. // </para>
  10568. // </remarks>
  10569. public LSL_Integer llBase64ToInteger(string str)
  10570. {
  10571. if (str is null || str.Length < 2 || str.Length > 8)
  10572. return 0;
  10573. int digit;
  10574. if ((digit = c2itable[str[0]]) <= 0)
  10575. return 0;
  10576. int number = --digit << 26;
  10577. if ((digit = c2itable[str[1]]) <= 0)
  10578. return 0;
  10579. if (str.Length == 2)
  10580. return number | (--digit & 0x30) << 20;
  10581. int next = --digit << 20;
  10582. if ((digit = c2itable[str[2]]) <= 0)
  10583. return number;
  10584. number |= next;
  10585. if (str.Length == 3)
  10586. return number | (--digit & 0x3C) << 14;
  10587. next = --digit << 14;
  10588. if ((digit = c2itable[str[3]]) <= 0)
  10589. return number;
  10590. number |= next;
  10591. number |= --digit << 8;
  10592. if (str.Length == 4)
  10593. return number;
  10594. if ((digit = c2itable[str[4]]) <= 0)
  10595. return number;
  10596. if (str.Length == 5)
  10597. return number;
  10598. next = --digit << 2;
  10599. if ((digit = c2itable[str[5]]) <= 0)
  10600. return number;
  10601. number |= next;
  10602. number |= --digit >> 4;
  10603. return number;
  10604. }
  10605. public LSL_Float llGetGMTclock()
  10606. {
  10607. return DateTime.UtcNow.TimeOfDay.TotalSeconds;
  10608. }
  10609. public LSL_String llGetHTTPHeader(LSL_Key request_id, string header)
  10610. {
  10611. if (m_UrlModule != null)
  10612. return m_UrlModule.GetHttpHeader(new UUID(request_id), header);
  10613. return LSL_String.Empty;
  10614. }
  10615. public LSL_String llGetSimulatorHostname()
  10616. {
  10617. IUrlModule UrlModule = World.RequestModuleInterface<IUrlModule>();
  10618. return UrlModule.ExternalHostNameForLSL;
  10619. }
  10620. // <summary>
  10621. // Scan the string supplied in 'src' and
  10622. // tokenize it based upon two sets of
  10623. // tokenizers provided in two lists,
  10624. // separators and spacers.
  10625. // </summary>
  10626. //
  10627. // <remarks>
  10628. // Separators demarcate tokens and are
  10629. // elided as they are encountered. Spacers
  10630. // also demarcate tokens, but are themselves
  10631. // retained as tokens.
  10632. //
  10633. // Both separators and spacers may be arbitrarily
  10634. // long strings. i.e. ":::".
  10635. //
  10636. // The function returns an ordered list
  10637. // representing the tokens found in the supplied
  10638. // sources string. If two successive tokenizers
  10639. // are encountered, then a null-string entry is
  10640. // added to the list.
  10641. //
  10642. // It is a precondition that the source and
  10643. // toekizer lisst are non-null. If they are null,
  10644. // then a null pointer exception will be thrown
  10645. // while their lengths are being determined.
  10646. //
  10647. // A small amount of working memoryis required
  10648. // of approximately 8*#tokenizers + 8*srcstrlen.
  10649. //
  10650. // There are many ways in which this function
  10651. // can be implemented, this implementation is
  10652. // fairly naive and assumes that when the
  10653. // function is invooked with a short source
  10654. // string and/or short lists of tokenizers, then
  10655. // performance will not be an issue.
  10656. //
  10657. // In order to minimize the perofrmance
  10658. // effects of long strings, or large numbers
  10659. // of tokeizers, the function skips as far as
  10660. // possible whenever a toekenizer is found,
  10661. // and eliminates redundant tokenizers as soon
  10662. // as is possible.
  10663. //
  10664. // The implementation tries to minimize temporary
  10665. // garbage generation.
  10666. // </remarks>
  10667. public LSL_List llParseStringKeepNulls(string src, LSL_List separators, LSL_List spacers)
  10668. {
  10669. return ParseString2List(src, separators, spacers, true);
  10670. }
  10671. private static LSL_List ParseString2List(string src, LSL_List separators, LSL_List spacers, bool keepNulls)
  10672. {
  10673. int srclen = src.Length;
  10674. int seplen = separators.Length;
  10675. object[] separray = separators.Data;
  10676. int spclen = spacers.Length;
  10677. object[] spcarray = spacers.Data;
  10678. int dellen = 0;
  10679. string[] delarray = new string[seplen+spclen];
  10680. int outlen = 0;
  10681. string[] outarray = new string[srclen*2+1];
  10682. int i, j;
  10683. string d;
  10684. /*
  10685. * Convert separator and spacer lists to C# strings.
  10686. * Also filter out null strings so we don't hang.
  10687. */
  10688. for (i = 0; i < seplen; i ++)
  10689. {
  10690. d = separray[i].ToString();
  10691. if (d.Length > 0)
  10692. {
  10693. delarray[dellen++] = d;
  10694. }
  10695. }
  10696. seplen = dellen;
  10697. for (i = 0; i < spclen; i ++)
  10698. {
  10699. d = spcarray[i].ToString();
  10700. if (d.Length > 0)
  10701. {
  10702. delarray[dellen++] = d;
  10703. }
  10704. }
  10705. /*
  10706. * Scan through source string from beginning to end.
  10707. */
  10708. for (i = 0;;)
  10709. {
  10710. /*
  10711. * Find earliest delimeter in src starting at i (if any).
  10712. */
  10713. int earliestDel = -1;
  10714. int earliestSrc = srclen;
  10715. string earliestStr = null;
  10716. for (j = 0; j < dellen; j ++)
  10717. {
  10718. d = delarray[j];
  10719. if (d != null)
  10720. {
  10721. int index = src.IndexOf(d, i, StringComparison.Ordinal);
  10722. if (index < 0)
  10723. {
  10724. delarray[j] = null; // delim nowhere in src, don't check it anymore
  10725. }
  10726. else if (index < earliestSrc)
  10727. {
  10728. earliestSrc = index; // where delimeter starts in source string
  10729. earliestDel = j; // where delimeter is in delarray[]
  10730. earliestStr = d; // the delimeter string from delarray[]
  10731. if (index == i) break; // can't do any better than found at beg of string
  10732. }
  10733. }
  10734. }
  10735. /*
  10736. * Output source string starting at i through start of earliest delimeter.
  10737. */
  10738. if (keepNulls || (earliestSrc > i))
  10739. {
  10740. outarray[outlen++] = src[i..earliestSrc];
  10741. }
  10742. /*
  10743. * If no delimeter found at or after i, we're done scanning.
  10744. */
  10745. if (earliestDel < 0) break;
  10746. /*
  10747. * If delimeter was a spacer, output the spacer.
  10748. */
  10749. if (earliestDel >= seplen)
  10750. {
  10751. outarray[outlen++] = earliestStr;
  10752. }
  10753. /*
  10754. * Look at rest of src string following delimeter.
  10755. */
  10756. i = earliestSrc + earliestStr.Length;
  10757. }
  10758. /*
  10759. * Make up an exact-sized output array suitable for an LSL_List object.
  10760. */
  10761. object[] outlist = new object[outlen];
  10762. for (i = 0; i < outlen; i ++)
  10763. {
  10764. outlist[i] = new LSL_String(outarray[i]);
  10765. }
  10766. return new LSL_List(outlist);
  10767. }
  10768. private const uint fullperms = (uint)PermissionMask.All; // no export for now
  10769. private static int PermissionMaskToLSLPerm(uint value)
  10770. {
  10771. value &= fullperms;
  10772. if (value == fullperms)
  10773. return ScriptBaseClass.PERM_ALL;
  10774. if( value == 0)
  10775. return 0;
  10776. int ret = 0;
  10777. if ((value & (uint)PermissionMask.Copy) != 0)
  10778. ret |= ScriptBaseClass.PERM_COPY;
  10779. if ((value & (uint)PermissionMask.Modify) != 0)
  10780. ret |= ScriptBaseClass.PERM_MODIFY;
  10781. if ((value & (uint)PermissionMask.Move) != 0)
  10782. ret |= ScriptBaseClass.PERM_MOVE;
  10783. if ((value & (uint)PermissionMask.Transfer) != 0)
  10784. ret |= ScriptBaseClass.PERM_TRANSFER;
  10785. return ret;
  10786. }
  10787. private static uint LSLPermToPermissionMask(int lslperm, uint oldvalue)
  10788. {
  10789. lslperm &= ScriptBaseClass.PERM_ALL;
  10790. if (lslperm == ScriptBaseClass.PERM_ALL)
  10791. return oldvalue |= fullperms;
  10792. oldvalue &= ~fullperms;
  10793. if(lslperm != 0)
  10794. {
  10795. if ((lslperm & ScriptBaseClass.PERM_COPY) != 0)
  10796. oldvalue |= (uint)PermissionMask.Copy;
  10797. if ((lslperm & ScriptBaseClass.PERM_MODIFY) != 0)
  10798. oldvalue |= (uint)PermissionMask.Modify;
  10799. if ((lslperm & ScriptBaseClass.PERM_MOVE) != 0)
  10800. oldvalue |= (uint)PermissionMask.Move;
  10801. if ((lslperm & ScriptBaseClass.PERM_TRANSFER) != 0)
  10802. oldvalue |= (uint)PermissionMask.Transfer;
  10803. }
  10804. return oldvalue;
  10805. }
  10806. private static int fixedCopyTransfer(int value)
  10807. {
  10808. if ((value & (ScriptBaseClass.PERM_COPY | ScriptBaseClass.PERM_TRANSFER)) == 0)
  10809. value |= ScriptBaseClass.PERM_TRANSFER;
  10810. return value;
  10811. }
  10812. public LSL_Integer llGetObjectPermMask(int mask)
  10813. {
  10814. return mask switch
  10815. {
  10816. ScriptBaseClass.MASK_BASE => (LSL_Integer)PermissionMaskToLSLPerm(m_host.BaseMask),
  10817. ScriptBaseClass.MASK_OWNER => (LSL_Integer)PermissionMaskToLSLPerm(m_host.OwnerMask),
  10818. ScriptBaseClass.MASK_GROUP => (LSL_Integer)PermissionMaskToLSLPerm(m_host.GroupMask),
  10819. ScriptBaseClass.MASK_EVERYONE => (LSL_Integer)PermissionMaskToLSLPerm(m_host.EveryoneMask),
  10820. ScriptBaseClass.MASK_NEXT => (LSL_Integer)PermissionMaskToLSLPerm(m_host.NextOwnerMask),
  10821. _ => (LSL_Integer)(-1),
  10822. };
  10823. }
  10824. public void llSetObjectPermMask(int mask, int value)
  10825. {
  10826. if (!m_AllowGodFunctions || !World.Permissions.IsAdministrator(m_host.OwnerID))
  10827. return;
  10828. // not even admins have right to violate basic rules
  10829. if (mask != ScriptBaseClass.MASK_BASE)
  10830. {
  10831. mask &= PermissionMaskToLSLPerm(m_host.BaseMask);
  10832. if (mask != ScriptBaseClass.MASK_OWNER)
  10833. mask &= PermissionMaskToLSLPerm(m_host.OwnerMask);
  10834. }
  10835. switch (mask)
  10836. {
  10837. case ScriptBaseClass.MASK_BASE:
  10838. value = fixedCopyTransfer(value);
  10839. m_host.BaseMask = LSLPermToPermissionMask(value, m_host.BaseMask);
  10840. break;
  10841. case ScriptBaseClass.MASK_OWNER:
  10842. value = fixedCopyTransfer(value);
  10843. m_host.OwnerMask = LSLPermToPermissionMask(value, m_host.OwnerMask);
  10844. break;
  10845. case ScriptBaseClass.MASK_GROUP:
  10846. m_host.GroupMask = LSLPermToPermissionMask(value, m_host.GroupMask);
  10847. break;
  10848. case ScriptBaseClass.MASK_EVERYONE:
  10849. m_host.EveryoneMask = LSLPermToPermissionMask(value, m_host.EveryoneMask);
  10850. break;
  10851. case ScriptBaseClass.MASK_NEXT:
  10852. value = fixedCopyTransfer(value);
  10853. m_host.NextOwnerMask = LSLPermToPermissionMask(value, m_host.NextOwnerMask);
  10854. break;
  10855. default:
  10856. return;
  10857. }
  10858. m_host.ParentGroup.AggregatePerms();
  10859. }
  10860. public LSL_Integer llGetInventoryPermMask(string itemName, int mask)
  10861. {
  10862. TaskInventoryItem item = m_host.Inventory.GetInventoryItem(itemName);
  10863. if (item is null)
  10864. return -1;
  10865. return mask switch
  10866. {
  10867. ScriptBaseClass.MASK_BASE => (LSL_Integer)PermissionMaskToLSLPerm(item.BasePermissions),
  10868. ScriptBaseClass.MASK_OWNER => (LSL_Integer)PermissionMaskToLSLPerm(item.CurrentPermissions),
  10869. ScriptBaseClass.MASK_GROUP => (LSL_Integer)PermissionMaskToLSLPerm(item.GroupPermissions),
  10870. ScriptBaseClass.MASK_EVERYONE => (LSL_Integer)PermissionMaskToLSLPerm(item.EveryonePermissions),
  10871. ScriptBaseClass.MASK_NEXT => (LSL_Integer)PermissionMaskToLSLPerm(item.NextPermissions),
  10872. _ => (LSL_Integer)(-1),
  10873. };
  10874. }
  10875. public void llSetInventoryPermMask(string itemName, int mask, int value)
  10876. {
  10877. if(!m_AllowGodFunctions || !World.Permissions.IsAdministrator(m_host.OwnerID))
  10878. return;
  10879. TaskInventoryItem item = m_host.Inventory.GetInventoryItem(itemName);
  10880. if (item is not null)
  10881. {
  10882. if (mask != ScriptBaseClass.MASK_BASE)
  10883. {
  10884. mask &= PermissionMaskToLSLPerm(item.BasePermissions);
  10885. if (mask != ScriptBaseClass.MASK_OWNER)
  10886. mask &= PermissionMaskToLSLPerm(item.CurrentPermissions);
  10887. }
  10888. /*
  10889. if(item.Type == (int)(AssetType.Settings))
  10890. value |= ScriptBaseClass.PERM_COPY;
  10891. */
  10892. switch (mask)
  10893. {
  10894. case ScriptBaseClass.MASK_BASE:
  10895. value = fixedCopyTransfer(value);
  10896. item.BasePermissions = LSLPermToPermissionMask(value, item.BasePermissions);
  10897. break;
  10898. case ScriptBaseClass.MASK_OWNER:
  10899. value = fixedCopyTransfer(value);
  10900. item.CurrentPermissions = LSLPermToPermissionMask(value, item.CurrentPermissions);
  10901. break;
  10902. case ScriptBaseClass.MASK_GROUP:
  10903. item.GroupPermissions = LSLPermToPermissionMask(value, item.GroupPermissions);
  10904. break;
  10905. case ScriptBaseClass.MASK_EVERYONE:
  10906. item.EveryonePermissions = LSLPermToPermissionMask(value, item.EveryonePermissions);
  10907. break;
  10908. case ScriptBaseClass.MASK_NEXT:
  10909. value = fixedCopyTransfer(value);
  10910. item.NextPermissions = LSLPermToPermissionMask(value, item.NextPermissions);
  10911. break;
  10912. default:
  10913. return;
  10914. }
  10915. m_host.ParentGroup.InvalidateDeepEffectivePerms();
  10916. m_host.ParentGroup.AggregatePerms();
  10917. }
  10918. }
  10919. public LSL_Key llGetInventoryCreator(string itemName)
  10920. {
  10921. TaskInventoryItem item = m_host.Inventory.GetInventoryItem(itemName);
  10922. if (item is null)
  10923. {
  10924. Error("llGetInventoryCreator", $"Can't find item '{itemName}'");
  10925. return String.Empty;
  10926. }
  10927. return item.CreatorID.ToString();
  10928. }
  10929. public LSL_String llGetInventoryAcquireTime(string itemName)
  10930. {
  10931. TaskInventoryItem item = m_host.Inventory.GetInventoryItem(itemName);
  10932. if (item is null)
  10933. {
  10934. Error("llGetInventoryAcquireTime", $"Can't find item '{itemName}'");
  10935. return LSL_String.Empty;
  10936. }
  10937. DateTime date = Util.ToDateTime(item.CreationDate);
  10938. return date.ToString("yyyy-MM-ddTHH:mm:ssZ");
  10939. }
  10940. public void llOwnerSay(string msg)
  10941. {
  10942. if(m_host.OwnerID.Equals(m_host.GroupID))
  10943. return;
  10944. World.SimChatBroadcast(msg, ChatTypeEnum.Owner, 0,
  10945. m_host.AbsolutePosition, m_host.Name, m_host.UUID, false);
  10946. }
  10947. public LSL_Key llRequestSecureURL()
  10948. {
  10949. if (m_UrlModule != null)
  10950. return m_UrlModule.RequestSecureURL(m_ScriptEngine.ScriptModule, m_host, m_item.ItemID, null).ToString();
  10951. return ScriptBaseClass.NULL_KEY;
  10952. }
  10953. public LSL_Key llRequestSimulatorData(string simulator, int data)
  10954. {
  10955. try
  10956. {
  10957. if (m_regionName.Equals(simulator))
  10958. {
  10959. string lreply = String.Empty;
  10960. RegionInfo rinfo = World.RegionInfo;
  10961. switch (data)
  10962. {
  10963. case ScriptBaseClass.DATA_SIM_POS:
  10964. lreply = new LSL_Vector(
  10965. rinfo.RegionLocX,
  10966. rinfo.RegionLocY,
  10967. 0).ToString();
  10968. break;
  10969. case ScriptBaseClass.DATA_SIM_STATUS:
  10970. lreply = "up"; // Duh!
  10971. break;
  10972. case ScriptBaseClass.DATA_SIM_RATING:
  10973. lreply = rinfo.RegionSettings.Maturity switch
  10974. {
  10975. 0 => "PG",
  10976. 1 => "MATURE",
  10977. 2 => "ADULT",
  10978. _ => "UNKNOWN",
  10979. };
  10980. break;
  10981. case ScriptBaseClass.DATA_SIM_RELEASE:
  10982. lreply = "OpenSim";
  10983. break;
  10984. default:
  10985. ScriptSleep(m_sleepMsOnRequestSimulatorData);
  10986. return ScriptBaseClass.NULL_KEY; // Raise no event
  10987. }
  10988. string ltid = m_AsyncCommands.DataserverPlugin.RequestWithImediatePost(m_host.LocalId,
  10989. m_item.ItemID, lreply);
  10990. ScriptSleep(m_sleepMsOnRequestSimulatorData);
  10991. return ltid;
  10992. }
  10993. void act(string eventID)
  10994. {
  10995. GridRegion info = World.GridService.GetRegionByName(RegionScopeID, simulator);
  10996. string reply = "unknown";
  10997. if (info is not null)
  10998. {
  10999. switch (data)
  11000. {
  11001. case ScriptBaseClass.DATA_SIM_POS:
  11002. // Hypergrid is currently placing real destination region co-ords into RegionSecret.
  11003. // But other code can also use this field for a genuine RegionSecret! Therefore, if
  11004. // anything is present we need to disambiguate.
  11005. //
  11006. // FIXME: Hypergrid should be storing this data in a different field.
  11007. RegionFlags regionFlags = (RegionFlags)m_ScriptEngine.World.GridService.GetRegionFlags(
  11008. info.ScopeID, info.RegionID);
  11009. if ((regionFlags & RegionFlags.Hyperlink) != 0)
  11010. {
  11011. Utils.LongToUInts(Convert.ToUInt64(info.RegionSecret), out uint rx, out uint ry);
  11012. reply = new LSL_Vector(rx, ry, 0).ToString();
  11013. }
  11014. else
  11015. {
  11016. // Local grid co-oridnates
  11017. reply = new LSL_Vector(info.RegionLocX, info.RegionLocY, 0).ToString();
  11018. }
  11019. break;
  11020. case ScriptBaseClass.DATA_SIM_STATUS:
  11021. reply = "up"; // Duh!
  11022. break;
  11023. case ScriptBaseClass.DATA_SIM_RATING:
  11024. reply = info.Maturity switch
  11025. {
  11026. 0 => "PG",
  11027. 1 => "MATURE",
  11028. 2 => "ADULT",
  11029. _ => "UNKNOWN",
  11030. };
  11031. break;
  11032. case ScriptBaseClass.DATA_SIM_RELEASE:
  11033. reply = "OpenSim";
  11034. break;
  11035. default:
  11036. break;
  11037. }
  11038. }
  11039. m_AsyncCommands.DataserverPlugin.DataserverReply(eventID, reply);
  11040. }
  11041. UUID tid = m_AsyncCommands.DataserverPlugin.RegisterRequest(
  11042. m_host.LocalId, m_item.ItemID, act);
  11043. ScriptSleep(m_sleepMsOnRequestSimulatorData);
  11044. return tid.ToString();
  11045. }
  11046. catch(Exception)
  11047. {
  11048. //m_log.Error("[LSL_API]: llRequestSimulatorData" + e.ToString());
  11049. return ScriptBaseClass.NULL_KEY;
  11050. }
  11051. }
  11052. public LSL_Key llRequestURL()
  11053. {
  11054. if (m_UrlModule != null)
  11055. return m_UrlModule.RequestURL(m_ScriptEngine.ScriptModule, m_host, m_item.ItemID, null).ToString();
  11056. return ScriptBaseClass.NULL_KEY;
  11057. }
  11058. public void llForceMouselook(int mouselook)
  11059. {
  11060. m_host.SetForceMouselook(mouselook != 0);
  11061. }
  11062. public LSL_Float llGetObjectMass(LSL_Key id)
  11063. {
  11064. if (!UUID.TryParse(id, out UUID key) || key.IsZero())
  11065. return 0;
  11066. // return total object mass
  11067. SceneObjectPart part = World.GetSceneObjectPart(key);
  11068. if (part != null)
  11069. return part.ParentGroup.GetMass();
  11070. // the object is null so the key is for an avatar
  11071. ScenePresence avatar = World.GetScenePresence(key);
  11072. if (avatar != null)
  11073. {
  11074. if (avatar.IsChildAgent)
  11075. {
  11076. // reference http://www.lslwiki.net/lslwiki/wakka.php?wakka=llGetObjectMass
  11077. // child agents have a mass of 1.0
  11078. return 1;
  11079. }
  11080. else
  11081. {
  11082. return avatar.GetMass();
  11083. }
  11084. }
  11085. return 0;
  11086. }
  11087. /// <summary>
  11088. /// llListReplaceList removes the sub-list defined by the inclusive indices
  11089. /// start and end and inserts the src list in its place. The inclusive
  11090. /// nature of the indices means that at least one element must be deleted
  11091. /// if the indices are within the bounds of the existing list. I.e. 2,2
  11092. /// will remove the element at index 2 and replace it with the source
  11093. /// list. Both indices may be negative, with the usual interpretation. An
  11094. /// interesting case is where end is lower than start. As these indices
  11095. /// bound the list to be removed, then 0->end, and start->lim are removed
  11096. /// and the source list is added as a suffix.
  11097. /// </summary>
  11098. public LSL_List llListReplaceList(LSL_List dest, LSL_List src, int start, int end)
  11099. {
  11100. LSL_List pref;
  11101. // Note that although we have normalized, both
  11102. // indices could still be negative.
  11103. if (start < 0)
  11104. start += dest.Length;
  11105. if (end < 0)
  11106. end += dest.Length;
  11107. // The comventional case, remove a sequence starting with
  11108. // start and ending with end. And then insert the source
  11109. // list.
  11110. if (start <= end)
  11111. {
  11112. // If greater than zero, then there is going to be a
  11113. // surviving prefix. Otherwise the inclusive nature
  11114. // of the indices mean that we're going to add the
  11115. // source list as a prefix.
  11116. if (start > 0)
  11117. {
  11118. pref = dest.GetSublist(0,start-1);
  11119. // Only add a suffix if there is something
  11120. // beyond the end index (it's inclusive too).
  11121. if (end + 1 < dest.Length)
  11122. {
  11123. return pref + src + dest.GetSublist(end + 1, -1);
  11124. }
  11125. else
  11126. {
  11127. return pref + src;
  11128. }
  11129. }
  11130. // If start is less than or equal to zero, then
  11131. // the new list is simply a prefix. We still need to
  11132. // figure out any necessary surgery to the destination
  11133. // based upon end. Note that if end exceeds the upper
  11134. // bound in this case, the entire destination list
  11135. // is removed.
  11136. else if (start == 0)
  11137. {
  11138. if (end + 1 < dest.Length)
  11139. return src + dest.GetSublist(end + 1, -1);
  11140. else
  11141. return src;
  11142. }
  11143. else // Start < 0
  11144. {
  11145. if (end + 1 < dest.Length)
  11146. return dest.GetSublist(end + 1, -1);
  11147. else
  11148. return new LSL_List();
  11149. }
  11150. }
  11151. // Finally, if start > end, we strip away a prefix and
  11152. // a suffix, to leave the list that sits <between> ens
  11153. // and start, and then tag on the src list. AT least
  11154. // that's my interpretation. We can get sublist to do
  11155. // this for us. Note that one, or both of the indices
  11156. // might have been negative.
  11157. else
  11158. {
  11159. return dest.GetSublist(end + 1, start - 1) + src;
  11160. }
  11161. }
  11162. public void llLoadURL(string avatar_id, string message, string url)
  11163. {
  11164. if(m_host.OwnerID.Equals(m_host.GroupID))
  11165. return;
  11166. try
  11167. {
  11168. Uri m_checkuri = new(url);
  11169. if (m_checkuri.Scheme != Uri.UriSchemeHttp && m_checkuri.Scheme != Uri.UriSchemeHttps)
  11170. {
  11171. Error("llLoadURL","Invalid url schema");
  11172. ScriptSleep(200);
  11173. return;
  11174. }
  11175. }
  11176. catch
  11177. {
  11178. Error("llLoadURL","Invalid url");
  11179. ScriptSleep(200);
  11180. return;
  11181. }
  11182. IDialogModule dm = World.RequestModuleInterface<IDialogModule>();
  11183. dm?.SendUrlToUser(
  11184. new UUID(avatar_id), m_host.Name, m_host.UUID, m_host.OwnerID, false, message, url);
  11185. ScriptSleep(m_sleepMsOnLoadURL);
  11186. }
  11187. public void llParcelMediaCommandList(LSL_List commandList)
  11188. {
  11189. // according to the docs, this command only works if script owner and land owner are the same
  11190. // lets add estate owners and gods, too, and use the generic permission check.
  11191. ILandObject landObject = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
  11192. if (!World.Permissions.CanEditParcelProperties(m_host.OwnerID, landObject, GroupPowers.ChangeMedia, false)) return;
  11193. bool update = false; // send a ParcelMediaUpdate (and possibly change the land's media URL)?
  11194. byte loop = 0;
  11195. LandData landData = landObject.LandData;
  11196. string url = landData.MediaURL;
  11197. string texture = landData.MediaID.ToString();
  11198. bool autoAlign = landData.MediaAutoScale != 0;
  11199. string mediaType = ""; // TODO these have to be added as soon as LandData supports it
  11200. string description = "";
  11201. int width = 0;
  11202. int height = 0;
  11203. ParcelMediaCommandEnum? commandToSend = null;
  11204. float time = 0.0f; // default is from start
  11205. uint cmndFlags = 0;
  11206. ScenePresence presence = null;
  11207. int cmd;
  11208. for (int i = 0; i < commandList.Data.Length; i++)
  11209. {
  11210. if(commandList.Data[i] is LSL_Integer LSL_Integerdt)
  11211. cmd = LSL_Integerdt;
  11212. else
  11213. cmd = (int)commandList.Data[i];
  11214. ParcelMediaCommandEnum command = (ParcelMediaCommandEnum)cmd;
  11215. switch (command)
  11216. {
  11217. case ParcelMediaCommandEnum.Agent:
  11218. // we send only to one agent
  11219. if ((i + 1) < commandList.Length)
  11220. {
  11221. if (commandList.Data[i + 1] is LSL_String LSL_Stringdt)
  11222. {
  11223. if (UUID.TryParse(LSL_Stringdt, out UUID agentID) && agentID.IsNotZero())
  11224. {
  11225. presence = World.GetScenePresence(agentID);
  11226. if(presence == null || presence.IsNPC)
  11227. return;
  11228. }
  11229. }
  11230. else Error("llParcelMediaCommandList", "The argument of PARCEL_MEDIA_COMMAND_AGENT must be a key");
  11231. ++i;
  11232. }
  11233. break;
  11234. case ParcelMediaCommandEnum.Loop:
  11235. loop = 1;
  11236. cmndFlags |= (1 << ScriptBaseClass.PARCEL_MEDIA_COMMAND_LOOP);
  11237. commandToSend = command;
  11238. update = true; //need to send the media update packet to set looping
  11239. break;
  11240. case ParcelMediaCommandEnum.Play:
  11241. loop = 0;
  11242. cmndFlags |= (1 << ScriptBaseClass.PARCEL_MEDIA_COMMAND_PLAY);
  11243. commandToSend = command;
  11244. update = true; //need to send the media update packet to make sure it doesn't loop
  11245. break;
  11246. case ParcelMediaCommandEnum.Pause:
  11247. cmndFlags |= (1 << ScriptBaseClass.PARCEL_MEDIA_COMMAND_PAUSE);
  11248. commandToSend = command;
  11249. break;
  11250. case ParcelMediaCommandEnum.Stop:
  11251. cmndFlags |= (1 << ScriptBaseClass.PARCEL_MEDIA_COMMAND_STOP);
  11252. commandToSend = command;
  11253. break;
  11254. case ParcelMediaCommandEnum.Unload:
  11255. cmndFlags |= (1 << ScriptBaseClass.PARCEL_MEDIA_COMMAND_UNLOAD);
  11256. commandToSend = command;
  11257. break;
  11258. case ParcelMediaCommandEnum.Url:
  11259. if ((i + 1) < commandList.Length)
  11260. {
  11261. if (commandList.Data[i + 1] is LSL_String LSL_Stringurl)
  11262. {
  11263. url = LSL_Stringurl.m_string;
  11264. if(string.IsNullOrWhiteSpace(url))
  11265. url = string.Empty;
  11266. else
  11267. {
  11268. try
  11269. {
  11270. Uri dummy = new(url, UriKind.Absolute);
  11271. }
  11272. catch
  11273. {
  11274. Error("llParcelMediaCommandList", "invalid PARCEL_MEDIA_COMMAND_URL");
  11275. return;
  11276. }
  11277. }
  11278. update = true;
  11279. }
  11280. else Error("llParcelMediaCommandList", "The argument of PARCEL_MEDIA_COMMAND_URL must be a string");
  11281. ++i;
  11282. }
  11283. break;
  11284. case ParcelMediaCommandEnum.Texture:
  11285. if ((i + 1) < commandList.Length)
  11286. {
  11287. if (commandList.Data[i + 1] is LSL_String LSL_Stringdt)
  11288. {
  11289. texture = LSL_Stringdt.m_string;
  11290. update = true;
  11291. }
  11292. else Error("llParcelMediaCommandList", "The argument of PARCEL_MEDIA_COMMAND_TEXTURE must be a string or a key");
  11293. ++i;
  11294. }
  11295. break;
  11296. case ParcelMediaCommandEnum.Time:
  11297. if ((i + 1) < commandList.Length)
  11298. {
  11299. if (commandList.Data[i + 1] is LSL_Float LSL_Floatdt)
  11300. {
  11301. time = (float)LSL_Floatdt;
  11302. cmndFlags |= (1 << ScriptBaseClass.PARCEL_MEDIA_COMMAND_TIME);
  11303. }
  11304. else Error("llParcelMediaCommandList", "The argument of PARCEL_MEDIA_COMMAND_TIME must be a float");
  11305. ++i;
  11306. }
  11307. break;
  11308. case ParcelMediaCommandEnum.AutoAlign:
  11309. if ((i + 1) < commandList.Length)
  11310. {
  11311. if (commandList.Data[i + 1] is LSL_Integer LSL_Integerdta)
  11312. {
  11313. autoAlign = LSL_Integerdta;
  11314. update = true;
  11315. }
  11316. else Error("llParcelMediaCommandList", "The argument of PARCEL_MEDIA_COMMAND_AUTO_ALIGN must be an integer");
  11317. ++i;
  11318. }
  11319. break;
  11320. case ParcelMediaCommandEnum.Type:
  11321. if ((i + 1) < commandList.Length)
  11322. {
  11323. if (commandList.Data[i + 1] is LSL_String LSL_Stringdt)
  11324. {
  11325. mediaType = LSL_Stringdt.m_string;
  11326. update = true;
  11327. }
  11328. else Error("llParcelMediaCommandList", "The argument of PARCEL_MEDIA_COMMAND_TYPE must be a string");
  11329. ++i;
  11330. }
  11331. break;
  11332. case ParcelMediaCommandEnum.Desc:
  11333. if ((i + 1) < commandList.Length)
  11334. {
  11335. if (commandList.Data[i + 1] is LSL_String LSL_Stringdesc)
  11336. {
  11337. description = LSL_Stringdesc.m_string;
  11338. update = true;
  11339. }
  11340. else Error("llParcelMediaCommandList", "The argument of PARCEL_MEDIA_COMMAND_DESC must be a string");
  11341. ++i;
  11342. }
  11343. break;
  11344. case ParcelMediaCommandEnum.Size:
  11345. if ((i + 2) < commandList.Length)
  11346. {
  11347. if (commandList.Data[i + 1] is LSL_Integer LSL_IntegerWitdh)
  11348. {
  11349. if (commandList.Data[i + 2] is LSL_Integer LSL_Integerheight)
  11350. {
  11351. width = LSL_IntegerWitdh;
  11352. height = LSL_Integerheight;
  11353. update = true;
  11354. }
  11355. else Error("llParcelMediaCommandList", "The second argument of PARCEL_MEDIA_COMMAND_SIZE must be an integer");
  11356. }
  11357. else Error("llParcelMediaCommandList", "The first argument of PARCEL_MEDIA_COMMAND_SIZE must be an integer");
  11358. i += 2;
  11359. }
  11360. break;
  11361. default:
  11362. NotImplemented("llParcelMediaCommandList", "Parameter not supported yet: " + Enum.Parse(typeof(ParcelMediaCommandEnum), commandList.Data[i].ToString()).ToString());
  11363. break;
  11364. }//end switch
  11365. }//end for
  11366. // if we didn't get a presence, we send to all and change the url
  11367. // if we did get a presence, we only send to the agent specified, and *don't change the land settings*!
  11368. // did something important change or do we only start/stop/pause?
  11369. if (update)
  11370. {
  11371. if (presence == null)
  11372. {
  11373. // we send to all
  11374. landData.MediaID = new UUID(texture);
  11375. landData.MediaAutoScale = autoAlign ? (byte)1 : (byte)0;
  11376. landData.MediaWidth = width;
  11377. landData.MediaHeight = height;
  11378. landData.MediaType = mediaType;
  11379. // do that one last, it will cause a ParcelPropertiesUpdate
  11380. landObject.SetMediaUrl(url);
  11381. // now send to all (non-child) agents in the parcel
  11382. World.ForEachRootScenePresence(delegate(ScenePresence sp)
  11383. {
  11384. if (sp.currentParcelUUID.Equals(landData.GlobalID))
  11385. {
  11386. sp.ControllingClient.SendParcelMediaUpdate(landData.MediaURL,
  11387. landData.MediaID,
  11388. landData.MediaAutoScale,
  11389. mediaType,
  11390. description,
  11391. width, height,
  11392. loop);
  11393. }
  11394. });
  11395. }
  11396. else if (!presence.IsChildAgent)
  11397. {
  11398. // we only send to one (root) agent
  11399. presence.ControllingClient.SendParcelMediaUpdate(url,
  11400. new UUID(texture),
  11401. autoAlign ? (byte)1 : (byte)0,
  11402. mediaType,
  11403. description,
  11404. width, height,
  11405. loop);
  11406. }
  11407. }
  11408. if (commandToSend != null)
  11409. {
  11410. // the commandList contained a start/stop/... command, too
  11411. if (presence == null)
  11412. {
  11413. // send to all (non-child) agents in the parcel
  11414. World.ForEachRootScenePresence(delegate(ScenePresence sp)
  11415. {
  11416. if (sp.currentParcelUUID.Equals(landData.GlobalID))
  11417. {
  11418. sp.ControllingClient.SendParcelMediaCommand(cmndFlags,
  11419. commandToSend.Value, time);
  11420. }
  11421. });
  11422. }
  11423. else if (!presence.IsChildAgent)
  11424. {
  11425. presence.ControllingClient.SendParcelMediaCommand(cmndFlags,
  11426. commandToSend.Value, time);
  11427. }
  11428. }
  11429. ScriptSleep(m_sleepMsOnParcelMediaCommandList);
  11430. }
  11431. public LSL_List llParcelMediaQuery(LSL_List aList)
  11432. {
  11433. LSL_List list = new();
  11434. Vector3 pos = m_host.AbsolutePosition;
  11435. ILandObject landObject = World.LandChannel.GetLandObject(pos);
  11436. if(landObject is null)
  11437. return list;
  11438. if (!World.Permissions.CanEditParcelProperties(m_host.OwnerID, landObject, GroupPowers.ChangeMedia, false))
  11439. return list;
  11440. LandData land = landObject.LandData;
  11441. if (land is null)
  11442. return list;
  11443. //TO DO: make the implementation for the missing commands
  11444. //PARCEL_MEDIA_COMMAND_LOOP_SET float loop Use this to get or set the parcel's media loop duration. (1.19.1 RC0 or later)
  11445. for (int i = 0; i < aList.Data.Length; i++)
  11446. {
  11447. if (aList.Data[i] != null)
  11448. {
  11449. switch ((ParcelMediaCommandEnum) Convert.ToInt32(aList.Data[i].ToString()))
  11450. {
  11451. case ParcelMediaCommandEnum.Url:
  11452. list.Add(new LSL_String(land.MediaURL));
  11453. break;
  11454. case ParcelMediaCommandEnum.Desc:
  11455. list.Add(new LSL_String(land.MediaDescription));
  11456. break;
  11457. case ParcelMediaCommandEnum.Texture:
  11458. list.Add(new LSL_String(land.MediaID.ToString()));
  11459. break;
  11460. case ParcelMediaCommandEnum.Type:
  11461. list.Add(new LSL_String(land.MediaType));
  11462. break;
  11463. case ParcelMediaCommandEnum.Size:
  11464. list.Add(new LSL_String(land.MediaWidth));
  11465. list.Add(new LSL_String(land.MediaHeight));
  11466. break;
  11467. default:
  11468. ParcelMediaCommandEnum mediaCommandEnum = ParcelMediaCommandEnum.Url;
  11469. NotImplemented("llParcelMediaQuery", "Parameter not supported yet: " + Enum.Parse(mediaCommandEnum.GetType() , aList.Data[i].ToString()).ToString());
  11470. break;
  11471. }
  11472. }
  11473. }
  11474. ScriptSleep(m_sleepMsOnParcelMediaQuery);
  11475. return list;
  11476. }
  11477. public LSL_Integer llModPow(int a, int b, int c)
  11478. {
  11479. Math.DivRem((long)Math.Pow(a, b), c, out long tmp);
  11480. ScriptSleep(m_sleepMsOnModPow);
  11481. return (int)tmp;
  11482. }
  11483. public LSL_Integer llGetInventoryType(string name)
  11484. {
  11485. TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name);
  11486. return item is null ? -1 : item.Type;
  11487. }
  11488. public void llSetPayPrice(int price, LSL_List quick_pay_buttons)
  11489. {
  11490. if(m_host.LocalId != m_host.ParentGroup.RootPart.LocalId)
  11491. return;
  11492. if (quick_pay_buttons.Data.Length < 4)
  11493. {
  11494. int x;
  11495. for (x=quick_pay_buttons.Data.Length; x<= 4; x++)
  11496. {
  11497. quick_pay_buttons.Add(ScriptBaseClass.PAY_HIDE);
  11498. }
  11499. }
  11500. int[] nPrice = new int[5];
  11501. nPrice[0] = price;
  11502. nPrice[1] = quick_pay_buttons.GetIntegerItem(0);
  11503. nPrice[2] = quick_pay_buttons.GetIntegerItem(1);
  11504. nPrice[3] = quick_pay_buttons.GetIntegerItem(2);
  11505. nPrice[4] = quick_pay_buttons.GetIntegerItem(3);
  11506. m_host.ParentGroup.RootPart.PayPrice = nPrice;
  11507. m_host.ParentGroup.HasGroupChanged = true;
  11508. }
  11509. public LSL_Vector llGetCameraPos()
  11510. {
  11511. if (m_item.PermsGranter.IsZero())
  11512. return LSL_Vector.Zero;
  11513. if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0)
  11514. {
  11515. Error("llGetCameraPos", "No permissions to track the camera");
  11516. return LSL_Vector.Zero;
  11517. }
  11518. ScenePresence presence = World.GetScenePresence(m_item.PermsGranter);
  11519. if (presence is not null)
  11520. return new LSL_Vector(presence.CameraPosition);
  11521. return LSL_Vector.Zero;
  11522. }
  11523. public LSL_Rotation llGetCameraRot()
  11524. {
  11525. if (m_item.PermsGranter.IsZero())
  11526. return LSL_Rotation.Identity;
  11527. if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0)
  11528. {
  11529. Error("llGetCameraRot", "No permissions to track the camera");
  11530. return LSL_Rotation.Identity;
  11531. }
  11532. ScenePresence presence = World.GetScenePresence(m_item.PermsGranter);
  11533. if (presence is not null)
  11534. {
  11535. return new LSL_Rotation(presence.CameraRotation);
  11536. }
  11537. return LSL_Rotation.Identity;
  11538. }
  11539. public LSL_Float llGetCameraFOV()
  11540. {
  11541. if (m_item.PermsGranter.IsZero())
  11542. return LSL_Float.Zero;
  11543. if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0)
  11544. {
  11545. Error("llGetCameraAspect", "No permissions to track the camera");
  11546. return LSL_Float.Zero;
  11547. }
  11548. ScenePresence presence = World.GetScenePresence(m_item.PermsGranter);
  11549. if (presence is not null && presence.ControllingClient is not null)
  11550. {
  11551. return new LSL_Float(presence.ControllingClient.FOV);
  11552. }
  11553. return 1.4f;
  11554. }
  11555. public LSL_Float llGetCameraAspect()
  11556. {
  11557. if (m_item.PermsGranter.IsZero())
  11558. return 1f;
  11559. if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0)
  11560. {
  11561. Error("llGetCameraAspect", "No permissions to track the camera");
  11562. return 1f;
  11563. }
  11564. ScenePresence presence = World.GetScenePresence(m_item.PermsGranter);
  11565. if (presence is not null && presence.ControllingClient is not null)
  11566. {
  11567. int h = presence.ControllingClient.viewHeight;
  11568. return new LSL_Float(h > 0 ? (float)presence.ControllingClient.viewWidth / h : 1.0f);
  11569. }
  11570. return 1f;
  11571. }
  11572. public void llSetPrimURL(string url)
  11573. {
  11574. Deprecated("llSetPrimURL", "Use llSetPrimMediaParams instead");
  11575. ScriptSleep(m_sleepMsOnSetPrimURL);
  11576. }
  11577. public void llRefreshPrimURL()
  11578. {
  11579. Deprecated("llRefreshPrimURL");
  11580. ScriptSleep(m_sleepMsOnRefreshPrimURL);
  11581. }
  11582. public LSL_String llEscapeURL(string url)
  11583. {
  11584. try
  11585. {
  11586. return Uri.EscapeDataString(url);
  11587. }
  11588. catch (Exception ex)
  11589. {
  11590. return "llEscapeURL: " + ex.ToString();
  11591. }
  11592. }
  11593. public LSL_String llUnescapeURL(string url)
  11594. {
  11595. try
  11596. {
  11597. return Uri.UnescapeDataString(url);
  11598. }
  11599. catch (Exception ex)
  11600. {
  11601. return "llUnescapeURL: " + ex.ToString();
  11602. }
  11603. }
  11604. public void llMapDestination(string simname, LSL_Vector pos, LSL_Vector lookAt)
  11605. {
  11606. DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, 0);
  11607. if (detectedParams == null)
  11608. {
  11609. if (m_host.ParentGroup.IsAttachment == true)
  11610. {
  11611. detectedParams = new DetectParams
  11612. {
  11613. Key = m_host.OwnerID
  11614. };
  11615. }
  11616. else
  11617. {
  11618. return;
  11619. }
  11620. }
  11621. ScenePresence avatar = World.GetScenePresence(detectedParams.Key);
  11622. avatar?.ControllingClient.SendScriptTeleportRequest(m_host.Name,
  11623. simname, pos, lookAt);
  11624. ScriptSleep(m_sleepMsOnMapDestination);
  11625. }
  11626. public void llAddToLandBanList(LSL_Key avatar, LSL_Float hours)
  11627. {
  11628. if (!UUID.TryParse(avatar, out UUID key) || key.IsZero())
  11629. return;
  11630. ILandObject parcel = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
  11631. if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, parcel, GroupPowers.LandManageBanned, false))
  11632. {
  11633. int expires = (hours != 0) ? Util.UnixTimeSinceEpoch() + (int)(3600.0 * hours) : 0;
  11634. LandData land = parcel.LandData;
  11635. foreach (LandAccessEntry e in land.ParcelAccessList)
  11636. {
  11637. if (e.Flags == AccessList.Ban && e.AgentID.Equals(key))
  11638. {
  11639. if (e.Expires != 0 && e.Expires < expires)
  11640. {
  11641. e.Expires = expires;
  11642. World.EventManager.TriggerLandObjectUpdated((uint)land.LocalID, parcel);
  11643. }
  11644. return;
  11645. }
  11646. }
  11647. LandAccessEntry entry = new()
  11648. {
  11649. AgentID = key,
  11650. Flags = AccessList.Ban,
  11651. Expires = expires
  11652. };
  11653. land.ParcelAccessList.Add(entry);
  11654. land.Flags |= (uint)ParcelFlags.UseBanList;
  11655. World.EventManager.TriggerLandObjectUpdated((uint)land.LocalID, parcel);
  11656. }
  11657. ScriptSleep(m_sleepMsOnAddToLandBanList);
  11658. }
  11659. public void llRemoveFromLandPassList(string avatar)
  11660. {
  11661. if (!UUID.TryParse(avatar, out UUID key) || key.IsZero())
  11662. return;
  11663. ILandObject parcel = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
  11664. if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, parcel, GroupPowers.LandManagePasses, false))
  11665. {
  11666. LandData land = parcel.LandData;
  11667. for(int i = 0; i < land.ParcelAccessList.Count; ++i)
  11668. {
  11669. LandAccessEntry e = land.ParcelAccessList[i];
  11670. if (e.Flags == AccessList.Access && e.AgentID.Equals(key))
  11671. {
  11672. land.ParcelAccessList.RemoveAt(i);
  11673. World.EventManager.TriggerLandObjectUpdated((uint)land.LocalID, parcel);
  11674. break;
  11675. }
  11676. }
  11677. }
  11678. ScriptSleep(m_sleepMsOnRemoveFromLandPassList);
  11679. }
  11680. public void llRemoveFromLandBanList(string avatar)
  11681. {
  11682. if (!UUID.TryParse(avatar, out UUID key) || key.IsZero())
  11683. return;
  11684. ILandObject parcel = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
  11685. if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, parcel, GroupPowers.LandManageBanned, false))
  11686. {
  11687. LandData land = parcel.LandData;
  11688. for (int i = 0; i < land.ParcelAccessList.Count; ++i)
  11689. {
  11690. LandAccessEntry e = land.ParcelAccessList[i];
  11691. if (e.Flags == AccessList.Ban && e.AgentID.Equals(key))
  11692. {
  11693. land.ParcelAccessList.RemoveAt(i);
  11694. World.EventManager.TriggerLandObjectUpdated((uint)land.LocalID, parcel);
  11695. break;
  11696. }
  11697. }
  11698. }
  11699. ScriptSleep(m_sleepMsOnRemoveFromLandBanList);
  11700. }
  11701. public void llSetCameraParams(LSL_List rules)
  11702. {
  11703. // the object we are in
  11704. UUID objectID = m_host.ParentUUID;
  11705. if (objectID.IsZero())
  11706. return;
  11707. // we need the permission first, to know which avatar we want to set the camera for
  11708. UUID agentID = m_item.PermsGranter;
  11709. if (agentID.IsZero())
  11710. return;
  11711. if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0)
  11712. return;
  11713. ScenePresence presence = World.GetScenePresence(agentID);
  11714. // we are not interested in child-agents
  11715. if (presence.IsChildAgent) return;
  11716. SortedDictionary<int, float> parameters = new();
  11717. object[] data = rules.Data;
  11718. for (int i = 0; i < data.Length; ++i)
  11719. {
  11720. int type;
  11721. try
  11722. {
  11723. type = Convert.ToInt32(data[i++].ToString());
  11724. }
  11725. catch
  11726. {
  11727. Error("llSetCameraParams", string.Format("Invalid camera param type {0}", data[i - 1]));
  11728. return;
  11729. }
  11730. if (i >= data.Length) break; // odd number of entries => ignore the last
  11731. // some special cases: Vector parameters are split into 3 float parameters (with type+1, type+2, type+3)
  11732. switch (type)
  11733. {
  11734. case ScriptBaseClass.CAMERA_FOCUS:
  11735. case ScriptBaseClass.CAMERA_FOCUS_OFFSET:
  11736. case ScriptBaseClass.CAMERA_POSITION:
  11737. LSL_Vector v = (LSL_Vector)data[i];
  11738. try
  11739. {
  11740. parameters.Add(type + 1, (float)v.x);
  11741. }
  11742. catch
  11743. {
  11744. switch(type)
  11745. {
  11746. case ScriptBaseClass.CAMERA_FOCUS:
  11747. Error("llSetCameraParams", "CAMERA_FOCUS: Parameter x is invalid");
  11748. return;
  11749. case ScriptBaseClass.CAMERA_FOCUS_OFFSET:
  11750. Error("llSetCameraParams", "CAMERA_FOCUS_OFFSET: Parameter x is invalid");
  11751. return;
  11752. case ScriptBaseClass.CAMERA_POSITION:
  11753. Error("llSetCameraParams", "CAMERA_POSITION: Parameter x is invalid");
  11754. return;
  11755. }
  11756. }
  11757. try
  11758. {
  11759. parameters.Add(type + 2, (float)v.y);
  11760. }
  11761. catch
  11762. {
  11763. switch(type)
  11764. {
  11765. case ScriptBaseClass.CAMERA_FOCUS:
  11766. Error("llSetCameraParams", "CAMERA_FOCUS: Parameter y is invalid");
  11767. return;
  11768. case ScriptBaseClass.CAMERA_FOCUS_OFFSET:
  11769. Error("llSetCameraParams", "CAMERA_FOCUS_OFFSET: Parameter y is invalid");
  11770. return;
  11771. case ScriptBaseClass.CAMERA_POSITION:
  11772. Error("llSetCameraParams", "CAMERA_POSITION: Parameter y is invalid");
  11773. return;
  11774. }
  11775. }
  11776. try
  11777. {
  11778. parameters.Add(type + 3, (float)v.z);
  11779. }
  11780. catch
  11781. {
  11782. switch(type)
  11783. {
  11784. case ScriptBaseClass.CAMERA_FOCUS:
  11785. Error("llSetCameraParams", "CAMERA_FOCUS: Parameter z is invalid");
  11786. return;
  11787. case ScriptBaseClass.CAMERA_FOCUS_OFFSET:
  11788. Error("llSetCameraParams", "CAMERA_FOCUS_OFFSET: Parameter z is invalid");
  11789. return;
  11790. case ScriptBaseClass.CAMERA_POSITION:
  11791. Error("llSetCameraParams", "CAMERA_POSITION: Parameter z is invalid");
  11792. return;
  11793. }
  11794. }
  11795. break;
  11796. default:
  11797. // TODO: clean that up as soon as the implicit casts are in
  11798. if (data[i] is LSL_Float LSL_Floatv)
  11799. parameters.Add(type, (float)LSL_Floatv.value);
  11800. else if (data[i] is LSL_Integer LSL_Integerv)
  11801. parameters.Add(type, LSL_Integerv.value);
  11802. else
  11803. {
  11804. try
  11805. {
  11806. parameters.Add(type, Convert.ToSingle(data[i]));
  11807. }
  11808. catch
  11809. {
  11810. Error("llSetCameraParams", string.Format("{0}: Parameter is invalid", type));
  11811. }
  11812. }
  11813. break;
  11814. }
  11815. }
  11816. if (parameters.Count > 0) presence.ControllingClient.SendSetFollowCamProperties(objectID, parameters);
  11817. }
  11818. public void llClearCameraParams()
  11819. {
  11820. // the object we are in
  11821. UUID objectID = m_host.ParentUUID;
  11822. if (objectID.IsZero())
  11823. return;
  11824. // we need the permission first, to know which avatar we want to clear the camera for
  11825. UUID agentID = m_item.PermsGranter;
  11826. if (agentID.IsZero())
  11827. return;
  11828. if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0)
  11829. return;
  11830. ScenePresence presence = World.GetScenePresence(agentID);
  11831. // we are not interested in child-agents
  11832. if (presence is null || presence.IsChildAgent)
  11833. return;
  11834. presence.ControllingClient.SendClearFollowCamProperties(objectID);
  11835. }
  11836. public LSL_Float llListStatistics(int operation, LSL_List src)
  11837. {
  11838. return operation switch
  11839. {
  11840. ScriptBaseClass.LIST_STAT_RANGE => (LSL_Float)src.Range(),
  11841. ScriptBaseClass.LIST_STAT_MIN => (LSL_Float)src.Min(),
  11842. ScriptBaseClass.LIST_STAT_MAX => (LSL_Float)src.Max(),
  11843. ScriptBaseClass.LIST_STAT_MEAN => (LSL_Float)src.Mean(),
  11844. ScriptBaseClass.LIST_STAT_MEDIAN => (LSL_Float)LSL_List.ToDoubleList(src).Median(),
  11845. ScriptBaseClass.LIST_STAT_NUM_COUNT => (LSL_Float)src.NumericLength(),
  11846. ScriptBaseClass.LIST_STAT_STD_DEV => (LSL_Float)src.StdDev(),
  11847. ScriptBaseClass.LIST_STAT_SUM => (LSL_Float)src.Sum(),
  11848. ScriptBaseClass.LIST_STAT_SUM_SQUARES => (LSL_Float)src.SumSqrs(),
  11849. ScriptBaseClass.LIST_STAT_GEOMETRIC_MEAN => (LSL_Float)src.GeometricMean(),
  11850. ScriptBaseClass.LIST_STAT_HARMONIC_MEAN => (LSL_Float)src.HarmonicMean(),
  11851. _ => (LSL_Float)0.0,
  11852. };
  11853. }
  11854. public LSL_Integer llGetUnixTime()
  11855. {
  11856. return Util.UnixTimeSinceEpoch();
  11857. }
  11858. public LSL_Integer llGetParcelFlags(LSL_Vector pos)
  11859. {
  11860. return (int)World.LandChannel.GetLandObject((float)pos.x, (float)pos.y).LandData.Flags;
  11861. }
  11862. public LSL_Integer llGetRegionFlags()
  11863. {
  11864. IEstateModule estate = World.RequestModuleInterface<IEstateModule>();
  11865. if (estate == null)
  11866. return 67108864;
  11867. return (int)estate.GetRegionFlags();
  11868. }
  11869. private const string b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  11870. public LSL_String llXorBase64Strings(string str1, string str2)
  11871. {
  11872. int padding = 0;
  11873. ScriptSleep(300);
  11874. if (str1.Length == 0)
  11875. return LSL_String.Empty;
  11876. if (str2.Length == 0)
  11877. return str1;
  11878. int len = str2.Length;
  11879. if ((len % 4) != 0) // LL is EVIL!!!!
  11880. {
  11881. while (str2.EndsWith("="))
  11882. str2 = str2[..^1];
  11883. len = str2.Length;
  11884. int mod = len % 4;
  11885. if (mod == 1)
  11886. str2 = str2[..^1];
  11887. else if (mod == 2)
  11888. str2 += "==";
  11889. else if (mod == 3)
  11890. str2 += "=";
  11891. }
  11892. byte[] data1;
  11893. byte[] data2;
  11894. try
  11895. {
  11896. data1 = Convert.FromBase64String(str1);
  11897. data2 = Convert.FromBase64String(str2);
  11898. }
  11899. catch
  11900. {
  11901. return LSL_String.Empty;
  11902. }
  11903. // Remove padding
  11904. while (str1.EndsWith('='))
  11905. {
  11906. str1 = str1[..^1];
  11907. padding++;
  11908. }
  11909. while (str2.EndsWith('='))
  11910. str2 = str2[..^1];
  11911. byte[] d1 = new byte[str1.Length];
  11912. byte[] d2 = new byte[str2.Length];
  11913. for (int i = 0; i < str1.Length; i++)
  11914. {
  11915. int idx = b64.IndexOf(str1.Substring(i, 1));
  11916. if (idx == -1)
  11917. idx = 0;
  11918. d1[i] = (byte)idx;
  11919. }
  11920. for (int i = 0; i < str2.Length; i++)
  11921. {
  11922. int idx = b64.IndexOf(str2.Substring(i, 1));
  11923. if (idx == -1)
  11924. idx = 0;
  11925. d2[i] = (byte)idx;
  11926. }
  11927. string output = string.Empty;
  11928. for (int pos = 0; pos < d1.Length; pos++)
  11929. output += b64[d1[pos] ^ d2[pos % d2.Length]];
  11930. // Here's a funny thing: LL blithely violate the base64
  11931. // standard pretty much everywhere. Here, padding is
  11932. // added only if the first input string had it, rather
  11933. // than when the data actually needs it. This can result
  11934. // in invalid base64 being returned. Go figure.
  11935. while (padding-- > 0)
  11936. output += '=';
  11937. return output;
  11938. }
  11939. public LSL_String llXorBase64StringsCorrect(string str1, string str2)
  11940. {
  11941. if (str1.Length == 0)
  11942. return LSL_String.Empty;
  11943. if (str2.Length == 0)
  11944. return str1;
  11945. int len = str2.Length;
  11946. if ((len % 4) != 0) // LL is EVIL!!!!
  11947. {
  11948. str2 = str2.TrimEnd(new char[] { '=' });
  11949. len = str2.Length;
  11950. if(len == 0)
  11951. return str1;
  11952. int mod = len % 4;
  11953. if (mod == 1)
  11954. str2 = str2[..(len - 1)];
  11955. else if (mod == 2)
  11956. str2 += "==";
  11957. else if (mod == 3)
  11958. str2 += "=";
  11959. }
  11960. byte[] data1;
  11961. byte[] data2;
  11962. try
  11963. {
  11964. data1 = Convert.FromBase64String(str1);
  11965. data2 = Convert.FromBase64String(str2);
  11966. }
  11967. catch (Exception)
  11968. {
  11969. return LSL_String.Empty;
  11970. }
  11971. int len2 = data2.Length;
  11972. if (len2 == 0)
  11973. return str1;
  11974. for (int pos = 0, pos2 = 0; pos < data1.Length; pos++)
  11975. {
  11976. data1[pos] ^= data2[pos2];
  11977. if (++pos2 >= len2)
  11978. pos2 = 0;
  11979. }
  11980. return Convert.ToBase64String(data1);
  11981. }
  11982. private static string truncateBase64(string input)
  11983. {
  11984. if (string.IsNullOrEmpty(input))
  11985. return string.Empty;
  11986. int paddingPos = -1;
  11987. for (int i = 0; i < input.Length; i++)
  11988. {
  11989. char c = input[i];
  11990. if (c >= 'A' && c <= 'Z')
  11991. continue;
  11992. if (c >= 'a' && c <= 'z')
  11993. continue;
  11994. if (c >= '0' && c <= '9')
  11995. continue;
  11996. if (c == '+' || c == '/')
  11997. continue;
  11998. paddingPos = i;
  11999. break;
  12000. }
  12001. if (paddingPos == 0)
  12002. return string.Empty;
  12003. if (paddingPos > 0)
  12004. input = input[..paddingPos];
  12005. int remainder = input.Length % 4;
  12006. return remainder switch
  12007. {
  12008. 0 => input,
  12009. 1 => input[..^1],
  12010. 2 => input + "==",
  12011. _ => input + "=",
  12012. };
  12013. }
  12014. public LSL_String llXorBase64(string str1, string str2)
  12015. {
  12016. if (string.IsNullOrEmpty(str2))
  12017. return str1;
  12018. str1 = truncateBase64(str1);
  12019. if (string.IsNullOrEmpty(str1))
  12020. return LSL_String.Empty;
  12021. str2 = truncateBase64(str2);
  12022. if (string.IsNullOrEmpty(str2))
  12023. return str1;
  12024. byte[] data1;
  12025. byte[] data2;
  12026. try
  12027. {
  12028. data1 = Convert.FromBase64String(str1);
  12029. data2 = Convert.FromBase64String(str2);
  12030. }
  12031. catch (Exception)
  12032. {
  12033. return LSL_String.Empty;
  12034. }
  12035. int len2 = data2.Length;
  12036. if (len2 == 0)
  12037. return str1;
  12038. for (int pos = 0, pos2 = 0; pos < data1.Length; pos++)
  12039. {
  12040. data1[pos] ^= data2[pos2];
  12041. if (++pos2 >= len2)
  12042. pos2 = 0;
  12043. }
  12044. return Convert.ToBase64String(data1);
  12045. }
  12046. static Regex llHTTPRequestRegex = new(@"^(https?:\/\/)(\w+):(\w+)@(.*)$", RegexOptions.Compiled);
  12047. public LSL_Key llHTTPRequest(string url, LSL_List parameters, string body)
  12048. {
  12049. IHttpRequestModule httpScriptMod = m_ScriptEngine.World.RequestModuleInterface<IHttpRequestModule>();
  12050. if(httpScriptMod == null)
  12051. return string.Empty;
  12052. if(!httpScriptMod.CheckThrottle(m_host.LocalId, m_host.OwnerID))
  12053. return ScriptBaseClass.NULL_KEY;
  12054. if(!Uri.TryCreate(url, UriKind.Absolute, out Uri m_checkuri))
  12055. {
  12056. Error("llHTTPRequest", "Invalid url");
  12057. return string.Empty;
  12058. }
  12059. if (m_checkuri.Scheme != Uri.UriSchemeHttp && m_checkuri.Scheme != Uri.UriSchemeHttps)
  12060. {
  12061. Error("llHTTPRequest", "Invalid url schema");
  12062. return string.Empty;
  12063. }
  12064. if (!httpScriptMod.CheckAllowed(m_checkuri))
  12065. {
  12066. Error("llHttpRequest", string.Format("Request to {0} disallowed by filter", url));
  12067. return string.Empty;
  12068. }
  12069. Dictionary<string, string> httpHeaders = new();
  12070. List<string> param = new();
  12071. int nCustomHeaders = 0;
  12072. int flag;
  12073. for (int i = 0; i < parameters.Data.Length; i += 2)
  12074. {
  12075. object di = parameters.Data[i];
  12076. if(di is LSL_Integer li )
  12077. flag = li.value;
  12078. else if (di is int ldi)
  12079. flag = ldi;
  12080. else flag = -1;
  12081. if(flag < 0 || flag > (int)HttpRequestConstants.HTTP_PRAGMA_NO_CACHE)
  12082. {
  12083. Error("llHTTPRequest", "Parameter " + i.ToString() + " is an invalid flag");
  12084. ScriptSleep(200);
  12085. return string.Empty;
  12086. }
  12087. if (flag != (int)HttpRequestConstants.HTTP_CUSTOM_HEADER)
  12088. {
  12089. param.Add(flag.ToString()); //Add parameter flag
  12090. param.Add(parameters.Data[i+1].ToString()); //Add parameter value
  12091. }
  12092. else
  12093. {
  12094. //Parameters are in pairs and custom header takes
  12095. //arguments in pairs so adjust for header marker.
  12096. ++i;
  12097. //Maximum of 8 headers are allowed based on the
  12098. //Second Life documentation for llHTTPRequest.
  12099. for (int count = 1; count <= 8; ++count)
  12100. {
  12101. if(nCustomHeaders >= 8)
  12102. {
  12103. Error("llHTTPRequest", "Max number of custom headers is 8, excess ignored");
  12104. break;
  12105. }
  12106. //Enough parameters remaining for (another) header?
  12107. if (parameters.Data.Length - i < 2)
  12108. {
  12109. //There must be at least one name/value pair for custom header
  12110. if (count == 1)
  12111. Error("llHTTPRequest", "Missing name/value for custom header at parameter " + i.ToString());
  12112. return string.Empty;
  12113. }
  12114. string paramName = parameters.Data[i].ToString();
  12115. string paramNamelwr = paramName.ToLower();
  12116. if (paramNamelwr.StartsWith("proxy-"))
  12117. {
  12118. Error("llHTTPRequest", "Name is invalid as a custom header at parameter " + i.ToString());
  12119. return string.Empty;
  12120. }
  12121. if (paramNamelwr.StartsWith("sec-"))
  12122. {
  12123. Error("llHTTPRequest", "Name is invalid as a custom header at parameter " + i.ToString());
  12124. return string.Empty;
  12125. }
  12126. bool noskip = true;
  12127. if (HttpForbiddenHeaders.TryGetValue(paramName, out bool fatal))
  12128. {
  12129. if(fatal)
  12130. {
  12131. Error("llHTTPRequest", "Name is invalid as a custom header at parameter " + i.ToString());
  12132. return string.Empty;
  12133. }
  12134. noskip = false;
  12135. }
  12136. if (noskip)
  12137. {
  12138. string paramValue = parameters.Data[i + 1].ToString();
  12139. if (paramName.Length + paramValue.Length > 253)
  12140. {
  12141. Error("llHTTPRequest", "name and value length exceds 253 characters for custom header at parameter " + i.ToString());
  12142. return string.Empty;
  12143. }
  12144. httpHeaders[paramName] = paramValue;
  12145. nCustomHeaders++;
  12146. }
  12147. //Have we reached the end of the list of headers?
  12148. //End is marked by a string with a single digit.
  12149. if (i + 2 >= parameters.Data.Length ||
  12150. Char.IsDigit(parameters.Data[i + 2].ToString()[0]))
  12151. {
  12152. break;
  12153. }
  12154. i += 2;
  12155. }
  12156. }
  12157. }
  12158. Vector3 position = m_host.AbsolutePosition;
  12159. Vector3 velocity = m_host.Velocity;
  12160. Quaternion rotation = m_host.GetWorldRotation();
  12161. string ownerName;
  12162. ScenePresence scenePresence = World.GetScenePresence(m_host.OwnerID);
  12163. if (scenePresence is null)
  12164. ownerName = resolveName(m_host.OwnerID);
  12165. else
  12166. ownerName = scenePresence.Name;
  12167. RegionInfo regionInfo = World.RegionInfo;
  12168. if (!string.IsNullOrWhiteSpace(m_lsl_shard))
  12169. httpHeaders["X-SecondLife-Shard"] = m_lsl_shard;
  12170. httpHeaders["X-SecondLife-Object-Name"] = m_host.Name;
  12171. httpHeaders["X-SecondLife-Object-Key"] = m_host.UUID.ToString();
  12172. httpHeaders["X-SecondLife-Region"] = string.Format("{0} ({1}, {2})", regionInfo.RegionName, regionInfo.WorldLocX, regionInfo.WorldLocY);
  12173. httpHeaders["X-SecondLife-Local-Position"] = string.Format("({0:0.000000}, {1:0.000000}, {2:0.000000})", position.X, position.Y, position.Z);
  12174. httpHeaders["X-SecondLife-Local-Velocity"] = string.Format("({0:0.000000}, {1:0.000000}, {2:0.000000})", velocity.X, velocity.Y, velocity.Z);
  12175. httpHeaders["X-SecondLife-Local-Rotation"] = string.Format("({0:0.000000}, {1:0.000000}, {2:0.000000}, {3:0.000000})", rotation.X, rotation.Y, rotation.Z, rotation.W);
  12176. httpHeaders["X-SecondLife-Owner-Name"] = ownerName;
  12177. httpHeaders["X-SecondLife-Owner-Key"] = m_host.OwnerID.ToString();
  12178. if (!string.IsNullOrWhiteSpace(m_lsl_user_agent))
  12179. httpHeaders["User-Agent"] = m_lsl_user_agent;
  12180. // See if the URL contains any header hacks
  12181. string[] urlParts = url.Split(new char[] {'\n'});
  12182. if (urlParts.Length > 1)
  12183. {
  12184. // Iterate the passed headers and parse them
  12185. for (int i = 1 ; i < urlParts.Length ; i++ )
  12186. {
  12187. // The rest of those would be added to the body in SL.
  12188. // Let's not do that.
  12189. if (urlParts[i].Length == 0)
  12190. break;
  12191. // See if this could be a valid header
  12192. string[] headerParts = urlParts[i].Split(new char[] {':'}, 2);
  12193. if (headerParts.Length != 2)
  12194. continue;
  12195. string headerName = headerParts[0].Trim();
  12196. if(!HttpForbiddenInHeaders.Contains(headerName))
  12197. {
  12198. string headerValue = headerParts[1].Trim();
  12199. httpHeaders[headerName] = headerValue;
  12200. }
  12201. }
  12202. // Finally, strip any protocol specifier from the URL
  12203. url = urlParts[0].Trim();
  12204. int idx = url.IndexOf(" HTTP/");
  12205. if (idx != -1)
  12206. url = url[..idx];
  12207. }
  12208. Match m = llHTTPRequestRegex.Match(url);
  12209. if (m.Success)
  12210. {
  12211. if (m.Groups.Count == 5)
  12212. {
  12213. httpHeaders["Authorization"] = String.Format("Basic {0}", Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(m.Groups[2].ToString() + ":" + m.Groups[3].ToString())));
  12214. url = m.Groups[1].ToString() + m.Groups[4].ToString();
  12215. }
  12216. }
  12217. UUID reqID = httpScriptMod.StartHttpRequest(m_host.LocalId, m_item.ItemID, url, param, httpHeaders, body);
  12218. return reqID.IsZero() ? string.Empty : reqID.ToString();
  12219. }
  12220. public void llHTTPResponse(LSL_Key id, int status, string body)
  12221. {
  12222. // Partial implementation: support for parameter flags needed
  12223. // see http://wiki.secondlife.com/wiki/llHTTPResponse
  12224. m_UrlModule?.HttpResponse(new UUID(id), status, body);
  12225. }
  12226. public void llResetLandBanList()
  12227. {
  12228. ILandObject parcel = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
  12229. if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, parcel, GroupPowers.LandManageBanned, false))
  12230. {
  12231. LandData land = parcel.LandData;
  12232. var tokeep = new List<LandAccessEntry>();
  12233. foreach (LandAccessEntry entry in land.ParcelAccessList)
  12234. {
  12235. if (entry.Flags != AccessList.Ban)
  12236. tokeep.Add(entry);
  12237. }
  12238. land.ParcelAccessList = tokeep;
  12239. land.Flags &= ~(uint)ParcelFlags.UseBanList;
  12240. }
  12241. ScriptSleep(m_sleepMsOnResetLandBanList);
  12242. }
  12243. public void llResetLandPassList()
  12244. {
  12245. ILandObject parcel = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
  12246. if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, parcel, GroupPowers.LandManagePasses, false))
  12247. {
  12248. LandData land = parcel.LandData;
  12249. var tokeep = new List<LandAccessEntry>();
  12250. foreach (LandAccessEntry entry in land.ParcelAccessList)
  12251. {
  12252. if (entry.Flags != AccessList.Access)
  12253. tokeep.Add(entry);
  12254. }
  12255. land.ParcelAccessList = tokeep;
  12256. }
  12257. ScriptSleep(m_sleepMsOnResetLandPassList);
  12258. }
  12259. public LSL_Integer llGetParcelPrimCount(LSL_Vector pos, int category, int sim_wide)
  12260. {
  12261. ILandObject lo = World.LandChannel.GetLandObject((float)pos.x, (float)pos.y);
  12262. if (lo == null)
  12263. return 0;
  12264. IPrimCounts pc = lo.PrimCounts;
  12265. if (sim_wide != ScriptBaseClass.FALSE)
  12266. {
  12267. if (category == ScriptBaseClass.PARCEL_COUNT_TOTAL)
  12268. {
  12269. return pc.Simulator;
  12270. }
  12271. else
  12272. {
  12273. // counts not implemented yet
  12274. return 0;
  12275. }
  12276. }
  12277. else
  12278. {
  12279. if (category == ScriptBaseClass.PARCEL_COUNT_TOTAL)
  12280. return pc.Total;
  12281. else if (category == ScriptBaseClass.PARCEL_COUNT_OWNER)
  12282. return pc.Owner;
  12283. else if (category == ScriptBaseClass.PARCEL_COUNT_GROUP)
  12284. return pc.Group;
  12285. else if (category == ScriptBaseClass.PARCEL_COUNT_OTHER)
  12286. return pc.Others;
  12287. else if (category == ScriptBaseClass.PARCEL_COUNT_SELECTED)
  12288. return pc.Selected;
  12289. else if (category == ScriptBaseClass.PARCEL_COUNT_TEMP)
  12290. return 0; // counts not implemented yet
  12291. }
  12292. return 0;
  12293. }
  12294. public LSL_List llGetParcelPrimOwners(LSL_Vector pos)
  12295. {
  12296. LandObject land = (LandObject)World.LandChannel.GetLandObject((float)pos.x, (float)pos.y);
  12297. LSL_List ret = new ();
  12298. if (land is not null)
  12299. {
  12300. foreach (KeyValuePair<UUID, int> detectedParams in land.GetLandObjectOwners())
  12301. {
  12302. ret.Add(new LSL_String(detectedParams.Key.ToString()));
  12303. ret.Add(new LSL_Integer(detectedParams.Value));
  12304. }
  12305. }
  12306. ScriptSleep(m_sleepMsOnGetParcelPrimOwners);
  12307. return ret;
  12308. }
  12309. public LSL_Integer llGetObjectPrimCount(LSL_Key object_id)
  12310. {
  12311. if(!UUID.TryParse(object_id, out UUID id) || id.IsZero())
  12312. return 0;
  12313. SceneObjectPart part = World.GetSceneObjectPart(id);
  12314. if (part is null || part.ParentGroup.IsAttachment)
  12315. return 0;
  12316. return part.ParentGroup.PrimCount;
  12317. }
  12318. public LSL_Integer llGetParcelMaxPrims(LSL_Vector pos, int sim_wide)
  12319. {
  12320. ILandObject lo = World.LandChannel.GetLandObject((float)pos.x, (float)pos.y);
  12321. if (lo == null)
  12322. return 0;
  12323. if (sim_wide != 0)
  12324. return lo.GetSimulatorMaxPrimCount();
  12325. else
  12326. return lo.GetParcelMaxPrimCount();
  12327. }
  12328. public LSL_List llGetParcelDetails(LSL_Vector pos, LSL_List param)
  12329. {
  12330. ILandObject parcel = World.LandChannel.GetLandObject(pos);
  12331. if (parcel is null)
  12332. return new LSL_List(0);
  12333. return GetParcelDetails(parcel, param);
  12334. }
  12335. public LSL_List GetParcelDetails(ILandObject parcel, LSL_List param)
  12336. {
  12337. LandData land = parcel.LandData;
  12338. if (land is null)
  12339. return new LSL_List(0);
  12340. LSL_List ret = new();
  12341. foreach (object o in param.Data)
  12342. {
  12343. if (o is not LSL_Integer io)
  12344. {
  12345. Error("GetParcelDetails", $"Unknown parameter {o}");
  12346. return new LSL_List(0);
  12347. }
  12348. switch (io.value)
  12349. {
  12350. case ScriptBaseClass.PARCEL_DETAILS_NAME:
  12351. ret.Add(new LSL_String(land.Name));
  12352. break;
  12353. case ScriptBaseClass.PARCEL_DETAILS_DESC:
  12354. ret.Add(new LSL_String(land.Description));
  12355. break;
  12356. case ScriptBaseClass.PARCEL_DETAILS_OWNER:
  12357. ret.Add(new LSL_Key(land.OwnerID.ToString()));
  12358. break;
  12359. case ScriptBaseClass.PARCEL_DETAILS_GROUP:
  12360. ret.Add(new LSL_Key(land.GroupID.ToString()));
  12361. break;
  12362. case ScriptBaseClass.PARCEL_DETAILS_AREA:
  12363. ret.Add(new LSL_Integer(land.Area));
  12364. break;
  12365. case ScriptBaseClass.PARCEL_DETAILS_ID:
  12366. ret.Add(new LSL_Key(land.GlobalID.ToString()));
  12367. break;
  12368. case ScriptBaseClass.PARCEL_DETAILS_SEE_AVATARS:
  12369. ret.Add(new LSL_Integer(land.SeeAVs ? 1 : 0));
  12370. break;
  12371. case ScriptBaseClass.PARCEL_DETAILS_PRIM_CAPACITY:
  12372. ret.Add(new LSL_Integer(parcel.GetParcelMaxPrimCount()));
  12373. break;
  12374. case 8:
  12375. ret.Add(new LSL_Integer(parcel.PrimCounts.Total));
  12376. break;
  12377. case ScriptBaseClass.PARCEL_DETAILS_LANDING_POINT:
  12378. ret.Add(new LSL_Vector(land.UserLocation));
  12379. break;
  12380. case ScriptBaseClass.PARCEL_DETAILS_LANDING_LOOKAT:
  12381. ret.Add(new LSL_Vector(land.UserLookAt));
  12382. break;
  12383. case ScriptBaseClass.PARCEL_DETAILS_TP_ROUTING:
  12384. ret.Add(new LSL_Integer(land.LandingType));
  12385. break;
  12386. case ScriptBaseClass.PARCEL_DETAILS_FLAGS:
  12387. ret.Add(new LSL_Integer(land.Flags));
  12388. break;
  12389. case ScriptBaseClass.PARCEL_DETAILS_SCRIPT_DANGER:
  12390. ret.Add(new LSL_Integer(World.LSLScriptDanger(m_host, parcel) ? 1 : 0));
  12391. break;
  12392. case ScriptBaseClass.PARCEL_DETAILS_DWELL:
  12393. ret.Add(new LSL_Integer(land.Dwell));
  12394. break;
  12395. case ScriptBaseClass.PARCEL_DETAILS_GETCLAIMDATE:
  12396. ret.Add(new LSL_Integer(land.ClaimDate));
  12397. break;
  12398. case ScriptBaseClass.PARCEL_DETAILS_GEOMETRICCENTER:
  12399. ret.Add(new LSL_Vector(parcel.CenterPoint.X, parcel.CenterPoint.Y, 0));
  12400. break;
  12401. default:
  12402. Error("GetParcelDetails", $"Unknown parameter {io.value}");
  12403. return new LSL_List(0);
  12404. }
  12405. }
  12406. return ret;
  12407. }
  12408. public LSL_String llStringTrim(LSL_String src, LSL_Integer type)
  12409. {
  12410. if (type == ScriptBaseClass.STRING_TRIM_HEAD) { return ((string)src).TrimStart(); }
  12411. if (type == ScriptBaseClass.STRING_TRIM_TAIL) { return ((string)src).TrimEnd(); }
  12412. if (type == ScriptBaseClass.STRING_TRIM) { return ((string)src).Trim(); }
  12413. return src;
  12414. }
  12415. public LSL_List llGetObjectDetails(LSL_Key id, LSL_List args)
  12416. {
  12417. LSL_List ret = new();
  12418. if (!UUID.TryParse(id, out UUID key) || key.IsZero())
  12419. return ret;
  12420. int count;
  12421. ScenePresence av = World.GetScenePresence(key);
  12422. if (av is not null)
  12423. {
  12424. List<SceneObjectGroup> Attachments = null;
  12425. int? nAnimated = null;
  12426. foreach (object o in args.Data)
  12427. {
  12428. switch (int.Parse(o.ToString()))
  12429. {
  12430. case ScriptBaseClass.OBJECT_NAME:
  12431. ret.Add(new LSL_String($"{av.Firstname} {av.Lastname}"));
  12432. break;
  12433. case ScriptBaseClass.OBJECT_DESC:
  12434. ret.Add(new LSL_String(""));
  12435. break;
  12436. case ScriptBaseClass.OBJECT_POS:
  12437. Vector3 avpos;
  12438. if (av.ParentID != 0 && av.ParentPart is not null &&
  12439. av.ParentPart.ParentGroup is not null && av.ParentPart.ParentGroup.RootPart is not null )
  12440. {
  12441. avpos = av.OffsetPosition;
  12442. if(!av.LegacySitOffsets)
  12443. {
  12444. Vector3 sitOffset = (Zrot(av.Rotation)) * (av.Appearance.AvatarHeight * 0.02638f *2.0f);
  12445. avpos -= sitOffset;
  12446. }
  12447. SceneObjectPart sitRoot = av.ParentPart.ParentGroup.RootPart;
  12448. avpos = sitRoot.GetWorldPosition() + avpos * sitRoot.GetWorldRotation();
  12449. }
  12450. else
  12451. avpos = av.AbsolutePosition;
  12452. ret.Add(new LSL_Vector(avpos));
  12453. break;
  12454. case ScriptBaseClass.OBJECT_ROT:
  12455. Quaternion avrot = av.GetWorldRotation();
  12456. ret.Add(new LSL_Rotation(avrot));
  12457. break;
  12458. case ScriptBaseClass.OBJECT_VELOCITY:
  12459. Vector3 avvel = av.GetWorldVelocity();
  12460. ret.Add(new LSL_Vector(avvel));
  12461. break;
  12462. case ScriptBaseClass.OBJECT_OWNER:
  12463. ret.Add(new LSL_Key((string)id));
  12464. break;
  12465. case ScriptBaseClass.OBJECT_GROUP:
  12466. ret.Add(new LSL_String(ScriptBaseClass.NULL_KEY));
  12467. break;
  12468. case ScriptBaseClass.OBJECT_CREATOR:
  12469. ret.Add(new LSL_Key(ScriptBaseClass.NULL_KEY));
  12470. break;
  12471. // For the following 8 see the Object version below
  12472. case ScriptBaseClass.OBJECT_RUNNING_SCRIPT_COUNT:
  12473. ret.Add(new LSL_Integer(av.RunningScriptCount()));
  12474. break;
  12475. case ScriptBaseClass.OBJECT_TOTAL_SCRIPT_COUNT:
  12476. ret.Add(new LSL_Integer(av.ScriptCount()));
  12477. break;
  12478. case ScriptBaseClass.OBJECT_SCRIPT_MEMORY:
  12479. ret.Add(new LSL_Integer(av.RunningScriptCount() * 16384));
  12480. break;
  12481. case ScriptBaseClass.OBJECT_SCRIPT_TIME:
  12482. ret.Add(new LSL_Float(av.ScriptExecutionTime() / 1000.0f));
  12483. break;
  12484. case ScriptBaseClass.OBJECT_PRIM_EQUIVALENCE:
  12485. ret.Add(new LSL_Integer(1));
  12486. break;
  12487. case ScriptBaseClass.OBJECT_SERVER_COST:
  12488. ret.Add(new LSL_Float(0));
  12489. break;
  12490. case ScriptBaseClass.OBJECT_STREAMING_COST:
  12491. ret.Add(new LSL_Float(0));
  12492. break;
  12493. case ScriptBaseClass.OBJECT_PHYSICS_COST:
  12494. ret.Add(new LSL_Float(0));
  12495. break;
  12496. case ScriptBaseClass.OBJECT_CHARACTER_TIME: // Pathfinding
  12497. ret.Add(new LSL_Float(0));
  12498. break;
  12499. case ScriptBaseClass.OBJECT_ROOT:
  12500. SceneObjectPart p = av.ParentPart;
  12501. if (p is not null)
  12502. ret.Add(new LSL_String(p.ParentGroup.RootPart.UUID.ToString()));
  12503. else
  12504. ret.Add(new LSL_Key((string)id));
  12505. break;
  12506. case ScriptBaseClass.OBJECT_ATTACHED_POINT:
  12507. ret.Add(new LSL_Integer(0));
  12508. break;
  12509. case ScriptBaseClass.OBJECT_PATHFINDING_TYPE: // Pathfinding
  12510. ret.Add(new LSL_Integer(ScriptBaseClass.OPT_AVATAR));
  12511. break;
  12512. case ScriptBaseClass.OBJECT_PHYSICS:
  12513. ret.Add(new LSL_Integer(0));
  12514. break;
  12515. case ScriptBaseClass.OBJECT_PHANTOM:
  12516. ret.Add(new LSL_Integer(0));
  12517. break;
  12518. case ScriptBaseClass.OBJECT_TEMP_ON_REZ:
  12519. ret.Add(new LSL_Integer(0));
  12520. break;
  12521. case ScriptBaseClass.OBJECT_RENDER_WEIGHT:
  12522. ret.Add(new LSL_Integer(-1));
  12523. break;
  12524. case ScriptBaseClass.OBJECT_HOVER_HEIGHT:
  12525. ret.Add(new LSL_Float(0));
  12526. break;
  12527. case ScriptBaseClass.OBJECT_BODY_SHAPE_TYPE:
  12528. LSL_Float shapeType;
  12529. if (av.Appearance.VisualParams[(int)AvatarAppearance.VPElement.SHAPE_MALE] != 0)
  12530. shapeType = new LSL_Float(1);
  12531. else
  12532. shapeType = new LSL_Float(0);
  12533. ret.Add(shapeType);
  12534. break;
  12535. case ScriptBaseClass.OBJECT_LAST_OWNER_ID:
  12536. ret.Add(new LSL_Key(ScriptBaseClass.NULL_KEY));
  12537. break;
  12538. case ScriptBaseClass.OBJECT_CLICK_ACTION:
  12539. ret.Add(new LSL_Integer(0));
  12540. break;
  12541. case ScriptBaseClass.OBJECT_OMEGA:
  12542. ret.Add(new LSL_Vector(Vector3.Zero));
  12543. break;
  12544. case ScriptBaseClass.OBJECT_PRIM_COUNT:
  12545. Attachments ??= av.GetAttachments();
  12546. count = 0;
  12547. try
  12548. {
  12549. foreach (SceneObjectGroup Attachment in Attachments)
  12550. count += Attachment.PrimCount;
  12551. }
  12552. catch { };
  12553. ret.Add(new LSL_Integer(count));
  12554. break;
  12555. case ScriptBaseClass.OBJECT_TOTAL_INVENTORY_COUNT:
  12556. Attachments ??= av.GetAttachments();
  12557. count = 0;
  12558. try
  12559. {
  12560. foreach (SceneObjectGroup Attachment in Attachments)
  12561. {
  12562. SceneObjectPart[] parts = Attachment.Parts;
  12563. for(int i = 0; i < parts.Length; i++)
  12564. count += parts[i].Inventory.Count;
  12565. }
  12566. } catch { };
  12567. ret.Add(new LSL_Integer(count));
  12568. break;
  12569. case ScriptBaseClass.OBJECT_REZZER_KEY:
  12570. ret.Add(new LSL_Key((string)id));
  12571. break;
  12572. case ScriptBaseClass.OBJECT_GROUP_TAG:
  12573. ret.Add(new LSL_String(av.Grouptitle));
  12574. break;
  12575. case ScriptBaseClass.OBJECT_TEMP_ATTACHED:
  12576. ret.Add(new LSL_Integer(0));
  12577. break;
  12578. case ScriptBaseClass.OBJECT_ATTACHED_SLOTS_AVAILABLE:
  12579. ret.Add(new LSL_Integer(Constants.MaxAgentAttachments - av.GetAttachmentsCount()));
  12580. break;
  12581. case ScriptBaseClass.OBJECT_CREATION_TIME:
  12582. ret.Add(new LSL_String(""));
  12583. break;
  12584. case ScriptBaseClass.OBJECT_SELECT_COUNT:
  12585. ret.Add(new LSL_Integer(0));
  12586. break;
  12587. case ScriptBaseClass.OBJECT_SIT_COUNT:
  12588. ret.Add(new LSL_Integer(0));
  12589. break;
  12590. case ScriptBaseClass.OBJECT_ANIMATED_COUNT:
  12591. count = 0;
  12592. if (nAnimated.HasValue)
  12593. count = nAnimated.Value;
  12594. else
  12595. {
  12596. Attachments ??= av.GetAttachments();
  12597. try
  12598. {
  12599. for(int i = 0; i < Attachments.Count;++i)
  12600. {
  12601. if(Attachments[i].RootPart.Shape.MeshFlagEntry)
  12602. ++count;
  12603. }
  12604. }
  12605. catch { };
  12606. nAnimated = count;
  12607. }
  12608. ret.Add(new LSL_Integer(count));
  12609. break;
  12610. case ScriptBaseClass.OBJECT_ANIMATED_SLOTS_AVAILABLE:
  12611. count = 0;
  12612. if (nAnimated.HasValue)
  12613. count = nAnimated.Value;
  12614. else
  12615. {
  12616. Attachments ??= av.GetAttachments();
  12617. count = 0;
  12618. try
  12619. {
  12620. for (int i = 0; i < Attachments.Count; ++i)
  12621. {
  12622. if (Attachments[i].RootPart.Shape.MeshFlagEntry)
  12623. ++count;
  12624. }
  12625. }
  12626. catch { };
  12627. nAnimated = count;
  12628. }
  12629. count = 2 - count; // for now hardcoded max (simulator features, viewers settings, etc)
  12630. if(count < 0)
  12631. count = 0;
  12632. ret.Add(new LSL_Integer(count));
  12633. break;
  12634. case ScriptBaseClass.OBJECT_ACCOUNT_LEVEL:
  12635. ret.Add(new LSL_Integer(1));
  12636. break;
  12637. case ScriptBaseClass.OBJECT_MATERIAL:
  12638. ret.Add(new LSL_Integer((int)Material.Flesh));
  12639. break;
  12640. case ScriptBaseClass.OBJECT_MASS:
  12641. ret.Add(new LSL_Float(av.GetMass()));
  12642. break;
  12643. case ScriptBaseClass.OBJECT_TEXT:
  12644. ret.Add(new LSL_String(""));
  12645. break;
  12646. case ScriptBaseClass.OBJECT_REZ_TIME:
  12647. ret.Add(new LSL_String(""));
  12648. break;
  12649. case ScriptBaseClass.OBJECT_LINK_NUMBER:
  12650. ret.Add(new LSL_Integer(0));
  12651. break;
  12652. case ScriptBaseClass.OBJECT_SCALE:
  12653. ret.Add(new LSL_Vector(av.Appearance.AvatarBoxSize));
  12654. break;
  12655. case ScriptBaseClass.OBJECT_TEXT_COLOR:
  12656. ret.Add(new LSL_Vector(0f, 0f, 0f));
  12657. break;
  12658. case ScriptBaseClass.OBJECT_TEXT_ALPHA:
  12659. ret.Add(new LSL_Float(1.0f));
  12660. break;
  12661. default:
  12662. // Invalid or unhandled constant.
  12663. ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL));
  12664. break;
  12665. }
  12666. }
  12667. return ret;
  12668. }
  12669. SceneObjectPart obj = World.GetSceneObjectPart(key);
  12670. if (obj is not null)
  12671. {
  12672. foreach (object o in args.Data)
  12673. {
  12674. switch (int.Parse(o.ToString()))
  12675. {
  12676. case ScriptBaseClass.OBJECT_NAME:
  12677. ret.Add(new LSL_String(obj.Name));
  12678. break;
  12679. case ScriptBaseClass.OBJECT_DESC:
  12680. ret.Add(new LSL_String(obj.Description));
  12681. break;
  12682. case ScriptBaseClass.OBJECT_POS:
  12683. ret.Add(new LSL_Vector(obj.AbsolutePosition));
  12684. break;
  12685. case ScriptBaseClass.OBJECT_ROT:
  12686. Quaternion rot;
  12687. if (obj.ParentGroup.IsAttachment)
  12688. {
  12689. ScenePresence sp = World.GetScenePresence(obj.ParentGroup.AttachedAvatar);
  12690. rot = sp != null ? sp.GetWorldRotation() : Quaternion.Identity;
  12691. }
  12692. else
  12693. {
  12694. if (obj.ParentGroup.RootPart.LocalId == obj.LocalId)
  12695. rot = obj.ParentGroup.GroupRotation;
  12696. else
  12697. rot = obj.GetWorldRotation();
  12698. }
  12699. ret.Add(new LSL_Rotation(rot));
  12700. break;
  12701. case ScriptBaseClass.OBJECT_VELOCITY:
  12702. Vector3 vel;
  12703. if (obj.ParentGroup.IsAttachment)
  12704. {
  12705. ScenePresence sp = World.GetScenePresence(obj.ParentGroup.AttachedAvatar);
  12706. if(sp is null)
  12707. vel = Vector3.Zero;
  12708. else
  12709. vel = sp.GetWorldVelocity();
  12710. }
  12711. else
  12712. {
  12713. vel = obj.Velocity;
  12714. }
  12715. ret.Add(new LSL_Vector(vel));
  12716. break;
  12717. case ScriptBaseClass.OBJECT_OWNER:
  12718. ret.Add(new LSL_String(obj.OwnerID.ToString()));
  12719. break;
  12720. case ScriptBaseClass.OBJECT_GROUP:
  12721. ret.Add(new LSL_String(obj.GroupID.ToString()));
  12722. break;
  12723. case ScriptBaseClass.OBJECT_CREATOR:
  12724. ret.Add(new LSL_String(obj.CreatorID.ToString()));
  12725. break;
  12726. case ScriptBaseClass.OBJECT_RUNNING_SCRIPT_COUNT:
  12727. ret.Add(new LSL_Integer(obj.ParentGroup.RunningScriptCount()));
  12728. break;
  12729. case ScriptBaseClass.OBJECT_TOTAL_SCRIPT_COUNT:
  12730. ret.Add(new LSL_Integer(obj.ParentGroup.ScriptCount()));
  12731. break;
  12732. case ScriptBaseClass.OBJECT_SCRIPT_MEMORY:
  12733. // The value returned in SL for mono scripts is 65536 * number of active scripts
  12734. // and 16384 * number of active scripts for LSO. since llGetFreememory
  12735. // is coded to give the LSO value use it here
  12736. ret.Add(new LSL_Integer(obj.ParentGroup.RunningScriptCount() * 16384));
  12737. break;
  12738. case ScriptBaseClass.OBJECT_SCRIPT_TIME:
  12739. // Average cpu time in seconds per simulator frame expended on all scripts in the object
  12740. ret.Add(new LSL_Float(obj.ParentGroup.ScriptExecutionTime() / 1000.0f));
  12741. break;
  12742. case ScriptBaseClass.OBJECT_PRIM_EQUIVALENCE:
  12743. // according to the SL wiki A prim or linkset will have prim
  12744. // equivalent of the number of prims in a linkset if it does not
  12745. // contain a mesh anywhere in the link set or is not a normal prim
  12746. // The value returned in SL for normal prims is prim count
  12747. ret.Add(new LSL_Integer(obj.ParentGroup.PrimCount));
  12748. break;
  12749. // costs below may need to be diferent for root parts, need to check
  12750. case ScriptBaseClass.OBJECT_SERVER_COST:
  12751. // The linden calculation is here
  12752. // http://wiki.secondlife.com/wiki/Mesh/Mesh_Server_Weight
  12753. // The value returned in SL for normal prims looks like the prim count
  12754. ret.Add(new LSL_Float(0));
  12755. break;
  12756. case ScriptBaseClass.OBJECT_STREAMING_COST:
  12757. // The value returned in SL for normal prims is prim count * 0.06
  12758. ret.Add(new LSL_Float(obj.StreamingCost));
  12759. break;
  12760. case ScriptBaseClass.OBJECT_PHYSICS_COST:
  12761. // The value returned in SL for normal prims is prim count
  12762. ret.Add(new LSL_Float(obj.PhysicsCost));
  12763. break;
  12764. case ScriptBaseClass.OBJECT_CHARACTER_TIME: // Pathfinding
  12765. ret.Add(new LSL_Float(0));
  12766. break;
  12767. case ScriptBaseClass.OBJECT_ROOT:
  12768. ret.Add(new LSL_String(obj.ParentGroup.RootPart.UUID.ToString()));
  12769. break;
  12770. case ScriptBaseClass.OBJECT_ATTACHED_POINT:
  12771. ret.Add(new LSL_Integer(obj.ParentGroup.AttachmentPoint));
  12772. break;
  12773. case ScriptBaseClass.OBJECT_PATHFINDING_TYPE:
  12774. byte pcode = obj.Shape.PCode;
  12775. if (obj.ParentGroup.AttachmentPoint != 0
  12776. || pcode == (byte)PCode.Grass
  12777. || pcode == (byte)PCode.Tree
  12778. || pcode == (byte)PCode.NewTree)
  12779. {
  12780. ret.Add(new LSL_Integer(ScriptBaseClass.OPT_OTHER));
  12781. }
  12782. else
  12783. {
  12784. ret.Add(new LSL_Integer(ScriptBaseClass.OPT_LEGACY_LINKSET));
  12785. }
  12786. break;
  12787. case ScriptBaseClass.OBJECT_PHYSICS:
  12788. if (obj.ParentGroup.AttachmentPoint != 0)
  12789. ret.Add(new LSL_Integer(0)); // Always false if attached
  12790. else
  12791. ret.Add(new LSL_Integer(obj.ParentGroup.UsesPhysics ? 1 : 0));
  12792. break;
  12793. case ScriptBaseClass.OBJECT_PHANTOM:
  12794. if (obj.ParentGroup.AttachmentPoint != 0)
  12795. ret.Add(new LSL_Integer(0)); // Always false if attached
  12796. else
  12797. ret.Add(new LSL_Integer(obj.ParentGroup.IsPhantom ? 1 : 0));
  12798. break;
  12799. case ScriptBaseClass.OBJECT_TEMP_ON_REZ:
  12800. ret.Add(new LSL_Integer(obj.ParentGroup.IsTemporary ? 1 : 0));
  12801. break;
  12802. case ScriptBaseClass.OBJECT_RENDER_WEIGHT:
  12803. ret.Add(new LSL_Integer(0));
  12804. break;
  12805. case ScriptBaseClass.OBJECT_HOVER_HEIGHT:
  12806. ret.Add(new LSL_Float(0));
  12807. break;
  12808. case ScriptBaseClass.OBJECT_BODY_SHAPE_TYPE:
  12809. ret.Add(new LSL_Float(-1));
  12810. break;
  12811. case ScriptBaseClass.OBJECT_LAST_OWNER_ID:
  12812. ret.Add(new LSL_Key(obj.ParentGroup.LastOwnerID.ToString()));
  12813. break;
  12814. case ScriptBaseClass.OBJECT_CLICK_ACTION:
  12815. ret.Add(new LSL_Integer(obj.ClickAction));
  12816. break;
  12817. case ScriptBaseClass.OBJECT_OMEGA:
  12818. ret.Add(new LSL_Vector(obj.AngularVelocity));
  12819. break;
  12820. case ScriptBaseClass.OBJECT_PRIM_COUNT:
  12821. ret.Add(new LSL_Integer(obj.ParentGroup.PrimCount));
  12822. break;
  12823. case ScriptBaseClass.OBJECT_TOTAL_INVENTORY_COUNT:
  12824. SceneObjectPart[] parts = obj.ParentGroup.Parts;
  12825. count = 0;
  12826. for(int i = 0; i < parts.Length; i++)
  12827. count += parts[i].Inventory.Count;
  12828. ret.Add(new LSL_Integer(count));
  12829. break;
  12830. case ScriptBaseClass.OBJECT_REZZER_KEY:
  12831. ret.Add(new LSL_Key(obj.ParentGroup.RezzerID.ToString()));
  12832. break;
  12833. case ScriptBaseClass.OBJECT_GROUP_TAG:
  12834. ret.Add(new LSL_String(String.Empty));
  12835. break;
  12836. case ScriptBaseClass.OBJECT_TEMP_ATTACHED:
  12837. if (obj.ParentGroup.AttachmentPoint != 0 && obj.ParentGroup.FromItemID.IsZero())
  12838. ret.Add(new LSL_Integer(1));
  12839. else
  12840. ret.Add(new LSL_Integer(0));
  12841. break;
  12842. case ScriptBaseClass.OBJECT_ATTACHED_SLOTS_AVAILABLE:
  12843. ret.Add(new LSL_Integer(0));
  12844. break;
  12845. case ScriptBaseClass.OBJECT_CREATION_TIME:
  12846. DateTime date = Util.ToDateTime(obj.ParentGroup.RootPart.CreationDate);
  12847. ret.Add(new LSL_String(date.ToString("yyyy-MM-ddTHH:mm:ssZ", CultureInfo.InvariantCulture)));
  12848. break;
  12849. case ScriptBaseClass.OBJECT_SELECT_COUNT:
  12850. ret.Add(new LSL_Integer(0));
  12851. break;
  12852. case ScriptBaseClass.OBJECT_SIT_COUNT:
  12853. ret.Add(new LSL_Integer(obj.ParentGroup.GetSittingAvatarsCount()));
  12854. break;
  12855. case ScriptBaseClass.OBJECT_ANIMATED_COUNT:
  12856. if(obj.ParentGroup.RootPart.Shape.MeshFlagEntry)
  12857. ret.Add(new LSL_Integer(1));
  12858. else
  12859. ret.Add(new LSL_Integer(0));
  12860. break;
  12861. case ScriptBaseClass.OBJECT_ANIMATED_SLOTS_AVAILABLE:
  12862. ret.Add(new LSL_Integer(0));
  12863. break;
  12864. case ScriptBaseClass.OBJECT_ACCOUNT_LEVEL:
  12865. ret.Add(new LSL_Integer(1));
  12866. break;
  12867. case ScriptBaseClass.OBJECT_MATERIAL:
  12868. ret.Add(new LSL_Integer(obj.Material));
  12869. break;
  12870. case ScriptBaseClass.OBJECT_MASS:
  12871. float mass;
  12872. if (obj.ParentGroup.IsAttachment)
  12873. {
  12874. ScenePresence attachedAvatar = World.GetScenePresence(obj.ParentGroup.AttachedAvatar);
  12875. mass = attachedAvatar is null ? 0 : attachedAvatar.GetMass();
  12876. }
  12877. else
  12878. mass = obj.ParentGroup.GetMass();
  12879. mass *= 100f;
  12880. ret.Add(new LSL_Float(mass));
  12881. break;
  12882. case ScriptBaseClass.OBJECT_TEXT:
  12883. ret.Add(new LSL_String(obj.Text));
  12884. break;
  12885. case ScriptBaseClass.OBJECT_REZ_TIME:
  12886. ret.Add(new LSL_String(obj.Rezzed.ToString("yyyy-MM-ddTHH:mm:ss.ffffffZ", CultureInfo.InvariantCulture)));
  12887. break;
  12888. case ScriptBaseClass.OBJECT_LINK_NUMBER:
  12889. ret.Add(new LSL_Integer(obj.LinkNum));
  12890. break;
  12891. case ScriptBaseClass.OBJECT_SCALE:
  12892. ret.Add(new LSL_Vector(obj.Scale));
  12893. break;
  12894. case ScriptBaseClass.OBJECT_TEXT_COLOR:
  12895. Color4 textColor = obj.GetTextColor();
  12896. ret.Add(new LSL_Vector(textColor.R, textColor.G, textColor.B));
  12897. break;
  12898. case ScriptBaseClass.OBJECT_TEXT_ALPHA:
  12899. ret.Add(new LSL_Float(obj.GetTextColor().A));
  12900. break;
  12901. default:
  12902. // Invalid or unhandled constant.
  12903. ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL));
  12904. break;
  12905. }
  12906. }
  12907. }
  12908. return ret;
  12909. }
  12910. internal UUID GetScriptByName(string name)
  12911. {
  12912. TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name);
  12913. if (item == null || item.Type != 10)
  12914. return UUID.Zero;
  12915. return item.ItemID;
  12916. }
  12917. /// <summary>
  12918. /// Reports the script error in the viewer's Script Warning/Error dialog and shouts it on the debug channel.
  12919. /// </summary>
  12920. /// <param name="command">The name of the command that generated the error.</param>
  12921. /// <param name="message">The error message to report to the user.</param>
  12922. internal void Error(string command, string message)
  12923. {
  12924. string text = command + ": " + message;
  12925. if (text.Length > 1023)
  12926. text = text[..1023];
  12927. World.SimChat(Utils.StringToBytes(text), ChatTypeEnum.DebugChannel, ScriptBaseClass.DEBUG_CHANNEL,
  12928. m_host.ParentGroup.RootPart.AbsolutePosition, m_host.Name, m_host.UUID, false);
  12929. IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
  12930. wComm?.DeliverMessage(ChatTypeEnum.Shout, ScriptBaseClass.DEBUG_CHANNEL, m_host.Name, m_host.UUID, text);
  12931. Sleep(1000);
  12932. }
  12933. /// <summary>
  12934. /// Reports that the command is not implemented as a script error.
  12935. /// </summary>
  12936. /// <param name="command">The name of the command that is not implemented.</param>
  12937. /// <param name="message">Additional information to report to the user. (Optional)</param>
  12938. internal void NotImplemented(string command, string message = "")
  12939. {
  12940. if (throwErrorOnNotImplemented)
  12941. {
  12942. if (message != "")
  12943. {
  12944. message = " - " + message;
  12945. }
  12946. throw new NotImplementedException("Command not implemented: " + command + message);
  12947. }
  12948. else
  12949. {
  12950. string text = "Command not implemented";
  12951. if (message != "")
  12952. {
  12953. text = text + " - " + message;
  12954. }
  12955. Error(command, text);
  12956. }
  12957. }
  12958. /// <summary>
  12959. /// Reports that the command is deprecated as a script error.
  12960. /// </summary>
  12961. /// <param name="command">The name of the command that is deprecated.</param>
  12962. /// <param name="message">Additional information to report to the user. (Optional)</param>
  12963. internal void Deprecated(string command, string message = "")
  12964. {
  12965. string text = "Command deprecated";
  12966. if (message != "")
  12967. {
  12968. text = text + " - " + message;
  12969. }
  12970. Error(command, text);
  12971. }
  12972. public delegate void AssetRequestCallback(UUID assetID, AssetBase asset);
  12973. protected void WithNotecard(UUID assetID, AssetRequestCallback cb)
  12974. {
  12975. World.AssetService.Get(assetID.ToString(), this,
  12976. delegate(string i, object sender, AssetBase a)
  12977. {
  12978. _ = UUID.TryParse(i, out UUID uuid);
  12979. cb(uuid, a);
  12980. });
  12981. }
  12982. public LSL_Key llGetNumberOfNotecardLines(string name)
  12983. {
  12984. if (!UUID.TryParse(name, out UUID assetID))
  12985. {
  12986. TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name);
  12987. if (item is not null && item.Type == 7)
  12988. assetID = item.AssetID;
  12989. }
  12990. if (assetID.IsZero())
  12991. {
  12992. // => complain loudly, as specified by the LSL docs
  12993. Error("llGetNumberOfNotecardLines", "Can't find notecard '" + name + "'");
  12994. return ScriptBaseClass.NULL_KEY;
  12995. }
  12996. if (NotecardCache.IsCached(assetID))
  12997. {
  12998. string ftid = m_AsyncCommands.DataserverPlugin.RequestWithImediatePost(m_host.LocalId, m_item.ItemID, NotecardCache.GetLines(assetID).ToString());
  12999. ScriptSleep(m_sleepMsOnGetNumberOfNotecardLines);
  13000. return ftid;
  13001. }
  13002. void act(string eventID)
  13003. {
  13004. if (NotecardCache.IsCached(assetID))
  13005. {
  13006. m_AsyncCommands.DataserverPlugin.DataserverReply(eventID, NotecardCache.GetLines(assetID).ToString());
  13007. return;
  13008. }
  13009. AssetBase a = World.AssetService.Get(assetID.ToString());
  13010. if (a is null || a.Type != 7)
  13011. {
  13012. m_AsyncCommands.DataserverPlugin.DataserverReply(eventID, string.Empty);
  13013. return;
  13014. }
  13015. NotecardCache.Cache(assetID, a.Data);
  13016. m_AsyncCommands.DataserverPlugin.DataserverReply(eventID, NotecardCache.GetLines(assetID).ToString());
  13017. }
  13018. UUID tid = m_AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, act);
  13019. ScriptSleep(m_sleepMsOnGetNumberOfNotecardLines);
  13020. return tid.ToString();
  13021. }
  13022. public LSL_String llGetNotecardLineSync(string name, int line)
  13023. {
  13024. if (line < 0)
  13025. return ScriptBaseClass.NAK;
  13026. if (!UUID.TryParse(name, out UUID assetID))
  13027. {
  13028. TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name, 7);
  13029. if (item is null)
  13030. {
  13031. Error("llGetNotecardLineSync", "Can't find notecard '" + name + "'");
  13032. return ScriptBaseClass.NAK;
  13033. }
  13034. assetID = item.AssetID;
  13035. }
  13036. if (NotecardCache.IsCached(assetID))
  13037. {
  13038. return NotecardCache.GetllLine(assetID, line, 1024);
  13039. }
  13040. else
  13041. {
  13042. return ScriptBaseClass.NAK;
  13043. }
  13044. }
  13045. public LSL_Key llGetNotecardLine(string name, int line)
  13046. {
  13047. if (!UUID.TryParse(name, out UUID assetID))
  13048. {
  13049. TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name);
  13050. if (item != null && item.Type == 7)
  13051. assetID = item.AssetID;
  13052. }
  13053. if (assetID.IsZero())
  13054. {
  13055. // => complain loudly, as specified by the LSL docs
  13056. Error("llGetNotecardLine", "Can't find notecard '" + name + "'");
  13057. return ScriptBaseClass.NULL_KEY;
  13058. }
  13059. if (NotecardCache.IsCached(assetID))
  13060. {
  13061. string eid = m_AsyncCommands.DataserverPlugin.RequestWithImediatePost(m_host.LocalId, m_item.ItemID,
  13062. NotecardCache.GetLine(assetID, line, m_notecardLineReadCharsMax));
  13063. ScriptSleep(m_sleepMsOnGetNotecardLine);
  13064. return eid;
  13065. }
  13066. void act(string eventID)
  13067. {
  13068. if (NotecardCache.IsCached(assetID))
  13069. {
  13070. m_AsyncCommands.DataserverPlugin.DataserverReply(eventID, NotecardCache.GetLine(assetID, line, m_notecardLineReadCharsMax));
  13071. return;
  13072. }
  13073. AssetBase a = World.AssetService.Get(assetID.ToString());
  13074. if (a == null || a.Type != 7)
  13075. {
  13076. m_AsyncCommands.DataserverPlugin.DataserverReply(eventID, string.Empty);
  13077. return;
  13078. }
  13079. NotecardCache.Cache(assetID, a.Data);
  13080. m_AsyncCommands.DataserverPlugin.DataserverReply(
  13081. eventID, NotecardCache.GetLine(assetID, line, m_notecardLineReadCharsMax));
  13082. }
  13083. UUID tid = m_AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, act);
  13084. ScriptSleep(m_sleepMsOnGetNotecardLine);
  13085. return tid.ToString();
  13086. }
  13087. public void SetPrimitiveParamsEx(LSL_Key prim, LSL_List rules, string originFunc)
  13088. {
  13089. if (!UUID.TryParse(prim, out UUID id) || id.IsZero())
  13090. return;
  13091. SceneObjectPart obj = World.GetSceneObjectPart(id);
  13092. if (obj == null)
  13093. return;
  13094. SceneObjectGroup sog = obj.ParentGroup;
  13095. if (sog == null || sog.IsDeleted)
  13096. return;
  13097. SceneObjectPart objRoot = sog.RootPart;
  13098. if (objRoot == null || objRoot.OwnerID.NotEqual(m_host.OwnerID) || (objRoot.OwnerMask & (uint)PermissionMask.Modify) == 0)
  13099. return;
  13100. uint rulesParsed = 0;
  13101. LSL_List remaining = SetPrimParams(obj, rules, originFunc, ref rulesParsed);
  13102. while (remaining.Length > 2)
  13103. {
  13104. int linknumber;
  13105. try
  13106. {
  13107. linknumber = remaining.GetIntegerItem(0);
  13108. }
  13109. catch (InvalidCastException)
  13110. {
  13111. Error(originFunc, string.Format("Error running rule #{0} -> PRIM_LINK_TARGET parameter must be integer", rulesParsed));
  13112. return;
  13113. }
  13114. List<ISceneEntity> entities = GetLinkEntities(obj, linknumber);
  13115. if (entities.Count == 0)
  13116. break;
  13117. rules = remaining.GetSublist(1, -1);
  13118. foreach (ISceneEntity entity in entities)
  13119. {
  13120. if (entity is SceneObjectPart sop)
  13121. remaining = SetPrimParams(sop, rules, originFunc, ref rulesParsed);
  13122. else
  13123. remaining = SetAgentParams((ScenePresence)entity, rules, originFunc, ref rulesParsed);
  13124. }
  13125. }
  13126. }
  13127. public LSL_List GetPrimitiveParamsEx(LSL_Key prim, LSL_List rules)
  13128. {
  13129. LSL_List result = new();
  13130. if (!UUID.TryParse(prim, out UUID id))
  13131. return result;
  13132. SceneObjectPart obj = World.GetSceneObjectPart(id);
  13133. if (obj is null)
  13134. return result;
  13135. SceneObjectGroup sog = obj.ParentGroup;
  13136. if (sog is null || sog.IsDeleted)
  13137. return result;
  13138. SceneObjectPart objRoot = sog.RootPart;
  13139. if (objRoot is null || objRoot.OwnerID.NotEqual(m_host.OwnerID) || (objRoot.OwnerMask & (uint)PermissionMask.Modify) == 0)
  13140. return result;
  13141. LSL_List remaining = GetPrimParams(obj, rules, ref result);
  13142. while (remaining.Length > 1)
  13143. {
  13144. int linknumber;
  13145. try
  13146. {
  13147. linknumber = remaining.GetIntegerItem(0);
  13148. }
  13149. catch (InvalidCastException)
  13150. {
  13151. Error("", string.Format("Error PRIM_LINK_TARGET: parameter must be integer"));
  13152. return result;
  13153. }
  13154. List<ISceneEntity> entities = GetLinkEntities(obj, linknumber);
  13155. if (entities.Count == 0)
  13156. break;
  13157. rules = remaining.GetSublist(1, -1);
  13158. foreach (ISceneEntity entity in entities)
  13159. {
  13160. if (entity is SceneObjectPart sop)
  13161. remaining = GetPrimParams(sop, rules, ref result);
  13162. else
  13163. remaining = GetPrimParams((ScenePresence)entity, rules, ref result);
  13164. }
  13165. }
  13166. return result;
  13167. }
  13168. public void print(string str)
  13169. {
  13170. // yes, this is a real LSL function. See: http://wiki.secondlife.com/wiki/Print
  13171. IOSSL_Api ossl = (IOSSL_Api)m_ScriptEngine.GetApi(m_item.ItemID, "OSSL");
  13172. if (ossl != null)
  13173. {
  13174. ossl.CheckThreatLevel(ThreatLevel.High, "print");
  13175. m_log.Info("LSL print():" + str);
  13176. }
  13177. }
  13178. public LSL_Integer llGetLinkNumberOfSides(LSL_Integer link)
  13179. {
  13180. List<SceneObjectPart> parts = GetLinkParts(link);
  13181. if (parts.Count < 1)
  13182. return 0;
  13183. return GetNumberOfSides(parts[0]);
  13184. }
  13185. private static string Name2Username(string name)
  13186. {
  13187. string[] parts = name.Split();
  13188. if (parts.Length < 2)
  13189. return name.ToLower();
  13190. if (parts[1].Equals("Resident"))
  13191. return parts[0].ToLower();
  13192. return name.Replace(" ", ".").ToLower();
  13193. }
  13194. public LSL_String llGetUsername(LSL_Key id)
  13195. {
  13196. return Name2Username(llKey2Name(id));
  13197. }
  13198. public LSL_Key llRequestUsername(LSL_Key id)
  13199. {
  13200. if (!UUID.TryParse(id, out UUID key) || key.IsZero())
  13201. return string.Empty;
  13202. ScenePresence lpresence = World.GetScenePresence(key);
  13203. if (lpresence != null)
  13204. {
  13205. string lname = lpresence.Name;
  13206. string ftid = m_AsyncCommands.DataserverPlugin.RequestWithImediatePost(m_host.LocalId,
  13207. m_item.ItemID, Name2Username(lname));
  13208. return ftid;
  13209. }
  13210. void act(string eventID)
  13211. {
  13212. string name = String.Empty;
  13213. ScenePresence presence = World.GetScenePresence(key);
  13214. if (presence != null)
  13215. {
  13216. name = presence.Name;
  13217. }
  13218. else if (World.TryGetSceneObjectPart(key, out SceneObjectPart sop))
  13219. {
  13220. name = sop.Name;
  13221. }
  13222. else
  13223. {
  13224. UserAccount account = m_userAccountService.GetUserAccount(RegionScopeID, key);
  13225. if (account != null)
  13226. {
  13227. name = account.FirstName + " " + account.LastName;
  13228. }
  13229. }
  13230. m_AsyncCommands.DataserverPlugin.DataserverReply(eventID, Name2Username(name));
  13231. }
  13232. UUID rq = m_AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, act);
  13233. ScriptSleep(m_sleepMsOnRequestAgentData);
  13234. return rq.ToString();
  13235. }
  13236. public LSL_String llGetDisplayName(LSL_Key id)
  13237. {
  13238. if (UUID.TryParse(id, out UUID key) && key.IsNotZero())
  13239. {
  13240. ScenePresence presence = World.GetScenePresence(key);
  13241. if (presence != null)
  13242. {
  13243. return presence.Name;
  13244. }
  13245. }
  13246. return LSL_String.Empty;
  13247. }
  13248. public LSL_Key llRequestDisplayName(LSL_Key id)
  13249. {
  13250. if (!UUID.TryParse(id, out UUID key) || key.IsZero())
  13251. return string.Empty;
  13252. ScenePresence lpresence = World.GetScenePresence(key);
  13253. if (lpresence != null)
  13254. {
  13255. string lname = lpresence.Name;
  13256. string ftid = m_AsyncCommands.DataserverPlugin.RequestWithImediatePost(m_host.LocalId,
  13257. m_item.ItemID, lname);
  13258. return ftid;
  13259. }
  13260. void act(string eventID)
  13261. {
  13262. string name = String.Empty;
  13263. ScenePresence presence = World.GetScenePresence(key);
  13264. if (presence is not null)
  13265. {
  13266. name = presence.Name;
  13267. }
  13268. else if (World.TryGetSceneObjectPart(key, out SceneObjectPart sop))
  13269. {
  13270. name = sop.Name;
  13271. }
  13272. else
  13273. {
  13274. UserAccount account = m_userAccountService.GetUserAccount(RegionScopeID, key);
  13275. if (account is not null)
  13276. {
  13277. name = account.FirstName + " " + account.LastName;
  13278. }
  13279. }
  13280. m_AsyncCommands.DataserverPlugin.DataserverReply(eventID, name);
  13281. }
  13282. UUID rq = m_AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, act);
  13283. return rq.ToString();
  13284. }
  13285. private struct Tri
  13286. {
  13287. public Vector3 p1;
  13288. public Vector3 p2;
  13289. public Vector3 p3;
  13290. }
  13291. private static bool InBoundingBox(ScenePresence avatar, Vector3 point)
  13292. {
  13293. float height = avatar.Appearance.AvatarHeight;
  13294. Vector3 b1 = avatar.AbsolutePosition + new Vector3(-0.22f, -0.22f, -height/2);
  13295. Vector3 b2 = avatar.AbsolutePosition + new Vector3(0.22f, 0.22f, height/2);
  13296. if (point.X > b1.X && point.X < b2.X &&
  13297. point.Y > b1.Y && point.Y < b2.Y &&
  13298. point.Z > b1.Z && point.Z < b2.Z)
  13299. return true;
  13300. return false;
  13301. }
  13302. private ContactResult[] AvatarIntersection(Vector3 rayStart, Vector3 rayEnd, bool skipPhys)
  13303. {
  13304. List<ContactResult> contacts = new();
  13305. Vector3 ab = rayEnd - rayStart;
  13306. float ablen = ab.Length();
  13307. World.ForEachScenePresence(delegate(ScenePresence sp)
  13308. {
  13309. if(skipPhys && sp.PhysicsActor is not null)
  13310. return;
  13311. Vector3 ac = sp.AbsolutePosition - rayStart;
  13312. double d = Math.Abs(Vector3.Mag(Vector3.Cross(ab, ac)) / ablen);
  13313. if (d > 1.5)
  13314. return;
  13315. double d2 = Vector3.Dot(Vector3.Negate(ab), ac);
  13316. if (d2 > 0)
  13317. return;
  13318. double dp = Math.Sqrt(Vector3.Mag(ac) * Vector3.Mag(ac) - d * d);
  13319. Vector3 p = rayStart + Vector3.Divide(Vector3.Multiply(ab, (float)dp), (float)Vector3.Mag(ab));
  13320. if (!InBoundingBox(sp, p))
  13321. return;
  13322. ContactResult result = new()
  13323. {
  13324. ConsumerID = sp.LocalId,
  13325. Depth = Vector3.Distance(rayStart, p),
  13326. Normal = Vector3.Zero,
  13327. Pos = p
  13328. };
  13329. contacts.Add(result);
  13330. });
  13331. return contacts.ToArray();
  13332. }
  13333. private ContactResult[] ObjectIntersection(Vector3 rayStart, Vector3 rayEnd, bool includePhysical, bool includeNonPhysical, bool includePhantom)
  13334. {
  13335. Ray ray = new(rayStart, Vector3.Normalize(rayEnd - rayStart));
  13336. List<ContactResult> contacts = new();
  13337. Vector3 ab = rayEnd - rayStart;
  13338. World.ForEachSOG(delegate(SceneObjectGroup group)
  13339. {
  13340. if (m_host.ParentGroup == group)
  13341. return;
  13342. if (group.IsAttachment)
  13343. return;
  13344. if (group.RootPart.PhysActor == null)
  13345. {
  13346. if (!includePhantom)
  13347. return;
  13348. }
  13349. else
  13350. {
  13351. if (group.RootPart.PhysActor.IsPhysical)
  13352. {
  13353. if (!includePhysical)
  13354. return;
  13355. }
  13356. else
  13357. {
  13358. if (!includeNonPhysical)
  13359. return;
  13360. }
  13361. }
  13362. // Find the radius ouside of which we don't even need to hit test
  13363. float radius = 0.0f;
  13364. group.GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ);
  13365. if (Math.Abs(minX) > radius)
  13366. radius = Math.Abs(minX);
  13367. if (Math.Abs(minY) > radius)
  13368. radius = Math.Abs(minY);
  13369. if (Math.Abs(minZ) > radius)
  13370. radius = Math.Abs(minZ);
  13371. if (Math.Abs(maxX) > radius)
  13372. radius = Math.Abs(maxX);
  13373. if (Math.Abs(maxY) > radius)
  13374. radius = Math.Abs(maxY);
  13375. if (Math.Abs(maxZ) > radius)
  13376. radius = Math.Abs(maxZ);
  13377. radius *= 1.413f;
  13378. Vector3 ac = group.AbsolutePosition - rayStart;
  13379. double d = Math.Abs(Vector3.Mag(Vector3.Cross(ab, ac)) / Vector3.Distance(rayStart, rayEnd));
  13380. // Too far off ray, don't bother
  13381. if (d > radius)
  13382. return;
  13383. // Behind ray, drop
  13384. double d2 = Vector3.Dot(Vector3.Negate(ab), ac);
  13385. if (d2 > 0)
  13386. return;
  13387. ray = new Ray(rayStart, Vector3.Normalize(rayEnd - rayStart));
  13388. EntityIntersection intersection = group.TestIntersection(ray, true, false);
  13389. // Miss.
  13390. if (!intersection.HitTF)
  13391. return;
  13392. Vector3 b1 = group.AbsolutePosition + new Vector3(minX, minY, minZ);
  13393. Vector3 b2 = group.AbsolutePosition + new Vector3(maxX, maxY, maxZ);
  13394. //m_log.DebugFormat("[LLCASTRAY]: min<{0},{1},{2}>, max<{3},{4},{5}> = hitp<{6},{7},{8}>", b1.X,b1.Y,b1.Z,b2.X,b2.Y,b2.Z,intersection.ipoint.X,intersection.ipoint.Y,intersection.ipoint.Z);
  13395. if (!(intersection.ipoint.X >= b1.X && intersection.ipoint.X <= b2.X &&
  13396. intersection.ipoint.Y >= b1.Y && intersection.ipoint.Y <= b2.Y &&
  13397. intersection.ipoint.Z >= b1.Z && intersection.ipoint.Z <= b2.Z))
  13398. return;
  13399. ContactResult result = new()
  13400. {
  13401. ConsumerID = group.LocalId,
  13402. //Depth = intersection.distance;
  13403. Normal = intersection.normal,
  13404. Pos = intersection.ipoint
  13405. };
  13406. result.Depth = Vector3.Mag(rayStart - result.Pos);
  13407. contacts.Add(result);
  13408. });
  13409. return contacts.ToArray();
  13410. }
  13411. private ContactResult? GroundIntersection(Vector3 rayStart, Vector3 rayEnd)
  13412. {
  13413. double[,] heightfield = World.Heightmap.GetDoubles();
  13414. List<ContactResult> contacts = new();
  13415. double min = 2048.0;
  13416. double max = 0.0;
  13417. // Find the min and max of the heightfield
  13418. for (int x = 0 ; x < World.Heightmap.Width ; x++)
  13419. {
  13420. for (int y = 0 ; y < World.Heightmap.Height ; y++)
  13421. {
  13422. if (heightfield[x, y] > max)
  13423. max = heightfield[x, y];
  13424. if (heightfield[x, y] < min)
  13425. min = heightfield[x, y];
  13426. }
  13427. }
  13428. // A ray extends past rayEnd, but doesn't go back before
  13429. // rayStart. If the start is above the highest point of the ground
  13430. // and the ray goes up, we can't hit the ground. Ever.
  13431. if (rayStart.Z > max && rayEnd.Z >= rayStart.Z)
  13432. return null;
  13433. // Same for going down
  13434. if (rayStart.Z < min && rayEnd.Z <= rayStart.Z)
  13435. return null;
  13436. List<Tri> trilist = new();
  13437. // Create our triangle list
  13438. for (int x = 1 ; x < World.Heightmap.Width ; x++)
  13439. {
  13440. for (int y = 1 ; y < World.Heightmap.Height ; y++)
  13441. {
  13442. Tri t1 = new();
  13443. Tri t2 = new();
  13444. Vector3 p1 = new(x-1, y-1, (float)heightfield[x-1, y-1]);
  13445. Vector3 p2 = new(x, y-1, (float)heightfield[x, y-1]);
  13446. Vector3 p3 = new(x, y, (float)heightfield[x, y]);
  13447. Vector3 p4 = new(x-1, y, (float)heightfield[x-1, y]);
  13448. t1.p1 = p1;
  13449. t1.p2 = p2;
  13450. t1.p3 = p3;
  13451. t2.p1 = p3;
  13452. t2.p2 = p4;
  13453. t2.p3 = p1;
  13454. trilist.Add(t1);
  13455. trilist.Add(t2);
  13456. }
  13457. }
  13458. // Ray direction
  13459. Vector3 rayDirection = rayEnd - rayStart;
  13460. foreach (Tri t in trilist)
  13461. {
  13462. // Compute triangle plane normal and edges
  13463. Vector3 u = t.p2 - t.p1;
  13464. Vector3 v = t.p3 - t.p1;
  13465. Vector3 n = Vector3.Cross(u, v);
  13466. if (n.IsZero())
  13467. continue;
  13468. Vector3 w0 = rayStart - t.p1;
  13469. double a = -Vector3.Dot(n, w0);
  13470. double b = Vector3.Dot(n, rayDirection);
  13471. // Not intersecting the plane, or in plane (same thing)
  13472. // Ignoring this MAY cause the ground to not be detected
  13473. // sometimes
  13474. if (Math.Abs(b) < 0.000001)
  13475. continue;
  13476. double r = a / b;
  13477. // ray points away from plane
  13478. if (r < 0.0)
  13479. continue;
  13480. Vector3 ip = rayStart + Vector3.Multiply(rayDirection, (float)r);
  13481. float uu = Vector3.Dot(u, u);
  13482. float uv = Vector3.Dot(u, v);
  13483. float vv = Vector3.Dot(v, v);
  13484. Vector3 w = ip - t.p1;
  13485. float wu = Vector3.Dot(w, u);
  13486. float wv = Vector3.Dot(w, v);
  13487. float d = uv * uv - uu * vv;
  13488. float cs = (uv * wv - vv * wu) / d;
  13489. if (cs < 0 || cs > 1.0)
  13490. continue;
  13491. float ct = (uv * wu - uu * wv) / d;
  13492. if (ct < 0 || (cs + ct) > 1.0)
  13493. continue;
  13494. // Add contact point
  13495. ContactResult result = new()
  13496. {
  13497. ConsumerID = 0,
  13498. Depth = Vector3.Distance(rayStart, ip),
  13499. Normal = n,
  13500. Pos = ip
  13501. };
  13502. contacts.Add(result);
  13503. }
  13504. if (contacts.Count == 0)
  13505. return null;
  13506. contacts.Sort(delegate(ContactResult a, ContactResult b)
  13507. {
  13508. return (int)(a.Depth - b.Depth);
  13509. });
  13510. return contacts[0];
  13511. }
  13512. /*
  13513. // not done:
  13514. private ContactResult[] testRay2NonPhysicalPhantom(Vector3 rayStart, Vector3 raydir, float raylenght)
  13515. {
  13516. ContactResult[] contacts = null;
  13517. World.ForEachSOG(delegate(SceneObjectGroup group)
  13518. {
  13519. if (m_host.ParentGroup == group)
  13520. return;
  13521. if (group.IsAttachment)
  13522. return;
  13523. if(group.RootPart.PhysActor != null)
  13524. return;
  13525. contacts = group.RayCastGroupPartsOBBNonPhysicalPhantom(rayStart, raydir, raylenght);
  13526. });
  13527. return contacts;
  13528. }
  13529. */
  13530. public LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options)
  13531. {
  13532. LSL_List list = new();
  13533. Vector3 rayStart = start;
  13534. Vector3 rayEnd = end;
  13535. Vector3 dir = rayEnd - rayStart;
  13536. float dist = dir.LengthSquared();
  13537. if (dist < 1e-6)
  13538. {
  13539. list.Add(new LSL_Integer(0));
  13540. return list;
  13541. }
  13542. int count = 1;
  13543. bool detectPhantom = false;
  13544. int dataFlags = 0;
  13545. int rejectTypes = 0;
  13546. for (int i = 0; i < options.Length; i += 2)
  13547. {
  13548. if (options.GetIntegerItem(i) == ScriptBaseClass.RC_MAX_HITS)
  13549. count = options.GetIntegerItem(i + 1);
  13550. else if (options.GetIntegerItem(i) == ScriptBaseClass.RC_DETECT_PHANTOM)
  13551. detectPhantom = (options.GetIntegerItem(i + 1) > 0);
  13552. else if (options.GetIntegerItem(i) == ScriptBaseClass.RC_DATA_FLAGS)
  13553. dataFlags = options.GetIntegerItem(i + 1);
  13554. else if (options.GetIntegerItem(i) == ScriptBaseClass.RC_REJECT_TYPES)
  13555. rejectTypes = options.GetIntegerItem(i + 1);
  13556. }
  13557. if (count > 16)
  13558. count = 16;
  13559. List<ContactResult> results = new();
  13560. bool checkTerrain = (rejectTypes & ScriptBaseClass.RC_REJECT_LAND) == 0;
  13561. bool checkAgents = (rejectTypes & ScriptBaseClass.RC_REJECT_AGENTS) == 0;
  13562. bool checkNonPhysical = (rejectTypes & ScriptBaseClass.RC_REJECT_NONPHYSICAL) == 0;
  13563. bool checkPhysical = (rejectTypes & ScriptBaseClass.RC_REJECT_PHYSICAL) == 0;
  13564. bool rejectHost = (rejectTypes & ScriptBaseClass.RC_REJECT_HOST) != 0;
  13565. bool rejectHostGroup = (rejectTypes & ScriptBaseClass.RC_REJECT_HOSTGROUP) != 0;
  13566. if (World.SupportsRayCastFiltered())
  13567. {
  13568. RayFilterFlags rayfilter = 0;
  13569. if (checkTerrain)
  13570. rayfilter = RayFilterFlags.land;
  13571. if (checkAgents)
  13572. rayfilter |= RayFilterFlags.agent;
  13573. if (checkPhysical)
  13574. rayfilter |= RayFilterFlags.physical;
  13575. if (checkNonPhysical)
  13576. rayfilter |= RayFilterFlags.nonphysical;
  13577. if (detectPhantom)
  13578. rayfilter |= RayFilterFlags.LSLPhantom;
  13579. if(rayfilter == 0)
  13580. {
  13581. list.Add(new LSL_Integer(0));
  13582. return list;
  13583. }
  13584. rayfilter |= RayFilterFlags.BackFaceCull;
  13585. dist = (float)Math.Sqrt(dist);
  13586. Vector3 direction = dir * (1.0f / dist);
  13587. // get some more contacts to sort ???
  13588. object physresults = World.RayCastFiltered(rayStart, direction, dist, 2 * count, rayfilter);
  13589. if (physresults != null)
  13590. {
  13591. results = (List<ContactResult>)physresults;
  13592. }
  13593. // for now physics doesn't detect sitted avatars so do it outside physics
  13594. if (checkAgents)
  13595. {
  13596. ContactResult[] agentHits = AvatarIntersection(rayStart, rayEnd, true);
  13597. foreach (ContactResult r in agentHits)
  13598. results.Add(r);
  13599. }
  13600. // TODO: Replace this with a better solution. ObjectIntersection can only
  13601. // detect nonphysical phantoms. They are detected by virtue of being
  13602. // nonphysical (e.g. no PhysActor) so will not conflict with detecting
  13603. // physicsl phantoms as done by the physics scene
  13604. // We don't want anything else but phantoms here.
  13605. if (detectPhantom)
  13606. {
  13607. ContactResult[] objectHits = ObjectIntersection(rayStart, rayEnd, false, false, true);
  13608. foreach (ContactResult r in objectHits)
  13609. results.Add(r);
  13610. }
  13611. // Double check this because of current ODE distance problems
  13612. if (checkTerrain && dist > 60)
  13613. {
  13614. bool skipGroundCheck = false;
  13615. foreach (ContactResult c in results)
  13616. {
  13617. if (c.ConsumerID == 0) // Physics gave us a ground collision
  13618. skipGroundCheck = true;
  13619. }
  13620. if (!skipGroundCheck)
  13621. {
  13622. float tmp = dir.X * dir.X + dir.Y * dir.Y;
  13623. if(tmp > 2500)
  13624. {
  13625. ContactResult? groundContact = GroundIntersection(rayStart, rayEnd);
  13626. if (groundContact != null)
  13627. results.Add((ContactResult)groundContact);
  13628. }
  13629. }
  13630. }
  13631. }
  13632. else
  13633. {
  13634. if (checkAgents)
  13635. {
  13636. ContactResult[] agentHits = AvatarIntersection(rayStart, rayEnd, false);
  13637. foreach (ContactResult r in agentHits)
  13638. results.Add(r);
  13639. }
  13640. if (checkPhysical || checkNonPhysical || detectPhantom)
  13641. {
  13642. ContactResult[] objectHits = ObjectIntersection(rayStart, rayEnd, checkPhysical, checkNonPhysical, detectPhantom);
  13643. for (int iter = 0; iter < objectHits.Length; iter++)
  13644. {
  13645. // Redistance the Depth because the Scene RayCaster returns distance from center to make the rezzing code simpler.
  13646. objectHits[iter].Depth = Vector3.Distance(objectHits[iter].Pos, rayStart);
  13647. results.Add(objectHits[iter]);
  13648. }
  13649. }
  13650. if (checkTerrain)
  13651. {
  13652. ContactResult? groundContact = GroundIntersection(rayStart, rayEnd);
  13653. if (groundContact != null)
  13654. results.Add((ContactResult)groundContact);
  13655. }
  13656. }
  13657. results.Sort(delegate(ContactResult a, ContactResult b)
  13658. {
  13659. return a.Depth.CompareTo(b.Depth);
  13660. });
  13661. int values = 0;
  13662. SceneObjectGroup thisgrp = m_host.ParentGroup;
  13663. foreach (ContactResult result in results)
  13664. {
  13665. if (result.Depth > dist)
  13666. continue;
  13667. // physics ray can return colisions with host prim
  13668. if (rejectHost && m_host.LocalId == result.ConsumerID)
  13669. continue;
  13670. UUID itemID = UUID.Zero;
  13671. int linkNum = 0;
  13672. SceneObjectPart part = World.GetSceneObjectPart(result.ConsumerID);
  13673. // It's a prim!
  13674. if (part != null)
  13675. {
  13676. if (rejectHostGroup && part.ParentGroup == thisgrp)
  13677. continue;
  13678. if ((dataFlags & ScriptBaseClass.RC_GET_ROOT_KEY) != 0)
  13679. itemID = part.ParentGroup.UUID;
  13680. else
  13681. itemID = part.UUID;
  13682. linkNum = part.LinkNum;
  13683. }
  13684. else
  13685. {
  13686. ScenePresence sp = World.GetScenePresence(result.ConsumerID);
  13687. /// It it a boy? a girl?
  13688. if (sp != null)
  13689. itemID = sp.UUID;
  13690. }
  13691. list.Add(new LSL_String(itemID.ToString()));
  13692. list.Add(new LSL_String(result.Pos.ToString()));
  13693. if ((dataFlags & ScriptBaseClass.RC_GET_LINK_NUM) != 0)
  13694. list.Add(new LSL_Integer(linkNum));
  13695. if ((dataFlags & ScriptBaseClass.RC_GET_NORMAL) != 0)
  13696. list.Add(new LSL_Vector(result.Normal));
  13697. values++;
  13698. if (values >= count)
  13699. break;
  13700. }
  13701. list.Add(new LSL_Integer(values));
  13702. return list;
  13703. }
  13704. /// <summary>
  13705. /// Implementation of llCastRay similar to SL 2015-04-21.
  13706. /// http://wiki.secondlife.com/wiki/LlCastRay
  13707. /// Uses pure geometry, bounding shapes, meshing and no physics
  13708. /// for prims, sculpts, meshes, avatars and terrain.
  13709. /// Implements all flags, reject types and data flags.
  13710. /// Can handle both objects/groups and prims/parts, by config.
  13711. /// May sometimes be inaccurate owing to calculation precision,
  13712. /// meshing detail level and a bug in libopenmetaverse PrimMesher.
  13713. /// </summary>
  13714. public LSL_List llCastRayV3(LSL_Vector start, LSL_Vector end, LSL_List options)
  13715. {
  13716. LSL_List result = new();
  13717. // Prepare throttle data
  13718. int calledMs = Environment.TickCount;
  13719. Stopwatch stopWatch = new();
  13720. stopWatch.Start();
  13721. UUID regionId = World.RegionInfo.RegionID;
  13722. UUID userId = UUID.Zero;
  13723. int msAvailable = 0;
  13724. // Throttle per owner when attachment or "vehicle" (sat upon)
  13725. if (m_host.ParentGroup.IsAttachment || m_host.ParentGroup.GetSittingAvatarsCount() > 0)
  13726. {
  13727. userId = m_host.OwnerID;
  13728. msAvailable = m_msPerAvatarInCastRay;
  13729. }
  13730. // Throttle per parcel when not attachment or vehicle
  13731. else
  13732. {
  13733. LandData land = World.GetLandData(m_host.GetWorldPosition());
  13734. if (land != null)
  13735. msAvailable = m_msPerRegionInCastRay * land.Area / 65536;
  13736. }
  13737. // Clamp for "oversized" parcels on varregions
  13738. if (msAvailable > m_msMaxInCastRay)
  13739. msAvailable = m_msMaxInCastRay;
  13740. // Check throttle data
  13741. int fromCalledMs = calledMs - m_msThrottleInCastRay;
  13742. lock (m_castRayCalls)
  13743. {
  13744. for (int i = m_castRayCalls.Count - 1; i >= 0; i--)
  13745. {
  13746. // Delete old calls from throttle data
  13747. if (m_castRayCalls[i].CalledMs < fromCalledMs)
  13748. m_castRayCalls.RemoveAt(i);
  13749. // Use current region (in multi-region sims)
  13750. else if (m_castRayCalls[i].RegionId.Equals(regionId))
  13751. {
  13752. // Reduce available time with recent calls
  13753. if (m_castRayCalls[i].UserId.Equals(userId))
  13754. msAvailable -= m_castRayCalls[i].UsedMs;
  13755. }
  13756. }
  13757. // Return failure if not enough available time
  13758. if (msAvailable < m_msMinInCastRay)
  13759. {
  13760. result.Add(new LSL_Integer(ScriptBaseClass.RCERR_CAST_TIME_EXCEEDED));
  13761. return result;
  13762. }
  13763. }
  13764. // Initialize
  13765. List<RayHit> rayHits = new();
  13766. float tol = m_floatToleranceInCastRay;
  13767. Vector3 pos1Ray = start;
  13768. Vector3 pos2Ray = end;
  13769. // Get input options
  13770. int rejectTypes = 0;
  13771. int dataFlags = 0;
  13772. int maxHits = 1;
  13773. bool notdetectPhantom = true;
  13774. for (int i = 0; i < options.Length; i += 2)
  13775. {
  13776. if (options.GetIntegerItem(i) == ScriptBaseClass.RC_REJECT_TYPES)
  13777. rejectTypes = options.GetIntegerItem(i + 1);
  13778. else if (options.GetIntegerItem(i) == ScriptBaseClass.RC_DATA_FLAGS)
  13779. dataFlags = options.GetIntegerItem(i + 1);
  13780. else if (options.GetIntegerItem(i) == ScriptBaseClass.RC_MAX_HITS)
  13781. maxHits = options.GetIntegerItem(i + 1);
  13782. else if (options.GetIntegerItem(i) == ScriptBaseClass.RC_DETECT_PHANTOM)
  13783. notdetectPhantom = (options.GetIntegerItem(i + 1) == 0);
  13784. }
  13785. if (maxHits > m_maxHitsInCastRay)
  13786. maxHits = m_maxHitsInCastRay;
  13787. bool rejectAgents = ((rejectTypes & ScriptBaseClass.RC_REJECT_AGENTS) != 0);
  13788. bool rejectPhysical = ((rejectTypes & ScriptBaseClass.RC_REJECT_PHYSICAL) != 0);
  13789. bool rejectNonphysical = ((rejectTypes & ScriptBaseClass.RC_REJECT_NONPHYSICAL) != 0);
  13790. bool rejectLand = ((rejectTypes & ScriptBaseClass.RC_REJECT_LAND) != 0);
  13791. bool getNormal = ((dataFlags & ScriptBaseClass.RC_GET_NORMAL) != 0);
  13792. bool getRootKey = ((dataFlags & ScriptBaseClass.RC_GET_ROOT_KEY) != 0);
  13793. bool getLinkNum = ((dataFlags & ScriptBaseClass.RC_GET_LINK_NUM) != 0);
  13794. // Calculate some basic parameters
  13795. Vector3 vecRay = pos2Ray - pos1Ray;
  13796. float rayLength = vecRay.Length();
  13797. // Try to get a mesher and return failure if none, degenerate ray, or max 0 hits
  13798. IRendering primMesher = null;
  13799. List<string> renderers = RenderingLoader.ListRenderers(Util.ExecutingDirectory());
  13800. if (renderers.Count < 1 || rayLength < tol || m_maxHitsInCastRay < 1)
  13801. {
  13802. result.Add(new LSL_Integer(ScriptBaseClass.RCERR_UNKNOWN));
  13803. return result;
  13804. }
  13805. primMesher = RenderingLoader.LoadRenderer(renderers[0]);
  13806. // Iterate over all objects/groups and prims/parts in region
  13807. World.ForEachSOG(
  13808. delegate(SceneObjectGroup group)
  13809. {
  13810. if(group.IsDeleted || group.RootPart == null)
  13811. return;
  13812. // Check group filters unless part filters are configured
  13813. bool isPhysical = (group.RootPart.PhysActor != null && group.RootPart.PhysActor.IsPhysical);
  13814. bool isNonphysical = !isPhysical;
  13815. bool isPhantom = group.IsPhantom || group.IsVolumeDetect;
  13816. bool isAttachment = group.IsAttachment;
  13817. if (isPhysical && rejectPhysical)
  13818. return;
  13819. if (isNonphysical && rejectNonphysical)
  13820. return;
  13821. if (isPhantom && notdetectPhantom)
  13822. return;
  13823. if (isAttachment && !m_doAttachmentsInCastRay)
  13824. return;
  13825. // Parse object/group if passed filters
  13826. // Iterate over all prims/parts in object/group
  13827. foreach(SceneObjectPart part in group.Parts)
  13828. {
  13829. // ignore PhysicsShapeType.None as physics engines do
  13830. // or we will get into trouble in future
  13831. if(part.PhysicsShapeType == (byte)PhysicsShapeType.None)
  13832. continue;
  13833. isPhysical = (part.PhysActor != null && part.PhysActor.IsPhysical);
  13834. isNonphysical = !isPhysical;
  13835. isPhantom = ((part.Flags & PrimFlags.Phantom) != 0) ||
  13836. (part.VolumeDetectActive);
  13837. if (isPhysical && rejectPhysical)
  13838. continue;
  13839. if (isNonphysical && rejectNonphysical)
  13840. continue;
  13841. if (isPhantom && notdetectPhantom)
  13842. continue;
  13843. // Parse prim/part and project ray if passed filters
  13844. Vector3 scalePart = part.Scale;
  13845. Vector3 posPart = part.GetWorldPosition();
  13846. Quaternion rotPart = part.GetWorldRotation();
  13847. Quaternion rotPartInv = Quaternion.Inverse(rotPart);
  13848. Vector3 pos1RayProj = ((pos1Ray - posPart) * rotPartInv) / scalePart;
  13849. Vector3 pos2RayProj = ((pos2Ray - posPart) * rotPartInv) / scalePart;
  13850. // Filter parts by shape bounding boxes
  13851. Vector3 shapeBoxMax = new(0.5f, 0.5f, 0.5f);
  13852. if (!part.Shape.SculptEntry)
  13853. shapeBoxMax *= new Vector3(m_primSafetyCoeffX, m_primSafetyCoeffY, m_primSafetyCoeffZ);
  13854. shapeBoxMax += new Vector3(tol, tol, tol);
  13855. if (RayIntersectsShapeBox(pos1RayProj, pos2RayProj, shapeBoxMax))
  13856. {
  13857. // Prepare data needed to check for ray hits
  13858. RayTrans rayTrans = new()
  13859. {
  13860. PartId = part.UUID,
  13861. GroupId = part.ParentGroup.UUID,
  13862. Link = group.PrimCount > 1 ? part.LinkNum : 0,
  13863. ScalePart = scalePart,
  13864. PositionPart = posPart,
  13865. RotationPart = rotPart,
  13866. ShapeNeedsEnds = true,
  13867. Position1Ray = pos1Ray,
  13868. Position1RayProj = pos1RayProj,
  13869. VectorRayProj = pos2RayProj - pos1RayProj
  13870. };
  13871. // Get detail level depending on type
  13872. int lod = 0;
  13873. // Mesh detail level
  13874. if (part.Shape.SculptEntry && part.Shape.SculptType == (byte)SculptType.Mesh)
  13875. lod = (int)m_meshLodInCastRay;
  13876. // Sculpt detail level
  13877. else if (part.Shape.SculptEntry && part.Shape.SculptType == (byte)SculptType.Mesh)
  13878. lod = (int)m_sculptLodInCastRay;
  13879. // Shape detail level
  13880. else if (!part.Shape.SculptEntry)
  13881. lod = (int)m_primLodInCastRay;
  13882. // Try to get cached mesh if configured
  13883. ulong meshKey = 0;
  13884. FacetedMesh mesh = null;
  13885. if (m_useMeshCacheInCastRay)
  13886. {
  13887. meshKey = part.Shape.GetMeshKey(Vector3.One, (float)(4 << lod));
  13888. lock (m_cachedMeshes)
  13889. {
  13890. m_cachedMeshes.TryGetValue(meshKey, out mesh);
  13891. }
  13892. }
  13893. // Create mesh if no cached mesh
  13894. if (mesh == null)
  13895. {
  13896. // Make an OMV prim to be able to mesh part
  13897. Primitive omvPrim = part.Shape.ToOmvPrimitive(posPart, rotPart);
  13898. byte[] sculptAsset = null;
  13899. if (omvPrim.Sculpt != null)
  13900. sculptAsset = World.AssetService.GetData(omvPrim.Sculpt.SculptTexture.ToString());
  13901. // When part is mesh, get mesh
  13902. if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type == SculptType.Mesh && sculptAsset != null)
  13903. {
  13904. AssetMesh meshAsset = new(omvPrim.Sculpt.SculptTexture, sculptAsset);
  13905. FacetedMesh.TryDecodeFromAsset(omvPrim, meshAsset, m_meshLodInCastRay, out mesh);
  13906. meshAsset = null;
  13907. }
  13908. // When part is sculpt, create mesh
  13909. // Quirk: Generated sculpt mesh is about 2.8% smaller in X and Y than visual sculpt.
  13910. else if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type != SculptType.Mesh && sculptAsset != null)
  13911. {
  13912. IJ2KDecoder imgDecoder = World.RequestModuleInterface<IJ2KDecoder>();
  13913. if (imgDecoder != null)
  13914. {
  13915. Image sculpt = imgDecoder.DecodeToImage(sculptAsset);
  13916. if (sculpt != null)
  13917. {
  13918. mesh = primMesher.GenerateFacetedSculptMesh(omvPrim, (Bitmap)sculpt, m_sculptLodInCastRay);
  13919. sculpt.Dispose();
  13920. }
  13921. }
  13922. }
  13923. // When part is shape, create mesh
  13924. else if (omvPrim.Sculpt == null)
  13925. {
  13926. if (
  13927. omvPrim.PrimData.PathBegin == 0.0 && omvPrim.PrimData.PathEnd == 1.0 &&
  13928. omvPrim.PrimData.PathTaperX == 0.0 && omvPrim.PrimData.PathTaperY == 0.0 &&
  13929. omvPrim.PrimData.PathSkew == 0.0 &&
  13930. omvPrim.PrimData.PathTwist - omvPrim.PrimData.PathTwistBegin == 0.0
  13931. )
  13932. rayTrans.ShapeNeedsEnds = false;
  13933. mesh = primMesher.GenerateFacetedMesh(omvPrim, m_primLodInCastRay);
  13934. }
  13935. // Cache mesh if configured
  13936. if (m_useMeshCacheInCastRay && mesh != null)
  13937. {
  13938. lock(m_cachedMeshes)
  13939. {
  13940. if (!m_cachedMeshes.ContainsKey(meshKey))
  13941. m_cachedMeshes.Add(meshKey, mesh);
  13942. }
  13943. }
  13944. }
  13945. // Check mesh for ray hits
  13946. AddRayInFacetedMesh(mesh, rayTrans, ref rayHits);
  13947. mesh = null;
  13948. }
  13949. }
  13950. }
  13951. );
  13952. // Check avatar filter
  13953. if (!rejectAgents)
  13954. {
  13955. // Iterate over all avatars in region
  13956. World.ForEachRootScenePresence(
  13957. delegate (ScenePresence sp)
  13958. {
  13959. // Get bounding box
  13960. BoundingBoxOfScenePresence(sp, out Vector3 lower, out Vector3 upper);
  13961. // Parse avatar
  13962. Vector3 scalePart = upper - lower;
  13963. Vector3 posPart = sp.AbsolutePosition;
  13964. Quaternion rotPart = sp.GetWorldRotation();
  13965. Quaternion rotPartInv = Quaternion.Inverse(rotPart);
  13966. posPart += (lower + upper) * 0.5f * rotPart;
  13967. // Project ray
  13968. Vector3 pos1RayProj = ((pos1Ray - posPart) * rotPartInv) / scalePart;
  13969. Vector3 pos2RayProj = ((pos2Ray - posPart) * rotPartInv) / scalePart;
  13970. // Filter avatars by shape bounding boxes
  13971. Vector3 shapeBoxMax = new(0.5f + tol, 0.5f + tol, 0.5f + tol);
  13972. if (RayIntersectsShapeBox(pos1RayProj, pos2RayProj, shapeBoxMax))
  13973. {
  13974. // Prepare data needed to check for ray hits
  13975. RayTrans rayTrans = new()
  13976. {
  13977. PartId = sp.UUID,
  13978. GroupId = sp.ParentPart != null ? sp.ParentPart.ParentGroup.UUID : sp.UUID,
  13979. Link = sp.ParentPart != null ? UUID2LinkNumber(sp.ParentPart, sp.UUID) : 0,
  13980. ScalePart = scalePart,
  13981. PositionPart = posPart,
  13982. RotationPart = rotPart,
  13983. ShapeNeedsEnds = false,
  13984. Position1Ray = pos1Ray,
  13985. Position1RayProj = pos1RayProj,
  13986. VectorRayProj = pos2RayProj - pos1RayProj
  13987. };
  13988. // Try to get cached mesh if configured
  13989. PrimitiveBaseShape prim = PrimitiveBaseShape.CreateSphere();
  13990. int lod = (int)m_avatarLodInCastRay;
  13991. ulong meshKey = prim.GetMeshKey(Vector3.One, (float)(4 << lod));
  13992. FacetedMesh mesh = null;
  13993. if (m_useMeshCacheInCastRay)
  13994. {
  13995. lock (m_cachedMeshes)
  13996. {
  13997. m_cachedMeshes.TryGetValue(meshKey, out mesh);
  13998. }
  13999. }
  14000. // Create mesh if no cached mesh
  14001. if (mesh == null)
  14002. {
  14003. // Make OMV prim and create mesh
  14004. prim.Scale = scalePart;
  14005. Primitive omvPrim = prim.ToOmvPrimitive(posPart, rotPart);
  14006. mesh = primMesher.GenerateFacetedMesh(omvPrim, m_avatarLodInCastRay);
  14007. // Cache mesh if configured
  14008. if (m_useMeshCacheInCastRay && mesh != null)
  14009. {
  14010. lock(m_cachedMeshes)
  14011. {
  14012. if (!m_cachedMeshes.ContainsKey(meshKey))
  14013. m_cachedMeshes.Add(meshKey, mesh);
  14014. }
  14015. }
  14016. }
  14017. // Check mesh for ray hits
  14018. AddRayInFacetedMesh(mesh, rayTrans, ref rayHits);
  14019. mesh = null;
  14020. }
  14021. }
  14022. );
  14023. }
  14024. // Check terrain filter
  14025. if (!rejectLand)
  14026. {
  14027. // Parse terrain
  14028. // Mesh terrain and check bounding box
  14029. List<Tri> triangles = TrisFromHeightmapUnderRay(pos1Ray, pos2Ray, out Vector3 lower, out Vector3 upper);
  14030. lower.Z -= tol;
  14031. upper.Z += tol;
  14032. if ((pos1Ray.Z >= lower.Z || pos2Ray.Z >= lower.Z) && (pos1Ray.Z <= upper.Z || pos2Ray.Z <= upper.Z))
  14033. {
  14034. // Prepare data needed to check for ray hits
  14035. RayTrans rayTrans = new()
  14036. {
  14037. PartId = UUID.Zero,
  14038. GroupId = UUID.Zero,
  14039. Link = 0,
  14040. ScalePart = new Vector3(1.0f, 1.0f, 1.0f),
  14041. PositionPart = Vector3.Zero,
  14042. RotationPart = Quaternion.Identity,
  14043. ShapeNeedsEnds = true,
  14044. Position1Ray = pos1Ray,
  14045. Position1RayProj = pos1Ray,
  14046. VectorRayProj = vecRay
  14047. };
  14048. // Check mesh
  14049. AddRayInTris(triangles, rayTrans, ref rayHits);
  14050. triangles = null;
  14051. }
  14052. }
  14053. // Sort hits by ascending distance
  14054. rayHits.Sort((s1, s2) => s1.Distance.CompareTo(s2.Distance));
  14055. // Check excess hits per part and group
  14056. for (int t = 0; t < 2; t++)
  14057. {
  14058. int maxHitsPerType = 0;
  14059. UUID id = UUID.Zero;
  14060. if (t == 0)
  14061. maxHitsPerType = m_maxHitsPerPrimInCastRay;
  14062. else
  14063. maxHitsPerType = m_maxHitsPerObjectInCastRay;
  14064. // Handle excess hits only when needed
  14065. if (maxHitsPerType < m_maxHitsInCastRay)
  14066. {
  14067. // Find excess hits
  14068. Hashtable hits = new();
  14069. for (int i = rayHits.Count - 1; i >= 0; i--)
  14070. {
  14071. if (t == 0)
  14072. id = rayHits[i].PartId;
  14073. else
  14074. id = rayHits[i].GroupId;
  14075. if (hits.ContainsKey(id))
  14076. hits[id] = (int)hits[id] + 1;
  14077. else
  14078. hits[id] = 1;
  14079. }
  14080. // Remove excess hits
  14081. for (int i = rayHits.Count - 1; i >= 0; i--)
  14082. {
  14083. if (t == 0)
  14084. id = rayHits[i].PartId;
  14085. else
  14086. id = rayHits[i].GroupId;
  14087. int hit = (int)hits[id];
  14088. if (hit > m_maxHitsPerPrimInCastRay)
  14089. {
  14090. rayHits.RemoveAt(i);
  14091. hit--;
  14092. hits[id] = hit;
  14093. }
  14094. }
  14095. }
  14096. }
  14097. // Parse hits into result list according to data flags
  14098. int hitCount = rayHits.Count;
  14099. if (hitCount > maxHits)
  14100. hitCount = maxHits;
  14101. for (int i = 0; i < hitCount; i++)
  14102. {
  14103. RayHit rayHit = rayHits[i];
  14104. if (getRootKey)
  14105. result.Add(new LSL_Key(rayHit.GroupId.ToString()));
  14106. else
  14107. result.Add(new LSL_Key(rayHit.PartId.ToString()));
  14108. result.Add(new LSL_Vector(rayHit.Position));
  14109. if (getLinkNum)
  14110. result.Add(new LSL_Integer(rayHit.Link));
  14111. if (getNormal)
  14112. result.Add(new LSL_Vector(rayHit.Normal));
  14113. }
  14114. result.Add(new LSL_Integer(hitCount));
  14115. // Add to throttle data
  14116. stopWatch.Stop();
  14117. lock (m_castRayCalls)
  14118. {
  14119. CastRayCall castRayCall = new()
  14120. {
  14121. RegionId = regionId,
  14122. UserId = userId,
  14123. CalledMs = calledMs,
  14124. UsedMs = (int)stopWatch.ElapsedMilliseconds
  14125. };
  14126. m_castRayCalls.Add(castRayCall);
  14127. }
  14128. // Return hits
  14129. return result;
  14130. }
  14131. /// <summary>
  14132. /// Struct for transmitting parameters required for finding llCastRay ray hits.
  14133. /// </summary>
  14134. public struct RayTrans
  14135. {
  14136. public UUID PartId;
  14137. public UUID GroupId;
  14138. public int Link;
  14139. public Vector3 ScalePart;
  14140. public Vector3 PositionPart;
  14141. public Quaternion RotationPart;
  14142. public bool ShapeNeedsEnds;
  14143. public Vector3 Position1Ray;
  14144. public Vector3 Position1RayProj;
  14145. public Vector3 VectorRayProj;
  14146. }
  14147. /// <summary>
  14148. /// Struct for llCastRay ray hits.
  14149. /// </summary>
  14150. public struct RayHit
  14151. {
  14152. public UUID PartId;
  14153. public UUID GroupId;
  14154. public int Link;
  14155. public Vector3 Position;
  14156. public Vector3 Normal;
  14157. public float Distance;
  14158. }
  14159. /// <summary>
  14160. /// Struct for llCastRay throttle data.
  14161. /// </summary>
  14162. public struct CastRayCall
  14163. {
  14164. public UUID RegionId;
  14165. public UUID UserId;
  14166. public int CalledMs;
  14167. public int UsedMs;
  14168. }
  14169. /// <summary>
  14170. /// Helper to check if a ray intersects a shape bounding box.
  14171. /// </summary>
  14172. private bool RayIntersectsShapeBox(Vector3 pos1RayProj, Vector3 pos2RayProj, Vector3 shapeBoxMax)
  14173. {
  14174. // Skip if ray can't intersect bounding box;
  14175. Vector3 rayBoxProjMin = Vector3.Min(pos1RayProj, pos2RayProj);
  14176. Vector3 rayBoxProjMax = Vector3.Max(pos1RayProj, pos2RayProj);
  14177. if (
  14178. rayBoxProjMin.X > shapeBoxMax.X || rayBoxProjMin.Y > shapeBoxMax.Y || rayBoxProjMin.Z > shapeBoxMax.Z ||
  14179. rayBoxProjMax.X < -shapeBoxMax.X || rayBoxProjMax.Y < -shapeBoxMax.Y || rayBoxProjMax.Z < -shapeBoxMax.Z
  14180. )
  14181. return false;
  14182. // Check if ray intersect any bounding box side
  14183. int sign;
  14184. float dist;
  14185. Vector3 posProj;
  14186. Vector3 vecRayProj = pos2RayProj - pos1RayProj;
  14187. // Check both X sides unless ray is parallell to them
  14188. if (Math.Abs(vecRayProj.X) > m_floatToleranceInCastRay)
  14189. {
  14190. for (sign = -1; sign <= 1; sign += 2)
  14191. {
  14192. dist = ((float)sign * shapeBoxMax.X - pos1RayProj.X) / vecRayProj.X;
  14193. posProj = pos1RayProj + vecRayProj * dist;
  14194. if (Math.Abs(posProj.Y) <= shapeBoxMax.Y && Math.Abs(posProj.Z) <= shapeBoxMax.Z)
  14195. return true;
  14196. }
  14197. }
  14198. // Check both Y sides unless ray is parallell to them
  14199. if (Math.Abs(vecRayProj.Y) > m_floatToleranceInCastRay)
  14200. {
  14201. for (sign = -1; sign <= 1; sign += 2)
  14202. {
  14203. dist = ((float)sign * shapeBoxMax.Y - pos1RayProj.Y) / vecRayProj.Y;
  14204. posProj = pos1RayProj + vecRayProj * dist;
  14205. if (Math.Abs(posProj.X) <= shapeBoxMax.X && Math.Abs(posProj.Z) <= shapeBoxMax.Z)
  14206. return true;
  14207. }
  14208. }
  14209. // Check both Z sides unless ray is parallell to them
  14210. if (Math.Abs(vecRayProj.Z) > m_floatToleranceInCastRay)
  14211. {
  14212. for (sign = -1; sign <= 1; sign += 2)
  14213. {
  14214. dist = ((float)sign * shapeBoxMax.Z - pos1RayProj.Z) / vecRayProj.Z;
  14215. posProj = pos1RayProj + vecRayProj * dist;
  14216. if (Math.Abs(posProj.X) <= shapeBoxMax.X && Math.Abs(posProj.Y) <= shapeBoxMax.Y)
  14217. return true;
  14218. }
  14219. }
  14220. // No hits on bounding box so return false
  14221. return false;
  14222. }
  14223. /// <summary>
  14224. /// Helper to parse FacetedMesh for ray hits.
  14225. /// </summary>
  14226. private void AddRayInFacetedMesh(FacetedMesh mesh, RayTrans rayTrans, ref List<RayHit> rayHits)
  14227. {
  14228. if (mesh != null)
  14229. {
  14230. foreach (Face face in mesh.Faces)
  14231. {
  14232. for (int i = 0; i < face.Indices.Count; i += 3)
  14233. {
  14234. Tri triangle = new()
  14235. {
  14236. p1 = face.Vertices[face.Indices[i]].Position,
  14237. p2 = face.Vertices[face.Indices[i + 1]].Position,
  14238. p3 = face.Vertices[face.Indices[i + 2]].Position
  14239. };
  14240. AddRayInTri(triangle, rayTrans, ref rayHits);
  14241. }
  14242. }
  14243. }
  14244. }
  14245. /// <summary>
  14246. /// Helper to parse Tri (triangle) List for ray hits.
  14247. /// </summary>
  14248. private void AddRayInTris(List<Tri> triangles, RayTrans rayTrans, ref List<RayHit> rayHits)
  14249. {
  14250. foreach (Tri triangle in triangles)
  14251. {
  14252. AddRayInTri(triangle, rayTrans, ref rayHits);
  14253. }
  14254. }
  14255. /// <summary>
  14256. /// Helper to add ray hit in a Tri (triangle).
  14257. /// </summary>
  14258. private void AddRayInTri(Tri triProj, RayTrans rayTrans, ref List<RayHit> rayHits)
  14259. {
  14260. // Check for hit in triangle
  14261. if (HitRayInTri(triProj, rayTrans.Position1RayProj, rayTrans.VectorRayProj, out Vector3 posHitProj, out Vector3 normalProj))
  14262. {
  14263. // Hack to circumvent ghost face bug in PrimMesher by removing hits in (ghost) face plane through shape center
  14264. if (Math.Abs(Vector3.Dot(posHitProj, normalProj)) < m_floatToleranceInCastRay && !rayTrans.ShapeNeedsEnds)
  14265. return;
  14266. // Transform hit and normal to region coordinate system
  14267. Vector3 posHit = rayTrans.PositionPart + (posHitProj * rayTrans.ScalePart) * rayTrans.RotationPart;
  14268. Vector3 normal = Vector3.Normalize((normalProj * rayTrans.ScalePart) * rayTrans.RotationPart);
  14269. // Remove duplicate hits at triangle intersections
  14270. float distance = Vector3.Distance(rayTrans.Position1Ray, posHit);
  14271. for (int i = rayHits.Count - 1; i >= 0; i--)
  14272. {
  14273. if (rayHits[i].PartId != rayTrans.PartId)
  14274. break;
  14275. if (Math.Abs(rayHits[i].Distance - distance) < m_floatTolerance2InCastRay)
  14276. return;
  14277. }
  14278. // Build result data set
  14279. RayHit rayHit = new()
  14280. {
  14281. PartId = rayTrans.PartId,
  14282. GroupId = rayTrans.GroupId,
  14283. Link = rayTrans.Link,
  14284. Position = posHit,
  14285. Normal = normal,
  14286. Distance = distance
  14287. };
  14288. rayHits.Add(rayHit);
  14289. }
  14290. }
  14291. /// <summary>
  14292. /// Helper to find ray hit in triangle
  14293. /// </summary>
  14294. bool HitRayInTri(Tri triProj, Vector3 pos1RayProj, Vector3 vecRayProj, out Vector3 posHitProj, out Vector3 normalProj)
  14295. {
  14296. float tol = m_floatToleranceInCastRay;
  14297. posHitProj = Vector3.Zero;
  14298. // Calculate triangle edge vectors
  14299. Vector3 vec1Proj = triProj.p2 - triProj.p1;
  14300. Vector3 vec2Proj = triProj.p3 - triProj.p2;
  14301. Vector3 vec3Proj = triProj.p1 - triProj.p3;
  14302. // Calculate triangle normal
  14303. normalProj = Vector3.Cross(vec1Proj, vec2Proj);
  14304. // Skip if degenerate triangle or ray parallell with triangle plane
  14305. float divisor = Vector3.Dot(vecRayProj, normalProj);
  14306. if (Math.Abs(divisor) < tol)
  14307. return false;
  14308. // Skip if exit and not configured to detect
  14309. if (divisor > tol && !m_detectExitsInCastRay)
  14310. return false;
  14311. // Skip if outside ray ends
  14312. float distanceProj = Vector3.Dot(triProj.p1 - pos1RayProj, normalProj) / divisor;
  14313. if (distanceProj < -tol || distanceProj > 1 + tol)
  14314. return false;
  14315. // Calculate hit position in triangle
  14316. posHitProj = pos1RayProj + vecRayProj * distanceProj;
  14317. // Skip if outside triangle bounding box
  14318. Vector3 triProjMin = Vector3.Min(Vector3.Min(triProj.p1, triProj.p2), triProj.p3);
  14319. Vector3 triProjMax = Vector3.Max(Vector3.Max(triProj.p1, triProj.p2), triProj.p3);
  14320. if (
  14321. posHitProj.X < triProjMin.X - tol || posHitProj.Y < triProjMin.Y - tol || posHitProj.Z < triProjMin.Z - tol ||
  14322. posHitProj.X > triProjMax.X + tol || posHitProj.Y > triProjMax.Y + tol || posHitProj.Z > triProjMax.Z + tol
  14323. )
  14324. return false;
  14325. // Skip if outside triangle
  14326. if (
  14327. Vector3.Dot(Vector3.Cross(vec1Proj, normalProj), posHitProj - triProj.p1) > tol ||
  14328. Vector3.Dot(Vector3.Cross(vec2Proj, normalProj), posHitProj - triProj.p2) > tol ||
  14329. Vector3.Dot(Vector3.Cross(vec3Proj, normalProj), posHitProj - triProj.p3) > tol
  14330. )
  14331. return false;
  14332. // Return hit
  14333. return true;
  14334. }
  14335. /// <summary>
  14336. /// Helper to parse selected parts of HeightMap into a Tri (triangle) List and calculate bounding box.
  14337. /// </summary>
  14338. private List<Tri> TrisFromHeightmapUnderRay(Vector3 posStart, Vector3 posEnd, out Vector3 lower, out Vector3 upper)
  14339. {
  14340. // Get bounding X-Y rectangle of terrain under ray
  14341. lower = Vector3.Min(posStart, posEnd);
  14342. upper = Vector3.Max(posStart, posEnd);
  14343. lower.X = (float)Math.Floor(lower.X);
  14344. lower.Y = (float)Math.Floor(lower.Y);
  14345. float zLower = float.MaxValue;
  14346. upper.X = (float)Math.Ceiling(upper.X);
  14347. upper.Y = (float)Math.Ceiling(upper.Y);
  14348. float zUpper = float.MinValue;
  14349. // Initialize Tri (triangle) List
  14350. List<Tri> triangles = new();
  14351. // Set parsing lane direction to major ray X-Y axis
  14352. Vector3 vec = posEnd - posStart;
  14353. float xAbs = Math.Abs(vec.X);
  14354. float yAbs = Math.Abs(vec.Y);
  14355. bool bigX = true;
  14356. if (yAbs > xAbs)
  14357. {
  14358. bigX = false;
  14359. vec /= yAbs;
  14360. }
  14361. else if (xAbs > yAbs || xAbs > 0.0f)
  14362. vec /= xAbs;
  14363. else
  14364. vec = new Vector3(1.0f, 1.0f, 0.0f);
  14365. // Simplify by start parsing in lower end of lane
  14366. if ((bigX && vec.X < 0.0f) || (!bigX && vec.Y < 0.0f))
  14367. {
  14368. Vector3 posTemp = posStart;
  14369. posStart = posEnd;
  14370. posEnd = posTemp;
  14371. vec *= -1.0f;
  14372. }
  14373. // First 1x1 rectangle under ray
  14374. float xFloorOld;
  14375. float yFloorOld;
  14376. Vector3 pos = posStart;
  14377. float xFloor = (float)Math.Floor(pos.X);
  14378. float yFloor = (float)Math.Floor(pos.Y);
  14379. AddTrisFromHeightmap(xFloor, yFloor, ref triangles, ref zLower, ref zUpper);
  14380. // Parse every remaining 1x1 rectangle under ray
  14381. while (pos != posEnd)
  14382. {
  14383. // Next 1x1 rectangle under ray
  14384. xFloorOld = xFloor;
  14385. yFloorOld = yFloor;
  14386. pos += vec;
  14387. // Clip position to 1x1 rectangle border
  14388. xFloor = (float)Math.Floor(pos.X);
  14389. yFloor = (float)Math.Floor(pos.Y);
  14390. if (bigX && pos.X > xFloor)
  14391. {
  14392. pos.Y -= vec.Y * (pos.X - xFloor);
  14393. pos.X = xFloor;
  14394. }
  14395. else if (!bigX && pos.Y > yFloor)
  14396. {
  14397. pos.X -= vec.X * (pos.Y - yFloor);
  14398. pos.Y = yFloor;
  14399. }
  14400. // Last 1x1 rectangle under ray
  14401. if ((bigX && pos.X >= posEnd.X) || (!bigX && pos.Y >= posEnd.Y))
  14402. {
  14403. pos = posEnd;
  14404. xFloor = (float)Math.Floor(pos.X);
  14405. yFloor = (float)Math.Floor(pos.Y);
  14406. }
  14407. // Add new 1x1 rectangle in lane
  14408. if ((bigX && xFloor != xFloorOld) || (!bigX && yFloor != yFloorOld))
  14409. AddTrisFromHeightmap(xFloor, yFloor, ref triangles, ref zLower, ref zUpper);
  14410. // Add last 1x1 rectangle in old lane at lane shift
  14411. if (bigX && yFloor != yFloorOld)
  14412. AddTrisFromHeightmap(xFloor, yFloorOld, ref triangles, ref zLower, ref zUpper);
  14413. if (!bigX && xFloor != xFloorOld)
  14414. AddTrisFromHeightmap(xFloorOld, yFloor, ref triangles, ref zLower, ref zUpper);
  14415. }
  14416. // Finalize bounding box Z
  14417. lower.Z = zLower;
  14418. upper.Z = zUpper;
  14419. // Done and returning Tri (triangle)List
  14420. return triangles;
  14421. }
  14422. /// <summary>
  14423. /// Helper to add HeightMap squares into Tri (triangle) List and adjust bounding box.
  14424. /// </summary>
  14425. private void AddTrisFromHeightmap(float xPos, float yPos, ref List<Tri> triangles, ref float zLower, ref float zUpper)
  14426. {
  14427. int xInt = (int)xPos;
  14428. int yInt = (int)yPos;
  14429. // Corner 1 of 1x1 rectangle
  14430. int x = Math.Clamp(xInt+1, 0, World.Heightmap.Width - 1);
  14431. int y = Math.Clamp(yInt+1, 0, World.Heightmap.Height - 1);
  14432. Vector3 pos1 = new(x, y, (float)World.Heightmap[x, y]);
  14433. // Adjust bounding box
  14434. zLower = Math.Min(zLower, pos1.Z);
  14435. zUpper = Math.Max(zUpper, pos1.Z);
  14436. // Corner 2 of 1x1 rectangle
  14437. x = Math.Clamp(xInt, 0, World.Heightmap.Width - 1);
  14438. y = Math.Clamp(yInt+1, 0, World.Heightmap.Height - 1);
  14439. Vector3 pos2 = new(x, y, (float)World.Heightmap[x, y]);
  14440. // Adjust bounding box
  14441. zLower = Math.Min(zLower, pos2.Z);
  14442. zUpper = Math.Max(zUpper, pos2.Z);
  14443. // Corner 3 of 1x1 rectangle
  14444. x = Math.Clamp(xInt, 0, World.Heightmap.Width - 1);
  14445. y = Math.Clamp(yInt, 0, World.Heightmap.Height - 1);
  14446. Vector3 pos3 = new(x, y, (float)World.Heightmap[x, y]);
  14447. // Adjust bounding box
  14448. zLower = Math.Min(zLower, pos3.Z);
  14449. zUpper = Math.Max(zUpper, pos3.Z);
  14450. // Corner 4 of 1x1 rectangle
  14451. x = Math.Clamp(xInt+1, 0, World.Heightmap.Width - 1);
  14452. y = Math.Clamp(yInt, 0, World.Heightmap.Height - 1);
  14453. Vector3 pos4 = new(x, y, (float)World.Heightmap[x, y]);
  14454. // Adjust bounding box
  14455. zLower = Math.Min(zLower, pos4.Z);
  14456. zUpper = Math.Max(zUpper, pos4.Z);
  14457. // Add triangle 1
  14458. Tri triangle1 = new()
  14459. {
  14460. p1 = pos1,
  14461. p2 = pos2,
  14462. p3 = pos3
  14463. };
  14464. triangles.Add(triangle1);
  14465. // Add triangle 2
  14466. Tri triangle2 = new()
  14467. {
  14468. p1 = pos3,
  14469. p2 = pos4,
  14470. p3 = pos1
  14471. };
  14472. triangles.Add(triangle2);
  14473. }
  14474. /// <summary>
  14475. /// Helper to get link number for a UUID.
  14476. /// </summary>
  14477. private static int UUID2LinkNumber(SceneObjectPart part, UUID id)
  14478. {
  14479. SceneObjectGroup group = part.ParentGroup;
  14480. if (group is not null)
  14481. {
  14482. SceneObjectPart sop = group.GetPart(id);
  14483. if(sop is not null)
  14484. return sop.LinkNum;
  14485. if(group.GetSittingAvatarsCount() > 0)
  14486. {
  14487. List<ScenePresence> sps = group.GetSittingAvatars();
  14488. int ln = group.PrimCount;
  14489. foreach (ScenePresence sp in sps)
  14490. {
  14491. if(sp.UUID.Equals(id))
  14492. return ln;
  14493. ++ln;
  14494. }
  14495. }
  14496. }
  14497. // Return link number 0 if no links or UUID matches
  14498. return 0;
  14499. }
  14500. public LSL_Integer llManageEstateAccess(int action, string avatar)
  14501. {
  14502. if (!UUID.TryParse(avatar, out UUID id) || id.IsZero())
  14503. return 0;
  14504. EstateSettings estate = World.RegionInfo.EstateSettings;
  14505. if (!estate.IsEstateOwner(m_host.OwnerID) || !estate.IsEstateManagerOrOwner(m_host.OwnerID))
  14506. return 0;
  14507. UserAccount account = m_userAccountService.GetUserAccount(RegionScopeID, id);
  14508. bool isAccount = account is not null;
  14509. bool isGroup = false;
  14510. if (!isAccount)
  14511. {
  14512. IGroupsModule groups = World.RequestModuleInterface<IGroupsModule>();
  14513. if (groups is not null)
  14514. {
  14515. GroupRecord group = groups.GetGroupRecord(id);
  14516. isGroup = group is not null;
  14517. if (!isGroup)
  14518. return 0;
  14519. }
  14520. else
  14521. return 0;
  14522. }
  14523. switch (action)
  14524. {
  14525. case ScriptBaseClass.ESTATE_ACCESS_ALLOWED_AGENT_ADD:
  14526. if (!isAccount) return 0;
  14527. if (estate.HasAccess(id)) return 1;
  14528. if (estate.IsBanned(id, World.GetUserFlags(id)))
  14529. estate.RemoveBan(id);
  14530. estate.AddEstateUser(id);
  14531. break;
  14532. case ScriptBaseClass.ESTATE_ACCESS_ALLOWED_AGENT_REMOVE:
  14533. if (!isAccount || !estate.HasAccess(id)) return 0;
  14534. estate.RemoveEstateUser(id);
  14535. break;
  14536. case ScriptBaseClass.ESTATE_ACCESS_ALLOWED_GROUP_ADD:
  14537. if (!isGroup) return 0;
  14538. if (estate.GroupAccess(id)) return 1;
  14539. estate.AddEstateGroup(id);
  14540. break;
  14541. case ScriptBaseClass.ESTATE_ACCESS_ALLOWED_GROUP_REMOVE:
  14542. if (!isGroup || !estate.GroupAccess(id)) return 0;
  14543. estate.RemoveEstateGroup(id);
  14544. break;
  14545. case ScriptBaseClass.ESTATE_ACCESS_BANNED_AGENT_ADD:
  14546. if (!isAccount) return 0;
  14547. if (estate.IsBanned(id, World.GetUserFlags(id))) return 1;
  14548. EstateBan ban = new()
  14549. {
  14550. EstateID = estate.EstateID,
  14551. BannedUserID = id
  14552. };
  14553. estate.AddBan(ban);
  14554. break;
  14555. case ScriptBaseClass.ESTATE_ACCESS_BANNED_AGENT_REMOVE:
  14556. if (!isAccount || !estate.IsBanned(id, World.GetUserFlags(id))) return 0;
  14557. estate.RemoveBan(id);
  14558. break;
  14559. default: return 0;
  14560. }
  14561. return 1;
  14562. }
  14563. public LSL_Integer llGetMemoryLimit()
  14564. {
  14565. // The value returned for Mono scripts in SL
  14566. return 65536;
  14567. }
  14568. public LSL_Integer llSetMemoryLimit(LSL_Integer limit)
  14569. {
  14570. // Treat as an LSO script
  14571. return ScriptBaseClass.FALSE;
  14572. }
  14573. public LSL_Integer llGetSPMaxMemory()
  14574. {
  14575. // The value returned for Mono scripts in SL
  14576. return 65536;
  14577. }
  14578. public virtual LSL_Integer llGetUsedMemory()
  14579. {
  14580. // The value returned for Mono scripts in SL
  14581. return 65536;
  14582. }
  14583. public void llScriptProfiler(LSL_Integer flags)
  14584. {
  14585. // This does nothing for LSO scripts in SL
  14586. }
  14587. public void llSetSoundQueueing(int queue)
  14588. {
  14589. m_SoundModule?.SetSoundQueueing(m_host.UUID, queue == ScriptBaseClass.TRUE.value);
  14590. }
  14591. public void llLinkSetSoundQueueing(int linknumber, int queue)
  14592. {
  14593. if (m_SoundModule is not null)
  14594. {
  14595. foreach (SceneObjectPart sop in GetLinkParts(linknumber))
  14596. m_SoundModule.SetSoundQueueing(sop.UUID, queue == ScriptBaseClass.TRUE.value);
  14597. }
  14598. }
  14599. #region Not Implemented
  14600. //
  14601. // Listing the unimplemented lsl functions here, please move
  14602. // them from this region as they are completed
  14603. //
  14604. public void llCollisionSprite(LSL_String impact_sprite)
  14605. {
  14606. // Viewer 2.0 broke this and it's likely LL has no intention
  14607. // of fixing it. Therefore, letting this be a NOP seems appropriate.
  14608. }
  14609. public void llGodLikeRezObject(string inventory, LSL_Vector pos)
  14610. {
  14611. if (!World.Permissions.IsGod(m_host.OwnerID))
  14612. NotImplemented("llGodLikeRezObject");
  14613. AssetBase rezAsset = World.AssetService.Get(inventory);
  14614. if (rezAsset == null)
  14615. {
  14616. llSay(0, "Asset not found");
  14617. return;
  14618. }
  14619. SceneObjectGroup group;
  14620. try
  14621. {
  14622. string xmlData = Utils.BytesToString(rezAsset.Data);
  14623. group = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
  14624. }
  14625. catch
  14626. {
  14627. llSay(0, "Asset not found");
  14628. return;
  14629. }
  14630. if (group == null)
  14631. {
  14632. llSay(0, "Asset not found");
  14633. return;
  14634. }
  14635. group.RootPart.AttachedPos = group.AbsolutePosition;
  14636. group.ResetIDs();
  14637. Vector3 llpos = new((float)pos.x, (float)pos.y, (float)pos.z);
  14638. World.AddNewSceneObject(group, true, llpos, Quaternion.Identity, Vector3.Zero);
  14639. group.CreateScriptInstances(0, true, World.DefaultScriptEngine, 3);
  14640. group.ScheduleGroupForFullUpdate();
  14641. // objects rezzed with this method are die_at_edge by default.
  14642. group.RootPart.SetDieAtEdge(true);
  14643. group.ResumeScripts();
  14644. m_ScriptEngine.PostObjectEvent(m_host.LocalId, new EventParams(
  14645. "object_rez", new Object[] {
  14646. new LSL_String(
  14647. group.RootPart.UUID.ToString()) },
  14648. Array.Empty<DetectParams>()));
  14649. }
  14650. public LSL_Key llTransferLindenDollars(LSL_Key destination, LSL_Integer amount)
  14651. {
  14652. IMoneyModule money = World.RequestModuleInterface<IMoneyModule>();
  14653. UUID txn = UUID.Random();
  14654. UUID toID = UUID.Zero;
  14655. string replydata = "UnKnownError";
  14656. bool bad = true;
  14657. while(true)
  14658. {
  14659. if (amount <= 0)
  14660. {
  14661. replydata = "INVALID_AMOUNT";
  14662. break;
  14663. }
  14664. if (money == null)
  14665. {
  14666. replydata = "TRANSFERS_DISABLED";
  14667. break;
  14668. }
  14669. if (m_host.OwnerID.Equals(m_host.GroupID))
  14670. {
  14671. replydata = "GROUP_OWNED";
  14672. break;
  14673. }
  14674. if (m_item == null)
  14675. {
  14676. replydata = "SERVICE_ERROR";
  14677. break;
  14678. }
  14679. if (m_item.PermsGranter.IsZero())
  14680. {
  14681. replydata = "MISSING_PERMISSION_DEBIT";
  14682. break;
  14683. }
  14684. if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_DEBIT) == 0)
  14685. {
  14686. replydata = "MISSING_PERMISSION_DEBIT";
  14687. break;
  14688. }
  14689. if (!UUID.TryParse(destination, out toID))
  14690. {
  14691. replydata = "INVALID_AGENT";
  14692. break;
  14693. }
  14694. bad = false;
  14695. break;
  14696. }
  14697. if(bad)
  14698. {
  14699. m_ScriptEngine.PostScriptEvent(m_item.ItemID, new EventParams(
  14700. "transaction_result", new Object[] {
  14701. new LSL_String(txn.ToString()),
  14702. new LSL_Integer(0),
  14703. new LSL_String(replydata) },
  14704. Array.Empty<DetectParams>()));
  14705. return txn.ToString();
  14706. }
  14707. //fire and forget...
  14708. void act(string eventID)
  14709. {
  14710. int replycode = 0;
  14711. try
  14712. {
  14713. UserAccount account = m_userAccountService.GetUserAccount(RegionScopeID, toID);
  14714. if (account is null)
  14715. {
  14716. replydata = "LINDENDOLLAR_ENTITYDOESNOTEXIST";
  14717. return;
  14718. }
  14719. bool result = money.ObjectGiveMoney(m_host.ParentGroup.RootPart.UUID, m_host.ParentGroup.RootPart.OwnerID,
  14720. toID, amount, txn, out string reason);
  14721. if (result)
  14722. {
  14723. replycode = 1;
  14724. replydata = destination + "," + amount.ToString();
  14725. return;
  14726. }
  14727. replydata = reason;
  14728. }
  14729. finally
  14730. {
  14731. m_ScriptEngine.PostScriptEvent(m_item.ItemID, new EventParams(
  14732. "transaction_result", new Object[] {
  14733. new LSL_String(txn.ToString()),
  14734. new LSL_Integer(replycode),
  14735. new LSL_String(replydata) },
  14736. Array.Empty<DetectParams>()));
  14737. }
  14738. }
  14739. m_AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, act);
  14740. return txn.ToString();
  14741. }
  14742. #endregion
  14743. protected LSL_List SetPrimParams(ScenePresence av, LSL_List rules, string originFunc, ref uint rulesParsed)
  14744. {
  14745. //This is a special version of SetPrimParams to deal with avatars which are sitting on the linkset.
  14746. int idx = 0;
  14747. int idxStart = 0;
  14748. bool positionChanged = false;
  14749. try
  14750. {
  14751. while (idx < rules.Length)
  14752. {
  14753. ++rulesParsed;
  14754. int code = rules.GetIntegerItem(idx++);
  14755. int remain = rules.Length - idx;
  14756. idxStart = idx;
  14757. switch (code)
  14758. {
  14759. case ScriptBaseClass.PRIM_POSITION:
  14760. case ScriptBaseClass.PRIM_POS_LOCAL:
  14761. {
  14762. if (remain < 1)
  14763. return new LSL_List();
  14764. LSL_Vector v;
  14765. v = rules.GetVector3Item(idx++);
  14766. if(!av.LegacySitOffsets)
  14767. {
  14768. LSL_Vector sitOffset = (llRot2Up(new LSL_Rotation(av.Rotation.X, av.Rotation.Y, av.Rotation.Z, av.Rotation.W)) * av.Appearance.AvatarHeight * 0.02638f);
  14769. v += 2.0 * sitOffset;
  14770. }
  14771. av.OffsetPosition = new Vector3((float)v.x, (float)v.y, (float)v.z);
  14772. positionChanged = true;
  14773. }
  14774. break;
  14775. case ScriptBaseClass.PRIM_ROTATION:
  14776. {
  14777. if (remain < 1)
  14778. return new LSL_List();
  14779. Quaternion r;
  14780. r = rules.GetQuaternionItem(idx++);
  14781. av.Rotation = m_host.GetWorldRotation() * r;
  14782. positionChanged = true;
  14783. }
  14784. break;
  14785. case ScriptBaseClass.PRIM_ROT_LOCAL:
  14786. {
  14787. if (remain < 1)
  14788. return new LSL_List();
  14789. LSL_Rotation r;
  14790. r = rules.GetQuaternionItem(idx++);
  14791. av.Rotation = r;
  14792. positionChanged = true;
  14793. }
  14794. break;
  14795. // parse rest doing nothing but number of parameters error check
  14796. case ScriptBaseClass.PRIM_SIZE:
  14797. case ScriptBaseClass.PRIM_MATERIAL:
  14798. case ScriptBaseClass.PRIM_PHANTOM:
  14799. case ScriptBaseClass.PRIM_PHYSICS:
  14800. case ScriptBaseClass.PRIM_PHYSICS_SHAPE_TYPE:
  14801. case ScriptBaseClass.PRIM_TEMP_ON_REZ:
  14802. case ScriptBaseClass.PRIM_NAME:
  14803. case ScriptBaseClass.PRIM_DESC:
  14804. if (remain < 1)
  14805. return new LSL_List();
  14806. idx++;
  14807. break;
  14808. case ScriptBaseClass.PRIM_GLOW:
  14809. case ScriptBaseClass.PRIM_FULLBRIGHT:
  14810. case ScriptBaseClass.PRIM_TEXGEN:
  14811. if (remain < 2)
  14812. return new LSL_List();
  14813. idx += 2;
  14814. break;
  14815. case ScriptBaseClass.PRIM_TYPE:
  14816. if (remain < 3)
  14817. return new LSL_List();
  14818. code = (int)rules.GetIntegerItem(idx++);
  14819. remain = rules.Length - idx;
  14820. switch (code)
  14821. {
  14822. case ScriptBaseClass.PRIM_TYPE_BOX:
  14823. case ScriptBaseClass.PRIM_TYPE_CYLINDER:
  14824. case ScriptBaseClass.PRIM_TYPE_PRISM:
  14825. if (remain < 6)
  14826. return new LSL_List();
  14827. idx += 6;
  14828. break;
  14829. case ScriptBaseClass.PRIM_TYPE_SPHERE:
  14830. if (remain < 5)
  14831. return new LSL_List();
  14832. idx += 5;
  14833. break;
  14834. case ScriptBaseClass.PRIM_TYPE_TORUS:
  14835. case ScriptBaseClass.PRIM_TYPE_TUBE:
  14836. case ScriptBaseClass.PRIM_TYPE_RING:
  14837. if (remain < 11)
  14838. return new LSL_List();
  14839. idx += 11;
  14840. break;
  14841. case ScriptBaseClass.PRIM_TYPE_SCULPT:
  14842. if (remain < 2)
  14843. return new LSL_List();
  14844. idx += 2;
  14845. break;
  14846. }
  14847. break;
  14848. case ScriptBaseClass.PRIM_COLOR:
  14849. case ScriptBaseClass.PRIM_TEXT:
  14850. case ScriptBaseClass.PRIM_BUMP_SHINY:
  14851. case ScriptBaseClass.PRIM_OMEGA:
  14852. case ScriptBaseClass.PRIM_SIT_TARGET:
  14853. if (remain < 3)
  14854. return new LSL_List();
  14855. idx += 3;
  14856. break;
  14857. case ScriptBaseClass.PRIM_TEXTURE:
  14858. case ScriptBaseClass.PRIM_POINT_LIGHT:
  14859. case ScriptBaseClass.PRIM_PHYSICS_MATERIAL:
  14860. if (remain < 5)
  14861. return new LSL_List();
  14862. idx += 5;
  14863. break;
  14864. case ScriptBaseClass.PRIM_FLEXIBLE:
  14865. if (remain < 7)
  14866. return new LSL_List();
  14867. idx += 7;
  14868. break;
  14869. case ScriptBaseClass.PRIM_LINK_TARGET:
  14870. if (remain < 3) // setting to 3 on the basis that parsing any usage of PRIM_LINK_TARGET that has nothing following it is pointless.
  14871. return new LSL_List();
  14872. return rules.GetSublist(idx, -1);
  14873. }
  14874. }
  14875. }
  14876. catch (InvalidCastException e)
  14877. {
  14878. Error(originFunc,string.Format(
  14879. " error running rule #{0}: arg #{1} {2}",
  14880. rulesParsed, idx - idxStart, e.Message));
  14881. }
  14882. finally
  14883. {
  14884. if (positionChanged)
  14885. av.SendTerseUpdateToAllClients();
  14886. }
  14887. return new LSL_List();
  14888. }
  14889. public LSL_List GetPrimParams(ScenePresence avatar, LSL_List rules, ref LSL_List res)
  14890. {
  14891. // avatars case
  14892. // replies as SL wiki
  14893. // SceneObjectPart sitPart = avatar.ParentPart; // most likelly it will be needed
  14894. SceneObjectPart sitPart = World.GetSceneObjectPart(avatar.ParentID); // maybe better do this expensive search for it in case it's gone??
  14895. int idx = 0;
  14896. while (idx < rules.Length)
  14897. {
  14898. int code = rules.GetIntegerItem(idx++);
  14899. int remain = rules.Length - idx;
  14900. switch (code)
  14901. {
  14902. case ScriptBaseClass.PRIM_MATERIAL:
  14903. res.Add(new LSL_Integer((int)SOPMaterialData.SopMaterial.Flesh));
  14904. break;
  14905. case ScriptBaseClass.PRIM_PHYSICS:
  14906. res.Add(new LSL_Integer(0));
  14907. break;
  14908. case ScriptBaseClass.PRIM_TEMP_ON_REZ:
  14909. res.Add(new LSL_Integer(0));
  14910. break;
  14911. case ScriptBaseClass.PRIM_PHANTOM:
  14912. res.Add(new LSL_Integer(0));
  14913. break;
  14914. case ScriptBaseClass.PRIM_POSITION:
  14915. Vector3 pos;
  14916. if (sitPart.ParentGroup.RootPart != null)
  14917. {
  14918. pos = avatar.OffsetPosition;
  14919. if(!avatar.LegacySitOffsets)
  14920. {
  14921. Vector3 sitOffset = (Zrot(avatar.Rotation)) * (avatar.Appearance.AvatarHeight * 0.02638f *2.0f);
  14922. pos -= sitOffset;
  14923. }
  14924. SceneObjectPart sitroot = sitPart.ParentGroup.RootPart;
  14925. pos = sitroot.AbsolutePosition + pos * sitroot.GetWorldRotation();
  14926. }
  14927. else
  14928. pos = avatar.AbsolutePosition;
  14929. res.Add(new LSL_Vector(pos.X,pos.Y,pos.Z));
  14930. break;
  14931. case ScriptBaseClass.PRIM_SIZE:
  14932. Vector3 s = avatar.Appearance.AvatarSize;
  14933. res.Add(new LSL_Vector(s.X, s.Y, s.Z));
  14934. break;
  14935. case ScriptBaseClass.PRIM_ROTATION:
  14936. res.Add(new LSL_Rotation(avatar.GetWorldRotation()));
  14937. break;
  14938. case ScriptBaseClass.PRIM_TYPE:
  14939. res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TYPE_BOX));
  14940. res.Add(new LSL_Integer(ScriptBaseClass.PRIM_HOLE_DEFAULT));
  14941. res.Add(new LSL_Vector(0f,1.0f,0f));
  14942. res.Add(new LSL_Float(0.0f));
  14943. res.Add(new LSL_Vector(0, 0, 0));
  14944. res.Add(new LSL_Vector(1.0f,1.0f,0f));
  14945. res.Add(new LSL_Vector(0, 0, 0));
  14946. break;
  14947. case ScriptBaseClass.PRIM_TEXTURE:
  14948. if (remain < 1)
  14949. return new LSL_List();
  14950. int face = rules.GetIntegerItem(idx++);
  14951. if (face == ScriptBaseClass.ALL_SIDES)
  14952. {
  14953. for (face = 0; face < 21; face++)
  14954. {
  14955. res.Add(new LSL_String(""));
  14956. res.Add(new LSL_Vector(0,0,0));
  14957. res.Add(new LSL_Vector(0,0,0));
  14958. res.Add(new LSL_Float(0.0));
  14959. }
  14960. }
  14961. else
  14962. {
  14963. if (face >= 0 && face < 21)
  14964. {
  14965. res.Add(new LSL_String(""));
  14966. res.Add(new LSL_Vector(0,0,0));
  14967. res.Add(new LSL_Vector(0,0,0));
  14968. res.Add(new LSL_Float(0.0));
  14969. }
  14970. }
  14971. break;
  14972. case ScriptBaseClass.PRIM_COLOR:
  14973. if (remain < 1)
  14974. return new LSL_List();
  14975. face = rules.GetIntegerItem(idx++);
  14976. if (face == ScriptBaseClass.ALL_SIDES)
  14977. {
  14978. for (face = 0; face < 21; face++)
  14979. {
  14980. res.Add(new LSL_Vector(0,0,0));
  14981. res.Add(new LSL_Float(0));
  14982. }
  14983. }
  14984. else
  14985. {
  14986. res.Add(new LSL_Vector(0,0,0));
  14987. res.Add(new LSL_Float(0));
  14988. }
  14989. break;
  14990. case ScriptBaseClass.PRIM_BUMP_SHINY:
  14991. if (remain < 1)
  14992. return new LSL_List();
  14993. face = rules.GetIntegerItem(idx++);
  14994. if (face == ScriptBaseClass.ALL_SIDES)
  14995. {
  14996. for (face = 0; face < 21; face++)
  14997. {
  14998. res.Add(new LSL_Integer(ScriptBaseClass.PRIM_SHINY_NONE));
  14999. res.Add(new LSL_Integer(ScriptBaseClass.PRIM_BUMP_NONE));
  15000. }
  15001. }
  15002. else
  15003. {
  15004. res.Add(new LSL_Integer(ScriptBaseClass.PRIM_SHINY_NONE));
  15005. res.Add(new LSL_Integer(ScriptBaseClass.PRIM_BUMP_NONE));
  15006. }
  15007. break;
  15008. case ScriptBaseClass.PRIM_FULLBRIGHT:
  15009. if (remain < 1)
  15010. return new LSL_List();
  15011. face = rules.GetIntegerItem(idx++);
  15012. if (face == ScriptBaseClass.ALL_SIDES)
  15013. {
  15014. for (face = 0; face < 21; face++)
  15015. {
  15016. res.Add(new LSL_Integer(ScriptBaseClass.FALSE));
  15017. }
  15018. }
  15019. else
  15020. {
  15021. res.Add(new LSL_Integer(ScriptBaseClass.FALSE));
  15022. }
  15023. break;
  15024. case ScriptBaseClass.PRIM_FLEXIBLE:
  15025. res.Add(new LSL_Integer(0));
  15026. res.Add(new LSL_Integer(0));// softness
  15027. res.Add(new LSL_Float(0.0f)); // gravity
  15028. res.Add(new LSL_Float(0.0f)); // friction
  15029. res.Add(new LSL_Float(0.0f)); // wind
  15030. res.Add(new LSL_Float(0.0f)); // tension
  15031. res.Add(new LSL_Vector(0f,0f,0f));
  15032. break;
  15033. case ScriptBaseClass.PRIM_TEXGEN:
  15034. // (PRIM_TEXGEN_DEFAULT, PRIM_TEXGEN_PLANAR)
  15035. if (remain < 1)
  15036. return new LSL_List();
  15037. face = rules.GetIntegerItem(idx++);
  15038. if (face == ScriptBaseClass.ALL_SIDES)
  15039. {
  15040. for (face = 0; face < 21; face++)
  15041. {
  15042. res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TEXGEN_DEFAULT));
  15043. }
  15044. }
  15045. else
  15046. {
  15047. res.Add(new LSL_Integer(ScriptBaseClass.PRIM_TEXGEN_DEFAULT));
  15048. }
  15049. break;
  15050. case ScriptBaseClass.PRIM_POINT_LIGHT:
  15051. res.Add(new LSL_Integer(0));
  15052. res.Add(new LSL_Vector(0f, 0f, 0f));
  15053. res.Add(new LSL_Float(0f)); // intensity
  15054. res.Add(new LSL_Float(0f)); // radius
  15055. res.Add(new LSL_Float(0f)); // falloff
  15056. break;
  15057. case ScriptBaseClass.PRIM_REFLECTION_PROBE:
  15058. res.Add(new LSL_Integer(0));
  15059. res.Add(new LSL_Float(0f)); // ambiance
  15060. res.Add(new LSL_Float(0f)); // clip
  15061. res.Add(new LSL_Float(0f)); // flags
  15062. break;
  15063. case ScriptBaseClass.PRIM_GLOW:
  15064. if (remain < 1)
  15065. return new LSL_List();
  15066. face = rules.GetIntegerItem(idx++);
  15067. if (face == ScriptBaseClass.ALL_SIDES)
  15068. {
  15069. for (face = 0; face < 21; face++)
  15070. {
  15071. res.Add(new LSL_Float(0f));
  15072. }
  15073. }
  15074. else
  15075. {
  15076. res.Add(new LSL_Float(0f));
  15077. }
  15078. break;
  15079. case ScriptBaseClass.PRIM_TEXT:
  15080. res.Add(new LSL_String(""));
  15081. res.Add(new LSL_Vector(0f,0f,0f));
  15082. res.Add(new LSL_Float(1.0f));
  15083. break;
  15084. case ScriptBaseClass.PRIM_NAME:
  15085. res.Add(new LSL_String(avatar.Name));
  15086. break;
  15087. case ScriptBaseClass.PRIM_DESC:
  15088. res.Add(new LSL_String(""));
  15089. break;
  15090. case ScriptBaseClass.PRIM_ROT_LOCAL:
  15091. Quaternion lrot = avatar.Rotation;
  15092. res.Add(new LSL_Rotation(lrot.X, lrot.Y, lrot.Z, lrot.W));
  15093. break;
  15094. case ScriptBaseClass.PRIM_POS_LOCAL:
  15095. Vector3 lpos = avatar.OffsetPosition;
  15096. if(!avatar.LegacySitOffsets)
  15097. {
  15098. Vector3 lsitOffset = (Zrot(avatar.Rotation)) * (avatar.Appearance.AvatarHeight * 0.02638f * 2.0f);
  15099. lpos -= lsitOffset;
  15100. }
  15101. res.Add(new LSL_Vector(lpos.X,lpos.Y,lpos.Z));
  15102. break;
  15103. case ScriptBaseClass.PRIM_LINK_TARGET:
  15104. if (remain < 3) // setting to 3 on the basis that parsing any usage of PRIM_LINK_TARGET that has nothing following it is pointless.
  15105. return new LSL_List();
  15106. return rules.GetSublist(idx, -1);
  15107. }
  15108. }
  15109. return new LSL_List();
  15110. }
  15111. public void llSetAnimationOverride(LSL_String animState, LSL_String anim)
  15112. {
  15113. if (m_item.PermsGranter.IsZero())
  15114. {
  15115. llShout(ScriptBaseClass.DEBUG_CHANNEL, "No permission to override animations");
  15116. return;
  15117. }
  15118. if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_OVERRIDE_ANIMATIONS) == 0)
  15119. {
  15120. llShout(ScriptBaseClass.DEBUG_CHANNEL, "No permission to override animations");
  15121. return;
  15122. }
  15123. ScenePresence presence = World.GetScenePresence(m_item.PermsGranter);
  15124. if (presence == null)
  15125. return;
  15126. string state = String.Empty;
  15127. foreach (KeyValuePair<string, string> kvp in MovementAnimationsForLSL)
  15128. {
  15129. if (kvp.Value.ToLower() == ((string)animState).ToLower())
  15130. {
  15131. state = kvp.Key;
  15132. break;
  15133. }
  15134. }
  15135. if (state.Length == 0)
  15136. {
  15137. llShout(ScriptBaseClass.DEBUG_CHANNEL, "Invalid animation state " + animState);
  15138. return;
  15139. }
  15140. UUID animID;
  15141. animID = ScriptUtils.GetAssetIdFromItemName(m_host, anim, (int)AssetType.Animation);
  15142. if (animID.IsZero())
  15143. {
  15144. String animupper = ((string)anim).ToUpperInvariant();
  15145. DefaultAvatarAnimations.AnimsUUIDbyName.TryGetValue(animupper, out animID);
  15146. }
  15147. if (animID.IsZero())
  15148. {
  15149. llShout(ScriptBaseClass.DEBUG_CHANNEL, "Animation not found");
  15150. return;
  15151. }
  15152. presence.SetAnimationOverride(state, animID);
  15153. }
  15154. public void llResetAnimationOverride(LSL_String animState)
  15155. {
  15156. ScenePresence presence = World.GetScenePresence(m_item.PermsGranter);
  15157. if (presence == null)
  15158. return;
  15159. if (m_item.PermsGranter.IsZero())
  15160. {
  15161. llShout(ScriptBaseClass.DEBUG_CHANNEL, "No permission to override animations");
  15162. return;
  15163. }
  15164. if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_OVERRIDE_ANIMATIONS) == 0)
  15165. {
  15166. llShout(ScriptBaseClass.DEBUG_CHANNEL, "No permission to override animations");
  15167. return;
  15168. }
  15169. if (animState == "ALL")
  15170. {
  15171. presence.SetAnimationOverride("ALL", UUID.Zero);
  15172. return;
  15173. }
  15174. string state = String.Empty;
  15175. foreach (KeyValuePair<string, string> kvp in MovementAnimationsForLSL)
  15176. {
  15177. if (kvp.Value.ToLower() == ((string)animState).ToLower())
  15178. {
  15179. state = kvp.Key;
  15180. break;
  15181. }
  15182. }
  15183. if (state.Length == 0)
  15184. {
  15185. return;
  15186. }
  15187. presence.SetAnimationOverride(state, UUID.Zero);
  15188. }
  15189. public LSL_String llGetAnimationOverride(LSL_String animState)
  15190. {
  15191. ScenePresence presence = World.GetScenePresence(m_item.PermsGranter);
  15192. if (presence is null)
  15193. return LSL_String.Empty;
  15194. if (m_item.PermsGranter.IsZero())
  15195. {
  15196. llShout(ScriptBaseClass.DEBUG_CHANNEL, "No permission to override animations");
  15197. return LSL_String.Empty;
  15198. }
  15199. if ((m_item.PermsMask & (ScriptBaseClass.PERMISSION_OVERRIDE_ANIMATIONS | ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION)) == 0)
  15200. {
  15201. llShout(ScriptBaseClass.DEBUG_CHANNEL, "No permission to override animations");
  15202. return LSL_String.Empty;
  15203. }
  15204. string state = String.Empty;
  15205. foreach (KeyValuePair<string, string> kvp in MovementAnimationsForLSL)
  15206. {
  15207. if (kvp.Value.ToLower() == ((string)animState).ToLower())
  15208. {
  15209. state = kvp.Key;
  15210. break;
  15211. }
  15212. }
  15213. if (state.Length == 0)
  15214. {
  15215. return LSL_String.Empty;
  15216. }
  15217. if (!presence.TryGetAnimationOverride(state, out UUID animID) || animID.IsZero())
  15218. return animState;
  15219. foreach (KeyValuePair<string, UUID> kvp in DefaultAvatarAnimations.AnimsUUIDbyName)
  15220. {
  15221. if (kvp.Value.Equals(animID))
  15222. return kvp.Key.ToLower();
  15223. }
  15224. foreach (TaskInventoryItem item in m_host.Inventory.GetInventoryItems())
  15225. {
  15226. if (item.AssetID.Equals(animID))
  15227. return item.Name;
  15228. }
  15229. return LSL_String.Empty;
  15230. }
  15231. public LSL_Integer llGetDayLength()
  15232. {
  15233. if (m_envModule == null)
  15234. return 14400;
  15235. return m_envModule.GetDayLength(m_host.GetWorldPosition());
  15236. }
  15237. public LSL_Integer llGetRegionDayLength()
  15238. {
  15239. if (m_envModule == null)
  15240. return 14400;
  15241. return m_envModule.GetRegionDayLength();
  15242. }
  15243. public LSL_Integer llGetDayOffset()
  15244. {
  15245. if (m_envModule == null)
  15246. return 57600;
  15247. return m_envModule.GetDayOffset(m_host.GetWorldPosition());
  15248. }
  15249. public LSL_Integer llGetRegionDayOffset()
  15250. {
  15251. if (m_envModule == null)
  15252. return 57600;
  15253. return m_envModule.GetRegionDayOffset();
  15254. }
  15255. public LSL_Vector llGetSunDirection()
  15256. {
  15257. if (m_envModule == null)
  15258. return Vector3.Zero;
  15259. return m_envModule.GetSunDir(m_host.GetWorldPosition());
  15260. }
  15261. public LSL_Vector llGetRegionSunDirection()
  15262. {
  15263. if (m_envModule == null)
  15264. return Vector3.Zero;
  15265. float z = m_host.GetWorldPosition().Z;
  15266. return m_envModule.GetRegionSunDir(z);
  15267. }
  15268. public LSL_Vector llGetMoonDirection()
  15269. {
  15270. if (m_envModule == null)
  15271. return Vector3.Zero;
  15272. return m_envModule.GetMoonDir(m_host.GetWorldPosition());
  15273. }
  15274. public LSL_Vector llGetRegionMoonDirection()
  15275. {
  15276. if (m_envModule == null)
  15277. return Vector3.Zero;
  15278. float z = m_host.GetWorldPosition().Z;
  15279. return m_envModule.GetRegionMoonDir(z);
  15280. }
  15281. public LSL_Rotation llGetSunRotation()
  15282. {
  15283. if (m_envModule is null)
  15284. return LSL_Rotation.Identity;
  15285. return m_envModule.GetSunRot(m_host.GetWorldPosition());
  15286. }
  15287. public LSL_Rotation llGetRegionSunRotation()
  15288. {
  15289. if (m_envModule is null)
  15290. return LSL_Rotation.Identity;
  15291. float z = m_host.GetWorldPosition().Z;
  15292. return m_envModule.GetRegionSunRot(z);
  15293. }
  15294. public LSL_Rotation llGetMoonRotation()
  15295. {
  15296. if (m_envModule is null)
  15297. return LSL_Rotation.Identity;
  15298. return m_envModule.GetMoonRot(m_host.GetWorldPosition());
  15299. }
  15300. public LSL_Rotation llGetRegionMoonRotation()
  15301. {
  15302. if (m_envModule is null)
  15303. return LSL_Rotation.Identity;
  15304. float z = m_host.GetWorldPosition().Z;
  15305. return m_envModule.GetRegionMoonRot(z);
  15306. }
  15307. public LSL_List llJson2List(LSL_String json)
  15308. {
  15309. if (String.IsNullOrEmpty(json))
  15310. return new LSL_List();
  15311. if(json == "[]")
  15312. return new LSL_List();
  15313. if(json == "{}")
  15314. return new LSL_List();
  15315. char first = ((string)json)[0];
  15316. if(first != '[' && first !='{')
  15317. {
  15318. // we already have a single element
  15319. LSL_List l = new();
  15320. l.Add(json);
  15321. return l;
  15322. }
  15323. LitJson.JsonData jsdata;
  15324. try
  15325. {
  15326. jsdata = LitJson.JsonMapper.ToObject(json);
  15327. }
  15328. catch //(Exception e)
  15329. {
  15330. //string m = e.Message; // debug point
  15331. return json;
  15332. }
  15333. try
  15334. {
  15335. return JsonParseTop(jsdata);
  15336. }
  15337. catch //(Exception e)
  15338. {
  15339. //string m = e.Message; // debug point
  15340. return (LSL_String)ScriptBaseClass.JSON_INVALID;
  15341. }
  15342. }
  15343. private static LSL_List JsonParseTop(LitJson.JsonData elem)
  15344. {
  15345. LSL_List retl = new();
  15346. if(elem is null)
  15347. retl.Add((LSL_String)ScriptBaseClass.JSON_NULL);
  15348. LitJson.JsonType elemType = elem.GetJsonType();
  15349. switch (elemType)
  15350. {
  15351. case LitJson.JsonType.Int:
  15352. retl.Add(new LSL_Integer((int)elem));
  15353. return retl;
  15354. case LitJson.JsonType.Boolean:
  15355. retl.Add((LSL_String)((bool)elem ? ScriptBaseClass.JSON_TRUE : ScriptBaseClass.JSON_FALSE));
  15356. return retl;
  15357. case LitJson.JsonType.Double:
  15358. retl.Add(new LSL_Float((double)elem));
  15359. return retl;
  15360. case LitJson.JsonType.None:
  15361. retl.Add((LSL_String)ScriptBaseClass.JSON_NULL);
  15362. return retl;
  15363. case LitJson.JsonType.String:
  15364. retl.Add(new LSL_String((string)elem));
  15365. return retl;
  15366. case LitJson.JsonType.Array:
  15367. foreach (LitJson.JsonData subelem in elem)
  15368. retl.Add(JsonParseTopNodes(subelem));
  15369. return retl;
  15370. case LitJson.JsonType.Object:
  15371. IDictionaryEnumerator e = ((IOrderedDictionary)elem).GetEnumerator();
  15372. while (e.MoveNext())
  15373. {
  15374. retl.Add(new LSL_String((string)e.Key));
  15375. retl.Add(JsonParseTopNodes((LitJson.JsonData)e.Value));
  15376. }
  15377. return retl;
  15378. default:
  15379. throw new Exception(ScriptBaseClass.JSON_INVALID);
  15380. }
  15381. }
  15382. private static object JsonParseTopNodes(LitJson.JsonData elem)
  15383. {
  15384. if(elem is null)
  15385. return ((LSL_String)ScriptBaseClass.JSON_NULL);
  15386. LitJson.JsonType elemType = elem.GetJsonType();
  15387. switch (elemType)
  15388. {
  15389. case LitJson.JsonType.Int:
  15390. return (new LSL_Integer((int)elem));
  15391. case LitJson.JsonType.Boolean:
  15392. return ((bool)elem ? (LSL_String)ScriptBaseClass.JSON_TRUE : (LSL_String)ScriptBaseClass.JSON_FALSE);
  15393. case LitJson.JsonType.Double:
  15394. return (new LSL_Float((double)elem));
  15395. case LitJson.JsonType.None:
  15396. return ((LSL_String)ScriptBaseClass.JSON_NULL);
  15397. case LitJson.JsonType.String:
  15398. return (new LSL_String((string)elem));
  15399. case LitJson.JsonType.Array:
  15400. case LitJson.JsonType.Object:
  15401. string s = LitJson.JsonMapper.ToJson(elem);
  15402. return (LSL_String)s;
  15403. default:
  15404. throw new Exception(ScriptBaseClass.JSON_INVALID);
  15405. }
  15406. }
  15407. public LSL_String llList2Json(LSL_String type, LSL_List values)
  15408. {
  15409. try
  15410. {
  15411. StringBuilder sb = new();
  15412. if (type == ScriptBaseClass.JSON_ARRAY)
  15413. {
  15414. sb.Append('[');
  15415. int i= 0;
  15416. foreach (object o in values.Data)
  15417. {
  15418. sb.Append(ListToJson(o));
  15419. if((i++) < values.Data.Length - 1)
  15420. sb.Append(',');
  15421. }
  15422. sb.Append(']');
  15423. return (LSL_String)sb.ToString();
  15424. }
  15425. else if (type == ScriptBaseClass.JSON_OBJECT)
  15426. {
  15427. sb.Append('{');
  15428. for (int i = 0; i < values.Data.Length; i += 2)
  15429. {
  15430. if (values.Data[i] is not LSL_String LSL_StringVal)
  15431. return ScriptBaseClass.JSON_INVALID;
  15432. string key = LSL_StringVal.m_string;
  15433. key = EscapeForJSON(key, true);
  15434. sb.Append(key);
  15435. sb.Append(':');
  15436. sb.Append(ListToJson(values.Data[i+1]));
  15437. if(i < values.Data.Length - 2)
  15438. sb.Append(',');
  15439. }
  15440. sb.Append('}');
  15441. return (LSL_String)sb.ToString();
  15442. }
  15443. return ScriptBaseClass.JSON_INVALID;
  15444. }
  15445. catch
  15446. {
  15447. return ScriptBaseClass.JSON_INVALID;
  15448. }
  15449. }
  15450. private static string ListToJson(object o)
  15451. {
  15452. if (o is double od)
  15453. {
  15454. if(double.IsInfinity(od))
  15455. return "\"Inf\"";
  15456. if(double.IsNaN(od))
  15457. return "\"NaN\"";
  15458. return od.ToString();
  15459. }
  15460. if (o is LSL_Float olf)
  15461. {
  15462. if (double.IsInfinity(olf.value))
  15463. return "\"Inf\"";
  15464. if (double.IsNaN(olf.value))
  15465. return "\"NaN\"";
  15466. return olf.value.ToString();
  15467. }
  15468. if (o is LSL_Integer LSL_Integero)
  15469. {
  15470. return LSL_Integero.value.ToString();
  15471. }
  15472. if(o is int into)
  15473. {
  15474. return into.ToString();
  15475. }
  15476. if (o is LSL_Rotation LSL_Rotationo)
  15477. {
  15478. return $"\"{LSL_Rotationo}\"";
  15479. }
  15480. if (o is LSL_Vector LSL_Vectoro)
  15481. {
  15482. return $"\"{LSL_Vectoro}\"";
  15483. }
  15484. if (o is string str)
  15485. {
  15486. str = str.Trim();
  15487. if (str.Length == 0)
  15488. return "\"\"";
  15489. if (str[0] == '{')
  15490. return str;
  15491. if (str[0] == '[')
  15492. return str;
  15493. if (str.Equals(ScriptBaseClass.JSON_TRUE) || str.Equals("true"))
  15494. return "true";
  15495. if(str.Equals(ScriptBaseClass.JSON_FALSE) || str.Equals("false"))
  15496. return "false";
  15497. if(str.Equals(ScriptBaseClass.JSON_NULL) || str.Equals("null"))
  15498. return "null";
  15499. return EscapeForJSON(str, true);
  15500. }
  15501. if (o is LSL_String olstr)
  15502. {
  15503. string lstr = olstr.m_string.Trim();
  15504. if (lstr.Length == 0)
  15505. return "\"\"";
  15506. if (lstr[0] == '{')
  15507. return lstr;
  15508. if (lstr[0] == '[')
  15509. return lstr;
  15510. if (lstr.Equals(ScriptBaseClass.JSON_TRUE) || lstr.Equals( "true"))
  15511. return "true";
  15512. if (lstr.Equals(ScriptBaseClass.JSON_FALSE) || lstr.Equals("false"))
  15513. return "false";
  15514. if (lstr.Equals(ScriptBaseClass.JSON_NULL) || lstr.Equals( "null"))
  15515. return "null";
  15516. return EscapeForJSON(lstr, true);
  15517. }
  15518. throw new IndexOutOfRangeException();
  15519. }
  15520. private static string EscapeForJSON(string s, bool AddOuter)
  15521. {
  15522. int i;
  15523. char c;
  15524. String t;
  15525. int len = s.Length;
  15526. StringBuilder sb = new(len + 64);
  15527. if(AddOuter)
  15528. sb.Append('\"');
  15529. for (i = 0; i < len; i++)
  15530. {
  15531. c = s[i];
  15532. switch (c)
  15533. {
  15534. case '\\':
  15535. case '"':
  15536. case '/':
  15537. sb.Append('\\');
  15538. sb.Append(c);
  15539. break;
  15540. case '\b':
  15541. sb.Append("\\b");
  15542. break;
  15543. case '\t':
  15544. sb.Append("\\t");
  15545. break;
  15546. case '\n':
  15547. sb.Append("\\n");
  15548. break;
  15549. case '\f':
  15550. sb.Append("\\f");
  15551. break;
  15552. case '\r':
  15553. sb.Append("\\r");
  15554. break;
  15555. default:
  15556. if (c < ' ')
  15557. {
  15558. t = "000" + String.Format("{0:X}", c);
  15559. sb.Append("\\u");
  15560. sb.Append(t.AsSpan(t.Length - 4));
  15561. }
  15562. else
  15563. {
  15564. sb.Append(c);
  15565. }
  15566. break;
  15567. }
  15568. }
  15569. if(AddOuter)
  15570. sb.Append('\"');
  15571. return sb.ToString();
  15572. }
  15573. public LSL_String llJsonSetValue(LSL_String json, LSL_List specifiers, LSL_String value)
  15574. {
  15575. bool noSpecifiers = specifiers.Length == 0;
  15576. LitJson.JsonData workData;
  15577. try
  15578. {
  15579. if(noSpecifiers)
  15580. specifiers.Add(new LSL_Integer(0));
  15581. if(!String.IsNullOrEmpty(json))
  15582. workData = LitJson.JsonMapper.ToObject(json);
  15583. else
  15584. {
  15585. workData = new LitJson.JsonData();
  15586. workData.SetJsonType(LitJson.JsonType.Array);
  15587. }
  15588. }
  15589. catch //(Exception e)
  15590. {
  15591. //string m = e.Message; // debug point
  15592. return ScriptBaseClass.JSON_INVALID;
  15593. }
  15594. try
  15595. {
  15596. LitJson.JsonData replace = JsonSetSpecific(workData, specifiers, 0, value);
  15597. if(replace != null)
  15598. workData = replace;
  15599. }
  15600. catch //(Exception e)
  15601. {
  15602. //string m = e.Message; // debug point
  15603. return ScriptBaseClass.JSON_INVALID;
  15604. }
  15605. try
  15606. {
  15607. string r = LitJson.JsonMapper.ToJson(workData);
  15608. if(noSpecifiers)
  15609. r = r[1..^1]; // strip leading and trailing brakets
  15610. return r;
  15611. }
  15612. catch //(Exception e)
  15613. {
  15614. //string m = e.Message; // debug point
  15615. }
  15616. return ScriptBaseClass.JSON_INVALID;
  15617. }
  15618. private LitJson.JsonData JsonSetSpecific(LitJson.JsonData elem, LSL_List specifiers, int level, LSL_String val)
  15619. {
  15620. object spec = specifiers.Data[level];
  15621. if(spec is LSL_String LSL_Stringspec)
  15622. spec = LSL_Stringspec.m_string;
  15623. else if (spec is LSL_Integer LSL_Integerspec)
  15624. spec = LSL_Integerspec.value;
  15625. if(!(spec is string || spec is int))
  15626. throw new IndexOutOfRangeException();
  15627. int speclen = specifiers.Data.Length - 1;
  15628. bool hasvalue = false;
  15629. LitJson.JsonData value = null;
  15630. LitJson.JsonType elemType = elem.GetJsonType();
  15631. if (elemType == LitJson.JsonType.Array)
  15632. {
  15633. if (spec is int v)
  15634. {
  15635. int c = elem.Count;
  15636. if(v < 0 || (v != 0 && v > c))
  15637. throw new IndexOutOfRangeException();
  15638. if(v == c)
  15639. elem.Add(JsonBuildRestOfSpec(specifiers, level + 1, val));
  15640. else
  15641. {
  15642. hasvalue = true;
  15643. value = elem[v];
  15644. }
  15645. }
  15646. else if (spec is string stringspec)
  15647. {
  15648. if(stringspec == ScriptBaseClass.JSON_APPEND)
  15649. elem.Add(JsonBuildRestOfSpec(specifiers, level + 1, val));
  15650. else if(elem.Count < 2)
  15651. {
  15652. // our initial guess of array was wrong
  15653. LitJson.JsonData newdata = new();
  15654. newdata.SetJsonType(LitJson.JsonType.Object);
  15655. IOrderedDictionary no = newdata as IOrderedDictionary;
  15656. no.Add((string)spec,JsonBuildRestOfSpec(specifiers, level + 1, val));
  15657. return newdata;
  15658. }
  15659. }
  15660. }
  15661. else if (elemType == LitJson.JsonType.Object)
  15662. {
  15663. if (spec is string key)
  15664. {
  15665. IOrderedDictionary e = elem as IOrderedDictionary;
  15666. if(e.Contains(key))
  15667. {
  15668. hasvalue = true;
  15669. value = (LitJson.JsonData)e[key];
  15670. }
  15671. else
  15672. e.Add(key, JsonBuildRestOfSpec(specifiers, level + 1, val));
  15673. }
  15674. else if(spec is int intspec && intspec == 0)
  15675. {
  15676. //we are replacing a object by a array
  15677. LitJson.JsonData newData = new();
  15678. newData.SetJsonType(LitJson.JsonType.Array);
  15679. newData.Add(JsonBuildRestOfSpec(specifiers, level + 1, val));
  15680. return newData;
  15681. }
  15682. }
  15683. else
  15684. {
  15685. LitJson.JsonData newData = JsonBuildRestOfSpec(specifiers, level, val);
  15686. return newData;
  15687. }
  15688. if (hasvalue)
  15689. {
  15690. if (level < speclen)
  15691. {
  15692. LitJson.JsonData replace = JsonSetSpecific(value, specifiers, level + 1, val);
  15693. if(replace is not null)
  15694. {
  15695. if(elemType == LitJson.JsonType.Array)
  15696. {
  15697. if(spec is int intspec)
  15698. elem[intspec] = replace;
  15699. else if( spec is string stringspec)
  15700. {
  15701. LitJson.JsonData newdata = new();
  15702. newdata.SetJsonType(LitJson.JsonType.Object);
  15703. IOrderedDictionary no = newdata as IOrderedDictionary;
  15704. no.Add(stringspec, replace);
  15705. return newdata;
  15706. }
  15707. }
  15708. else if(elemType == LitJson.JsonType.Object)
  15709. {
  15710. if(spec is string stringspec)
  15711. elem[stringspec] = replace;
  15712. else if(spec is int intspec && intspec == 0)
  15713. {
  15714. LitJson.JsonData newdata = new();
  15715. newdata.SetJsonType(LitJson.JsonType.Array);
  15716. newdata.Add(replace);
  15717. return newdata;
  15718. }
  15719. }
  15720. }
  15721. return null;
  15722. }
  15723. else if(speclen == level)
  15724. {
  15725. if(val == ScriptBaseClass.JSON_DELETE)
  15726. {
  15727. if(elemType == LitJson.JsonType.Array)
  15728. {
  15729. if(spec is int intspec)
  15730. {
  15731. IList el = elem as IList;
  15732. el.RemoveAt(intspec);
  15733. }
  15734. }
  15735. else if(elemType == LitJson.JsonType.Object)
  15736. {
  15737. if(spec is string stringspec)
  15738. {
  15739. IOrderedDictionary eo = elem as IOrderedDictionary;
  15740. eo.Remove(stringspec);
  15741. }
  15742. }
  15743. return null;
  15744. }
  15745. LitJson.JsonData newval;
  15746. if(val == null || val == ScriptBaseClass.JSON_NULL || val == "null")
  15747. newval = null;
  15748. else if(val == ScriptBaseClass.JSON_TRUE || val == "true")
  15749. newval = new LitJson.JsonData(true);
  15750. else if(val == ScriptBaseClass.JSON_FALSE || val == "false")
  15751. newval = new LitJson.JsonData(false);
  15752. else if(float.TryParse(val, out float num))
  15753. {
  15754. // assuming we are at en.us already
  15755. if(num - (int)num == 0.0f && !val.Contains("."))
  15756. newval = new LitJson.JsonData((int)num);
  15757. else
  15758. {
  15759. num = (float)Math.Round(num,6);
  15760. newval = new LitJson.JsonData((double)num);
  15761. }
  15762. }
  15763. else
  15764. {
  15765. string str = val.m_string;
  15766. newval = new LitJson.JsonData(str);
  15767. }
  15768. if(elemType == LitJson.JsonType.Array)
  15769. {
  15770. if(spec is int intspec)
  15771. elem[intspec] = newval;
  15772. else if( spec is string stringspec)
  15773. {
  15774. LitJson.JsonData newdata = new();
  15775. newdata.SetJsonType(LitJson.JsonType.Object);
  15776. IOrderedDictionary no = newdata as IOrderedDictionary;
  15777. no.Add(stringspec,newval);
  15778. return newdata;
  15779. }
  15780. }
  15781. else if(elemType == LitJson.JsonType.Object)
  15782. {
  15783. if(spec is string stringspec)
  15784. elem[stringspec] = newval;
  15785. else if(spec is int intspec && intspec == 0)
  15786. {
  15787. LitJson.JsonData newdata = new();
  15788. newdata.SetJsonType(LitJson.JsonType.Array);
  15789. newdata.Add(newval);
  15790. return newdata;
  15791. }
  15792. }
  15793. }
  15794. }
  15795. if(val == ScriptBaseClass.JSON_DELETE)
  15796. throw new IndexOutOfRangeException();
  15797. return null;
  15798. }
  15799. private LitJson.JsonData JsonBuildRestOfSpec(LSL_List specifiers, int level, LSL_String val)
  15800. {
  15801. object spec = level >= specifiers.Data.Length ? null : specifiers.Data[level];
  15802. // 20131224 not used object specNext = i+1 >= specifiers.Data.Length ? null : specifiers.Data[i+1];
  15803. if (spec == null)
  15804. {
  15805. if(val == null || val == ScriptBaseClass.JSON_NULL || val == "null")
  15806. return null;
  15807. if(val == ScriptBaseClass.JSON_DELETE)
  15808. throw new IndexOutOfRangeException();
  15809. if(val == ScriptBaseClass.JSON_TRUE || val == "true")
  15810. return new LitJson.JsonData(true);
  15811. if(val == ScriptBaseClass.JSON_FALSE || val == "false")
  15812. return new LitJson.JsonData(false);
  15813. if(val == null || val == ScriptBaseClass.JSON_NULL || val == "null")
  15814. return null;
  15815. if(float.TryParse(val, out float num))
  15816. {
  15817. // assuming we are at en.us already
  15818. if(num - (int)num == 0.0f && !val.Contains("."))
  15819. return new LitJson.JsonData((int)num);
  15820. else
  15821. {
  15822. num = (float)Math.Round(num,6);
  15823. return new LitJson.JsonData(num);
  15824. }
  15825. }
  15826. else
  15827. {
  15828. string str = val.m_string;
  15829. return new LitJson.JsonData(str);
  15830. }
  15831. throw new IndexOutOfRangeException();
  15832. }
  15833. if(spec is LSL_String LSL_Stringspec)
  15834. spec = LSL_Stringspec.m_string;
  15835. else if (spec is LSL_Integer LSL_Integerspec)
  15836. spec = LSL_Integerspec.value;
  15837. if (spec is int ||
  15838. (spec is string stringspec && stringspec == ScriptBaseClass.JSON_APPEND) )
  15839. {
  15840. if(spec is int intspec && intspec != 0)
  15841. throw new IndexOutOfRangeException();
  15842. LitJson.JsonData newdata = new();
  15843. newdata.SetJsonType(LitJson.JsonType.Array);
  15844. newdata.Add(JsonBuildRestOfSpec(specifiers, level + 1, val));
  15845. return newdata;
  15846. }
  15847. else if (spec is string sspec)
  15848. {
  15849. LitJson.JsonData newdata = new();
  15850. newdata.SetJsonType(LitJson.JsonType.Object);
  15851. IOrderedDictionary no = newdata as IOrderedDictionary;
  15852. no.Add(sspec,JsonBuildRestOfSpec(specifiers, level + 1, val));
  15853. return newdata;
  15854. }
  15855. throw new IndexOutOfRangeException();
  15856. }
  15857. private bool JsonFind(LitJson.JsonData elem, LSL_List specifiers, int level, out LitJson.JsonData value)
  15858. {
  15859. value = null;
  15860. if(elem == null)
  15861. return false;
  15862. object spec;
  15863. spec = specifiers.Data[level];
  15864. bool haveVal = false;
  15865. LitJson.JsonData next = null;
  15866. if (elem.GetJsonType() == LitJson.JsonType.Array)
  15867. {
  15868. if (spec is LSL_Integer)
  15869. {
  15870. int indx = (LSL_Integer)spec;
  15871. if(indx >= 0 && indx < elem.Count)
  15872. {
  15873. haveVal = true;
  15874. next = (LitJson.JsonData)elem[indx];
  15875. }
  15876. }
  15877. }
  15878. else if (elem.GetJsonType() == LitJson.JsonType.Object)
  15879. {
  15880. if (spec is LSL_String LSL_Stringspec)
  15881. {
  15882. IOrderedDictionary e = elem as IOrderedDictionary;
  15883. string key = LSL_Stringspec.m_string;
  15884. if(e.Contains(key))
  15885. {
  15886. haveVal = true;
  15887. next = (LitJson.JsonData)e[key];
  15888. }
  15889. }
  15890. }
  15891. if (haveVal)
  15892. {
  15893. if(level == specifiers.Data.Length - 1)
  15894. {
  15895. value = next;
  15896. return true;
  15897. }
  15898. level++;
  15899. if(next == null)
  15900. return false;
  15901. LitJson.JsonType nextType = next.GetJsonType();
  15902. if(nextType != LitJson.JsonType.Object && nextType != LitJson.JsonType.Array)
  15903. return false;
  15904. return JsonFind(next, specifiers, level, out value);
  15905. }
  15906. return false;
  15907. }
  15908. public LSL_String llJsonGetValue(LSL_String json, LSL_List specifiers)
  15909. {
  15910. if(String.IsNullOrWhiteSpace(json))
  15911. return ScriptBaseClass.JSON_INVALID;
  15912. if(specifiers.Length > 0 && (json == "{}" || json == "[]"))
  15913. return ScriptBaseClass.JSON_INVALID;
  15914. char first = ((string)json)[0];
  15915. if((first != '[' && first !='{'))
  15916. {
  15917. if(specifiers.Length > 0)
  15918. return ScriptBaseClass.JSON_INVALID;
  15919. json = "[" + json + "]"; // could handle single element case.. but easier like this
  15920. specifiers.Add((LSL_Integer)0);
  15921. }
  15922. LitJson.JsonData jsonData;
  15923. try
  15924. {
  15925. jsonData = LitJson.JsonMapper.ToObject(json);
  15926. }
  15927. catch //(Exception e)
  15928. {
  15929. //string m = e.Message; // debug point
  15930. return ScriptBaseClass.JSON_INVALID;
  15931. }
  15932. LitJson.JsonData elem;
  15933. if(specifiers.Length == 0)
  15934. elem = jsonData;
  15935. else
  15936. {
  15937. if(!JsonFind(jsonData, specifiers, 0, out elem))
  15938. return ScriptBaseClass.JSON_INVALID;
  15939. }
  15940. return JsonElementToString(elem);
  15941. }
  15942. private static LSL_String JsonElementToString(LitJson.JsonData elem)
  15943. {
  15944. if(elem is null)
  15945. return ScriptBaseClass.JSON_NULL;
  15946. LitJson.JsonType elemType = elem.GetJsonType();
  15947. switch(elemType)
  15948. {
  15949. case LitJson.JsonType.Array:
  15950. return new LSL_String(LitJson.JsonMapper.ToJson(elem));
  15951. case LitJson.JsonType.Boolean:
  15952. return new LSL_String((bool)elem ? ScriptBaseClass.JSON_TRUE : ScriptBaseClass.JSON_FALSE);
  15953. case LitJson.JsonType.Double:
  15954. double d= (double)elem;
  15955. string sd = String.Format(Culture.FormatProvider, "{0:0.0#####}",d);
  15956. return new LSL_String(sd);
  15957. case LitJson.JsonType.Int:
  15958. int i = (int)elem;
  15959. return new LSL_String(i.ToString());
  15960. case LitJson.JsonType.Long:
  15961. long l = (long)elem;
  15962. return new LSL_String(l.ToString());
  15963. case LitJson.JsonType.Object:
  15964. return new LSL_String(LitJson.JsonMapper.ToJson(elem));
  15965. case LitJson.JsonType.String:
  15966. string s = (string)elem;
  15967. return new LSL_String(s);
  15968. case LitJson.JsonType.None:
  15969. return ScriptBaseClass.JSON_NULL;
  15970. default:
  15971. return ScriptBaseClass.JSON_INVALID;
  15972. }
  15973. }
  15974. public LSL_String llJsonValueType(LSL_String json, LSL_List specifiers)
  15975. {
  15976. if(String.IsNullOrWhiteSpace(json))
  15977. return ScriptBaseClass.JSON_INVALID;
  15978. if(specifiers.Length > 0 && (json == "{}" || json == "[]"))
  15979. return ScriptBaseClass.JSON_INVALID;
  15980. char first = ((string)json)[0];
  15981. if((first != '[' && first !='{'))
  15982. {
  15983. if(specifiers.Length > 0)
  15984. return ScriptBaseClass.JSON_INVALID;
  15985. json = "[" + json + "]"; // could handle single element case.. but easier like this
  15986. specifiers.Add((LSL_Integer)0);
  15987. }
  15988. LitJson.JsonData jsonData;
  15989. try
  15990. {
  15991. jsonData = LitJson.JsonMapper.ToObject(json);
  15992. }
  15993. catch //(Exception e)
  15994. {
  15995. //string m = e.Message; // debug point
  15996. return ScriptBaseClass.JSON_INVALID;
  15997. }
  15998. LitJson.JsonData elem;
  15999. if(specifiers.Length == 0)
  16000. elem = jsonData;
  16001. else
  16002. {
  16003. if(!JsonFind(jsonData, specifiers, 0, out elem))
  16004. return ScriptBaseClass.JSON_INVALID;
  16005. }
  16006. if(elem == null)
  16007. return ScriptBaseClass.JSON_NULL;
  16008. LitJson.JsonType elemType = elem.GetJsonType();
  16009. switch(elemType)
  16010. {
  16011. case LitJson.JsonType.Array:
  16012. return ScriptBaseClass.JSON_ARRAY;
  16013. case LitJson.JsonType.Boolean:
  16014. return (bool)elem ? ScriptBaseClass.JSON_TRUE : ScriptBaseClass.JSON_FALSE;
  16015. case LitJson.JsonType.Double:
  16016. case LitJson.JsonType.Int:
  16017. case LitJson.JsonType.Long:
  16018. return ScriptBaseClass.JSON_NUMBER;
  16019. case LitJson.JsonType.Object:
  16020. return ScriptBaseClass.JSON_OBJECT;
  16021. case LitJson.JsonType.String:
  16022. string s = (string)elem;
  16023. if(s == ScriptBaseClass.JSON_NULL)
  16024. return ScriptBaseClass.JSON_NULL;
  16025. if(s == ScriptBaseClass.JSON_TRUE)
  16026. return ScriptBaseClass.JSON_TRUE;
  16027. if(s == ScriptBaseClass.JSON_FALSE)
  16028. return ScriptBaseClass.JSON_FALSE;
  16029. return ScriptBaseClass.JSON_STRING;
  16030. case LitJson.JsonType.None:
  16031. return ScriptBaseClass.JSON_NULL;
  16032. default:
  16033. return ScriptBaseClass.JSON_INVALID;
  16034. }
  16035. }
  16036. public LSL_String llChar(LSL_Integer unicode)
  16037. {
  16038. if(unicode == 0)
  16039. return LSL_String.Empty;
  16040. try
  16041. {
  16042. return Char.ConvertFromUtf32(unicode);
  16043. }
  16044. catch { }
  16045. return "\ufffd";
  16046. }
  16047. public LSL_Integer llOrd(LSL_String s, LSL_Integer index)
  16048. {
  16049. if (string.IsNullOrEmpty(s))
  16050. return 0;
  16051. if(index < 0)
  16052. index += s.Length;
  16053. if (index < 0 || index >= s.Length)
  16054. return 0;
  16055. char c = s.m_string[index];
  16056. if(c >= 0xdc00 && c <= 0xdfff)
  16057. {
  16058. --index;
  16059. if (index < 0)
  16060. return 0;
  16061. int a = c - 0xdc00;
  16062. c = s.m_string[index];
  16063. if (c < 0xd800 || c > 0xdbff)
  16064. return 0;
  16065. c -= (char)(0xd800 - 0x40);
  16066. return a + (c << 10);
  16067. }
  16068. if (c >= 0xd800)
  16069. {
  16070. if(c < 0xdc00)
  16071. {
  16072. ++index;
  16073. if (index >= s.Length)
  16074. return 0;
  16075. c -= (char)(0xd800 - 0x40);
  16076. int a = (c << 10);
  16077. c = s.m_string[index];
  16078. if (c < 0xdc00 || c > 0xdfff)
  16079. return 0;
  16080. c -= (char)0xdc00;
  16081. return a + c;
  16082. }
  16083. else if(c < 0xe000)
  16084. return 0;
  16085. }
  16086. return (int)c;
  16087. }
  16088. public LSL_Integer llHash(LSL_String s)
  16089. {
  16090. if (string.IsNullOrEmpty(s))
  16091. return 0;
  16092. int hash = 0;
  16093. char c;
  16094. for(int i = 0; i < s.Length; ++i)
  16095. {
  16096. hash *= 65599;
  16097. // on modern intel/amd this is faster than the tradicional optimization:
  16098. // hash = (hash << 6) + (hash << 16) - hash;
  16099. c = s.m_string[i];
  16100. if (c >= 0xd800)
  16101. {
  16102. if(c < 0xdc00)
  16103. {
  16104. ++i;
  16105. if(i >= s.Length)
  16106. return 0;
  16107. c -= (char)(0xd800 - 0x40);
  16108. hash += (c << 10);
  16109. c = s.m_string[i];
  16110. if(c < 0xdc00 || c > 0xdfff)
  16111. return 0;
  16112. c -= (char)(0xdc00);
  16113. }
  16114. else if(c < 0xe000)
  16115. return 0;
  16116. }
  16117. hash += c;
  16118. }
  16119. return hash;
  16120. }
  16121. public LSL_String llReplaceSubString(LSL_String src, LSL_String pattern, LSL_String replacement, int count)
  16122. {
  16123. RegexOptions RegexOptions;
  16124. if (count < 0)
  16125. {
  16126. RegexOptions = RegexOptions.CultureInvariant | RegexOptions.RightToLeft;
  16127. count = -count;
  16128. }
  16129. else
  16130. {
  16131. RegexOptions = RegexOptions.CultureInvariant;
  16132. if (count == 0)
  16133. count = -1;
  16134. }
  16135. try
  16136. {
  16137. if (string.IsNullOrEmpty(src.m_string))
  16138. return src;
  16139. if (string.IsNullOrEmpty(pattern.m_string))
  16140. return src;
  16141. Regex rx = new(pattern, RegexOptions, TimeSpan.FromMilliseconds(10));
  16142. if (replacement == null)
  16143. return rx.Replace(src.m_string, string.Empty, count);
  16144. return rx.Replace(src.m_string, replacement.m_string, count);
  16145. }
  16146. catch
  16147. {
  16148. return src;
  16149. }
  16150. }
  16151. public LSL_Vector llLinear2sRGB(LSL_Vector src)
  16152. {
  16153. return new LSL_Vector(Util.LinearTosRGB((float)src.x), Util.LinearTosRGB((float)src.y), Util.LinearTosRGB((float)src.z));
  16154. }
  16155. public LSL_Vector llsRGB2Linear(LSL_Vector src)
  16156. {
  16157. return new LSL_Vector(Util.sRGBtoLinear((float)src.x), Util.sRGBtoLinear((float)src.y), Util.sRGBtoLinear((float)src.z));
  16158. }
  16159. public LSL_Integer llLinksetDataAvailable()
  16160. {
  16161. if (m_host.ParentGroup.LinksetData is null)
  16162. return m_linksetDataLimit;
  16163. return new LSL_Integer(m_host.ParentGroup.LinksetData.Free());
  16164. }
  16165. public LSL_Integer llLinksetDataCountKeys()
  16166. {
  16167. if (m_host.ParentGroup.LinksetData is null)
  16168. return 0;
  16169. return new LSL_Integer(m_host.ParentGroup.LinksetData.Count());
  16170. }
  16171. public LSL_String llLinksetDataRead(LSL_String name)
  16172. {
  16173. if (m_host.ParentGroup.LinksetData is null || string.IsNullOrEmpty(name.m_string))
  16174. return new LSL_String(string.Empty);
  16175. return new LSL_String(m_host.ParentGroup.LinksetData.Get(name.m_string));
  16176. }
  16177. public LSL_String llLinksetDataReadProtected(LSL_String name, LSL_String pass)
  16178. {
  16179. if (m_host.ParentGroup.LinksetData is null || string.IsNullOrEmpty(name.m_string))
  16180. return new LSL_String(string.Empty);
  16181. return new LSL_String(m_host.ParentGroup.LinksetData.Get(name.m_string, pass.m_string));
  16182. }
  16183. public LSL_Integer llLinksetDataDelete(LSL_String name)
  16184. {
  16185. if (string.IsNullOrEmpty(name.m_string))
  16186. return ScriptBaseClass.LINKSETDATA_ENOKEY;
  16187. if (m_host.ParentGroup.LinksetData is null)
  16188. return ScriptBaseClass.LINKSETDATA_NOTFOUND;
  16189. int ret = m_host.ParentGroup.LinksetData.Remove(name.m_string);
  16190. if (ret == 0)
  16191. {
  16192. m_ScriptEngine.PostObjectLinksetDataEvent(m_host.LocalId, ScriptBaseClass.LINKSETDATA_DELETE, name.m_string, string.Empty);
  16193. m_host.ParentGroup.HasGroupChanged = true;
  16194. }
  16195. return ret;
  16196. }
  16197. public LSL_Integer llLinksetDataDeleteProtected(LSL_String name, LSL_String pass)
  16198. {
  16199. if (string.IsNullOrEmpty(name.m_string))
  16200. return ScriptBaseClass.LINKSETDATA_ENOKEY;
  16201. if (m_host.ParentGroup.LinksetData is null)
  16202. return ScriptBaseClass.LINKSETDATA_NOTFOUND;
  16203. int ret = m_host.ParentGroup.LinksetData.Remove(name.m_string, pass.m_string);
  16204. if (ret == 0)
  16205. {
  16206. m_ScriptEngine.PostObjectLinksetDataEvent(m_host.LocalId, ScriptBaseClass.LINKSETDATA_DELETE, name.m_string, string.Empty);
  16207. m_host.ParentGroup.HasGroupChanged = true;
  16208. }
  16209. return ret;
  16210. }
  16211. public void llLinksetDataReset()
  16212. {
  16213. if (m_host.ParentGroup.LinksetData is null)
  16214. return;
  16215. bool changed = m_host.ParentGroup.LinksetData.Count() > 0;
  16216. m_host.ParentGroup.LinksetData = null;
  16217. if(changed)
  16218. {
  16219. m_ScriptEngine.PostObjectLinksetDataEvent(m_host.LocalId, ScriptBaseClass.LINKSETDATA_RESET, string.Empty, string.Empty);
  16220. m_host.ParentGroup.HasGroupChanged = true;
  16221. }
  16222. }
  16223. public LSL_Integer llLinksetDataWrite(LSL_String name, LSL_String value)
  16224. {
  16225. if (string.IsNullOrEmpty(name.m_string))
  16226. return ScriptBaseClass.LINKSETDATA_ENOKEY;
  16227. int ret;
  16228. if (string.IsNullOrEmpty(value.m_string))
  16229. {
  16230. if (m_host.ParentGroup.LinksetData is null)
  16231. return ScriptBaseClass.LINKSETDATA_NOTFOUND;
  16232. ret = m_host.ParentGroup.LinksetData.Remove(name.m_string);
  16233. if (ret == 0)
  16234. {
  16235. m_ScriptEngine.PostObjectLinksetDataEvent(m_host.LocalId, ScriptBaseClass.LINKSETDATA_DELETE, name.m_string, string.Empty);
  16236. m_host.ParentGroup.HasGroupChanged = true;
  16237. }
  16238. return ret;
  16239. }
  16240. m_host.ParentGroup.LinksetData ??= new(m_linksetDataLimit);
  16241. ret = m_host.ParentGroup.LinksetData.AddOrUpdate(name.m_string, value.m_string);
  16242. if (ret == 0)
  16243. {
  16244. m_ScriptEngine.PostObjectLinksetDataEvent(m_host.LocalId, ScriptBaseClass.LINKSETDATA_UPDATE, name.m_string, value.m_string);
  16245. m_host.ParentGroup.HasGroupChanged = true;
  16246. }
  16247. return ret;
  16248. }
  16249. public LSL_Integer llLinksetDataWriteProtected(LSL_String name, LSL_String value, LSL_String pass)
  16250. {
  16251. if (string.IsNullOrEmpty(name.m_string))
  16252. return ScriptBaseClass.LINKSETDATA_ENOKEY;
  16253. int ret;
  16254. if (string.IsNullOrEmpty(value.m_string))
  16255. {
  16256. if (m_host.ParentGroup.LinksetData is null)
  16257. return ScriptBaseClass.LINKSETDATA_NOTFOUND;
  16258. ret = m_host.ParentGroup.LinksetData.Remove(name.m_string, pass.m_string);
  16259. if (ret == 0)
  16260. {
  16261. m_ScriptEngine.PostObjectLinksetDataEvent(m_host.LocalId, ScriptBaseClass.LINKSETDATA_DELETE, name.m_string, string.Empty);
  16262. m_host.ParentGroup.HasGroupChanged = true;
  16263. }
  16264. return ret;
  16265. }
  16266. m_host.ParentGroup.LinksetData ??= new(m_linksetDataLimit);
  16267. ret = m_host.ParentGroup.LinksetData.AddOrUpdate(name.m_string, value.m_string, pass.m_string);
  16268. if (ret == 0)
  16269. {
  16270. m_ScriptEngine.PostObjectLinksetDataEvent(m_host.LocalId, ScriptBaseClass.LINKSETDATA_UPDATE, name.m_string, string.Empty);
  16271. m_host.ParentGroup.HasGroupChanged = true;
  16272. }
  16273. return ret;
  16274. }
  16275. public LSL_List llLinksetDataDeleteFound(LSL_String pattern, LSL_String pass)
  16276. {
  16277. if (string.IsNullOrEmpty(pattern.m_string) || m_host.ParentGroup.LinksetData is null)
  16278. return new LSL_List(new object[] { new LSL_Integer(0), new LSL_Integer(0)});
  16279. string[] deleted = m_host.ParentGroup.LinksetData.RemoveByPattern(pattern.m_string, pass.m_string, out int notDeleted);
  16280. int deletedCount = deleted.Length;
  16281. if(deleted.Length > 0)
  16282. {
  16283. string deletedList = string.Join(",", deleted);
  16284. m_ScriptEngine.PostObjectLinksetDataEvent(m_host.LocalId, ScriptBaseClass.LINKSETDATA_MULTIDELETE, deletedList, string.Empty);
  16285. m_host.ParentGroup.HasGroupChanged = true;
  16286. }
  16287. return new LSL_List(new object[] { new LSL_Integer(deleted.Length), new LSL_Integer(notDeleted) });
  16288. }
  16289. public LSL_Integer llLinksetDataCountFound(LSL_String pattern)
  16290. {
  16291. if (string.IsNullOrEmpty(pattern.m_string) || m_host.ParentGroup.LinksetData is null)
  16292. return new LSL_Integer(0);
  16293. return m_host.ParentGroup.LinksetData.CountByPattern(pattern.m_string);
  16294. }
  16295. public LSL_List llLinksetDataListKeys(LSL_Integer start, LSL_Integer count)
  16296. {
  16297. if (m_host.ParentGroup.LinksetData is null)
  16298. return new LSL_List();
  16299. return new LSL_List(m_host.ParentGroup.LinksetData.ListKeys(start, count));
  16300. }
  16301. public LSL_List llLinksetDataFindKeys(LSL_String pattern, LSL_Integer start, LSL_Integer count)
  16302. {
  16303. if (string.IsNullOrEmpty(pattern.m_string) || m_host.ParentGroup.LinksetData is null)
  16304. return new LSL_List();
  16305. return new LSL_List(m_host.ParentGroup.LinksetData.ListKeysByPatttern(pattern.m_string, start, count));
  16306. }
  16307. public LSL_Integer llIsFriend(LSL_Key agent_id)
  16308. {
  16309. SceneObjectGroup parentsog = m_host.ParentGroup;
  16310. if (parentsog is null || parentsog.IsDeleted)
  16311. return 0;
  16312. if (parentsog.OwnerID.Equals(parentsog.GroupID))
  16313. return llSameGroup(agent_id);
  16314. if (!UUID.TryParse(agent_id, out UUID agent) || agent.IsZero())
  16315. return 0;
  16316. IFriendsModule fm = World.RequestModuleInterface<IFriendsModule>();
  16317. if(fm is null)
  16318. return 0;
  16319. if (World.TryGetSceneRootPresence(agent, out _))
  16320. return fm.IsFriend(agent, parentsog.OwnerID) ? 1 : 0;
  16321. if (World.TryGetSceneRootPresence(parentsog.OwnerID, out _))
  16322. return fm.IsFriend(parentsog.OwnerID, agent) ? 1 : 0;
  16323. return 0;
  16324. }
  16325. public LSL_Integer llDerezObject(LSL_Key objectUUID, LSL_Integer flag)
  16326. {
  16327. if (!UUID.TryParse(objectUUID, out UUID objUUID))
  16328. return new LSL_Integer(0);
  16329. if (objUUID.IsZero())
  16330. return new LSL_Integer(0);
  16331. SceneObjectGroup sceneOG = World.GetSceneObjectGroup(objUUID);
  16332. if (sceneOG is null || sceneOG.IsDeleted || sceneOG.IsAttachment)
  16333. return new LSL_Integer(0);
  16334. if (sceneOG.OwnerID.NotEqual(m_host.OwnerID))
  16335. return new LSL_Integer(0);
  16336. // restrict to objects rezzed by host
  16337. if (sceneOG.RezzerID.NotEqual(m_host.ParentGroup.UUID))
  16338. return new LSL_Integer(0);
  16339. if (sceneOG.UUID.Equals(m_host.ParentGroup.UUID))
  16340. return new LSL_Integer(0);
  16341. if (flag.value == 0)
  16342. World.DeleteSceneObject(sceneOG, false);
  16343. else
  16344. sceneOG.RootPart.AddFlag(PrimFlags.TemporaryOnRez);
  16345. return new LSL_Integer(1);
  16346. }
  16347. }
  16348. public class NotecardCache
  16349. {
  16350. private static readonly ExpiringCacheOS<UUID, string[]> m_Notecards = new(30000);
  16351. public static void Cache(UUID assetID, byte[] text)
  16352. {
  16353. if (m_Notecards.ContainsKey(assetID, 30000))
  16354. return;
  16355. m_Notecards.AddOrUpdate(assetID, SLUtil.ParseNotecardToArray(text), 30);
  16356. }
  16357. public static bool IsCached(UUID assetID)
  16358. {
  16359. return m_Notecards.ContainsKey(assetID, 30000);
  16360. }
  16361. public static int GetLines(UUID assetID)
  16362. {
  16363. if (m_Notecards.TryGetValue(assetID, 30000, out string[] text))
  16364. return text.Length;
  16365. return -1;
  16366. }
  16367. /// <summary>
  16368. /// Get a notecard line.
  16369. /// </summary>
  16370. /// <param name="assetID"></param>
  16371. /// <param name="lineNumber">Lines start at index 0</param>
  16372. /// <returns></returns>
  16373. public static string GetLine(UUID assetID, int lineNumber)
  16374. {
  16375. if (lineNumber >= 0 && m_Notecards.TryGetValue(assetID, 30000, out string[] text))
  16376. {
  16377. if (lineNumber >= text.Length)
  16378. return "\n\n\n";
  16379. return text[lineNumber];
  16380. }
  16381. return "";
  16382. }
  16383. public static string GetllLine(UUID assetID, int lineNumber, int maxLength)
  16384. {
  16385. if (m_Notecards.TryGetValue(assetID, 30000, out string[] text))
  16386. {
  16387. if (lineNumber >= text.Length)
  16388. return "\n\n\n";
  16389. return text[lineNumber].Length < maxLength ? text[lineNumber] : text[lineNumber][..maxLength];
  16390. }
  16391. return ScriptBaseClass.NAK;
  16392. }
  16393. /// <summary>
  16394. /// Get a notecard line.
  16395. /// </summary>
  16396. /// <param name="assetID"></param>
  16397. /// <param name="lineNumber">Lines start at index 0</param>
  16398. /// <param name="maxLength">
  16399. /// Maximum length of the returned line.
  16400. /// </param>
  16401. /// <returns>
  16402. /// If the line length is longer than <paramref name="maxLength"/>,
  16403. /// the return string will be truncated.
  16404. /// </returns>
  16405. public static string GetLine(UUID assetID, int lineNumber, int maxLength)
  16406. {
  16407. string line = GetLine(assetID, lineNumber);
  16408. if (line.Length > maxLength)
  16409. return line[..maxLength];
  16410. return line;
  16411. }
  16412. }
  16413. }