„Houston, wir haben einen linked Prim!“

Genau, das Problem ist gelöst; letztendlich lag es an einem kleinen Ausrufezeichen. Danke an Bert! „Wir sind der Meinung, das war: Spitze!“ 😀

Im Linden-Dschungel Teil 2

Immer noch geht es um die Linked Prims, aber möglicherweise fangen wir gerade erst an, wollen also nicht so lamentieren zu Beginn ;).

Um das Logging zum Einsatz zu bringen waren noch zwei Includes (using bei c#) notwendig und das Anlegen einer statischen Variable. Erstes Modul auf das ich mich stürze ist MySQLRegionData.cs in Region/Framework/Scenes. Kein Erfolg ist feststellbar dass das Loggen irgendein hilfreiches Protokoll bringt. Die else-Zweige bei der Prozedur StoreObject die beschritten werden wenn kein „persistent“ gegeben ist das zum Speichern führen soll werden entkommentiert und mit Leben gefüllt, aber nichts zu bemerken. Es kommen aber schon interessante Erkenntnisse darüber was da wann geschieht, der eine else-Zweig dient nämlich dazu im Modus „selected“ noch nicht zu speichern, klingt vernünftig. Auch Anpassungen im neuen MySQLLegacyRegionData.cs – das in der 0.6.6er noch gar nicht vorhanden war – bringen nichts.

Der nächste Bereich ist, dass ständig – und zwar im 20-Sekunden-Abstand – von diesem Modul versucht wird auf Speicherfähigkeit zu prüfen, ehrlich gesagt halte ich die Last die hier erzeugt wird für ziemlich schlecht. Man merkt das ja gar nicht da im else-Zweig keine Ausgabe erfolgt, mit den debugging-Infos kommt alle paar Sekunden – und das schon für nur 3 Prims „did not update persistance“. Der interessante Punkt ist der, dass nur gespeichert wird wenn „HasGroupChanged“ wahr ist. Ich suche eine Art „HasPositionChanged“ das aber nicht aufzutreiben ist.

In der 0.6.9er wird das in Vorgängerversionen verwendete Setzen von HasGroupChanged an etlichen Stellen auskommentiert. Da mir das verdächtig erscheint nehme ich es mal wieder rein, jedoch ohne dass dies Auswirkungen auf das Speichern von Links hätte.

Nach einigen Tests bekomme ich schließlich eine Erleuchtung: Wir suchen ja einen Trigger der ausgelöst wird noch bevor überhaupt in den Speicherbereich eingestiegen wird, denn selbst VOR dem Speichern müsste ein Wechsel vom Fokus beim Select ja schon das Erhaltenbleiben des Links signalisieren, was definitiv nicht geschieht. Bisher also die komplett falsche Baustelle – die aber einige nette Erkenntnisse gebracht hat die wir sicherlich irgendwann gebrauchen können 😉

Mit vollständig neuer Herangehensweise steige ich in den ClientStack ein, nach einiger Suche werde ich fündig: Es gibt einen LinkHandler neben etlichen anderen – nämlich für all das was im Client ausgelöst werden soll – in LLClientView.cs im Bereich Region/ClientStack/LindenUDP. Und Heureka: Dort ein Logging eingebaut bringt sofort nach dem versuchten Linken eine Protokoll-Meldung auf der Konsole: Ich habe soeben den Hebel an der richtigen Stelle angesetzt.

Aus gegebenem Anlass: Ein Bewegungs-Script ohne Physics für OpenSim

[code lang=“c“]
integer alpha = 0;
vector basepos;
vector newpos;
integer timerset = 0;
float meterProSec = 3;
float offsetX = 0.0;
float offsetY = 0.2;
float offsetZ = 0.0;
integer i = 0;
integer timerSec = 1;
float grenzeYL = 100.0;
float grenzeYH = 110.0;
float grenzeXL = 100.0;
float grenzeXH = 110.0;
default
{
state_entry() {
llSay(0, „ready“);
llSleep(0.1);
basepos = llGetPos();
}

timer() {
vector pos = llGetPos();
float miniOffsetY = offsetY / 10;
float miniOffsetX = offsetX / 10;
for (i = 1; i <= 20; i++) { newpos = pos + ;
llSetPrimitiveParams([PRIM_POSITION, newpos]);
llSleep(0.1);
}
//llOwnerSay(“ am at : “ + (string)newpos);
//llOwnerSay(“ offsets : “ + (string)offsetX + „/“ + (string)offsetY);

// die randsteine
if ((newpos.x <= grenzeXL) && (newpos.y >= grenzeYH)) {
offsetX = meterProSec;
offsetY = 0;
llSetRot(llEuler2Rot(<0.0, 0.0, -PI_BY_TWO>) * llGetRot());
//llOwnerSay(„c1“);
} else if ((newpos.x >= grenzeXH) && (newpos.y >= grenzeYH)) {
offsetX = 0;
offsetY = -meterProSec;
llSetRot(llEuler2Rot(<0.0, 0.0, -PI_BY_TWO>) * llGetRot());
//llOwnerSay(„c2“);
} else if ((newpos.x >= grenzeXH) && (newpos.y <= grenzeYL)) { offsetX = -meterProSec; offsetY = 0; llSetRot(llEuler2Rot(<0.0, 0.0, -PI_BY_TWO>) * llGetRot());
//llOwnerSay(„c3“);
} else if ((newpos.x <= grenzeXL) && (newpos.y <= grenzeYL)) { offsetX = 0; offsetY = meterProSec; llSetRot(llEuler2Rot(<0.0, 0.0, -PI_BY_TWO>) * llGetRot());
//llOwnerSay(„c4“);
}

// die notfallbremsen
else if ((newpos.y > grenzeYH) && (offsetY != 0)) {
offsetY = 0;
offsetX = meterProSec;
llSetRot(llEuler2Rot(<0.0, 0.0, -PI_BY_TWO>) * llGetRot());
//llOwnerSay(„c5“);
} else if ((newpos.x > grenzeXH) && (offsetX != 0)) {
offsetX = 0;
offsetY = meterProSec;
llSetRot(llEuler2Rot(<0.0, 0.0, -PI_BY_TWO>) * llGetRot());
//llOwnerSay(„c6“);
} else if ((newpos.y < grenzeYL) && (offsetY != 0)) { offsetY = 0; offsetX = meterProSec; llSetRot(llEuler2Rot(<0.0, 0.0, -PI_BY_TWO>) * llGetRot());
//llOwnerSay(„c7“);
} else if ((newpos.x < grenzeXL) && (offsetX != 0)) { offsetX = 0; offsetY = meterProSec; llSetRot(llEuler2Rot(<0.0, 0.0, -PI_BY_TWO>) * llGetRot());
//llOwnerSay(„c8“);
}
}
touch_start(integer total_number) {
if (timerset) {
llOwnerSay(„stopping timer“);
timerset = 0;
llSetTimerEvent(0);
} else {
llOwnerSay(„starting timer“);
timerset = 1;
llSetTimerEvent(timerSec);
}
}
}
[/code]

des Programmierers Fundgrube: Wiederholungen

Es geht doch nichts darüber, wenn man gelegentlich Dinge findet die sich einfach kopieren lassen. Sei es von anderen (Programmierer klauen bekanntermassen wie die sprichwörtlichen Raben ^^) oder eben von einem selbst. Und es gab schon bei der mittlerweile schön laufenden 0.6.6 Probleme beim Speichern, die schon erwähnte GroupPosition lief gelegentlich auf einen kapitalen Fehler da sie nicht speicherbare Werte enthielt. Und damals – es ist witzigerweise fast genau ein Jahr her – ergänzte ich die Routine MySQLRegionData.cs um folgenden Schnipsel, der mir gute Dienste leistet immer noch:
[code lang=“csharp“]// bert@wolfsbone.de START 20091018
m_log.DebugFormat(„[DATA]: [BTRACE]: we will now inspect GroupPosition-Value Z“);
double tempGroupPositionZ = prim.GroupPosition.Z;
string tempString = tempGroupPositionZ.ToString(„0.00“);
string tempMessage = „[DATA]: [BTRACE]: it is: <“ + tempString + „>“;
m_log.DebugFormat(tempMessage);
if (tempString == „NaN“) {
m_log.DebugFormat(„[DATA]: [BTRACE]: now setting to 30, should be okay.“);
tempGroupPositionZ = 30;
}
// bert@wolfsbone.de END 20091018

cmd.Parameters.AddWithValue(„GroupPositionX“, (double)prim.GroupPosition.X);
cmd.Parameters.AddWithValue(„GroupPositionY“, (double)prim.GroupPosition.Y);
cmd.Parameters.AddWithValue(„GroupPositionZ“, (double)tempGroupPositionZ);[/code]

Etwas Ähnliches wollen wir dann doch mal wieder einbauen in die 0.6.9er, zunächst nur mit Meldecharakter um zu sehen was wann geschieht.

erste Annäherung

Nun, es gilt eine Aufgabe zu bewältigen, und diese heißt: Verlinken soll funktionieren. Wesentlich – wie immer im Bereich des (manchmal lästigen ;)) Reverse-Engineerings – ist, dass man langsam genug voranschreitet um einzelne Effekte auch klar einer bestimmten Ursache zuzuordnen.

Erste Aktion war, die mit dem Fehler behaftete Version standalone zum Laufen zu bringen. Das ist soweit geglückt, es sind einige Parameter in der OpenSim.ini und eine Standalone-Common.ini im config-include Bereich zu bestücken. Aktuelle Version an der ich bastele ist ja die 0.6.9er. Der standalone-Test ergibt – und in diesem Fall glücklicherweise – dass der Fehler auch dort auftritt. Das ist beruhigend, somit liegt es an der Grundversion und nicht an der falschen Implementierung ins Grid.
erste Annäherung weiterlesen

Welten einfach laden

Gestern und heute habe ich mal ein bisschen auf einem lokalen Grid mit Terrains herumexperimentiert. Über den Viewer kann man – sofern man der Boss einer Region ist – das Terrain über World → Region/Estate → Reiter „Terrain“ exportieren. Beim Klick auf „Export Terrain“ wählt man einen Pfad auf der Festplatte aus und nach einem kleinen Moment Wartezeit wurden die Terrain-Informationen als RAW-Datei abgespeichert, die man dann über einen weiteren Menüpunkt wieder importieren kann. Eine elegante Möglichkeit, ein mühsam geformtes Terrain wieder zu importieren.

Eine wesentlich umfassendere Möglichkeit bietet das Konsolen-Kommando „save oar“ (und „load oar“), dass es nicht nur ermöglicht, Terraininformationen zu speichern, sondern auch sämtliche Objekte, die sich auf der Region befinden. Lädt man sie dann wieder, ist der Besitzer der Region automatisch auch Besitzer/Ersteller der Objekte.

Das OAR-Kommando funktioniert folgendermaßen.

Welten einfach laden weiterlesen

Objekte (Prims) im Hippo Viewer exportieren und wieder importieren

Der Hippo Viewer (Download-Link übrigens hier) bietet eine elegante Möglichkeit, Objekte aus einem Grid zu exportieren und in ein anderes wieder zu importieren:

Einfach das gewünschte Objekt mit Rechtsklick/Edit auswählen und im Menü dann über „More“ weiterhangeln, bis der Menüpunkt „Export“ erscheint. Dort draufklicken. Nun öffnet sich ein Speicherfenster und das Objekt kann als XML exportiert werden (standardmäßig schlägt er „untitled.xml“ als Dateinamen vor, aber das „untitled“ kann auch umbenannt werden.

Nun im anderen Grid einfach über die Menüleiste „File/Import“ gehen und das Objekt wieder importieren. Es rezzt dann unmittelbar neben dem Avatar. Das funktioniert auch mit verlinkten Objekten! Was er nicht kann, ist Texturen, Animationen und Skripte importieren. D.h., sofern die Objekte z.B. keine Standard-Texturen haben muss dann noch einmal nachgearbeitet werden.

Ob das Ganze auch mit SL funktioniert, habe ich noch nicht getestet. Dort gilt aber beim Export sicher auf jeden Fall, dass man nur eigene Kreationen exportieren darf.

Hippo-Viewer vs. Second Life Viewer 2

Vor längerer Zeit schon einmal hatte ich den Hippo Open Sim Viewer ausprobiert, und ich kann gar nicht mehr sagen, aus welchem Grund ich ihn nicht mochte. Jedenfalls bot der Test mit dem Metropolis-Grid einen guten Anlass, ihn mal wieder zu installieren. Dazu muss ich sagen, dass ich bis dahin den Second Life Viewer 2 für Second Life und den Open Sim Viewer für Open Sim in Benutzung hatte.

Nachdem ich nun den Hippo Viewer ein paar Tage benutzt habe, bin ich ganz begeistert davon. Der Viewer bietet im Login-Screen nicht nur die Möglichkeit, relativ Problemlos zwischen verschiedenen Grids und Sims zu wechseln (darunter auch lokalen), er ist auch wesentlich flotter als alles, was ich bislang in Benutzung hatte. gegenüber dem Open Sim Viewer hebt er sich außerdem damit ab, dass er einige kleine, nette Zusatzfeatures bietet. Zum Beispiel eine über den Bildschirm einstellbare Sichtweite (dazu muss man in anderen Viewern immer in die Optionen), sofern man die Kamera-Optionen aktiviert hat.

Gegenüber dem Secondlife-Viewer 2 (der alte Viewer funktioniert ja leider nicht mehr in Second Life) hebt sich der Hippo aber besonders wohltuend ab, indem er nicht nur wensentlich schneller startet und arbeitet als der auf Web2.0 getrimmte SL-Client. Er bietet auch die liebgewonnene „alte“ Optik – und trotzdem kann man ihn mit Second Life nutzen.

So kann ich schon nach ein paar Tagen Nutzung sagen: Der Hippo Viewer ist der Client meiner Wahl!

Gehorcht der Dackel nicht …

… dann vielleicht der Bobtail. So oder ähnlich könnte man sagen ist der Weg, den ich gerade beschreite, um zu einem konsistenten Verhalten zu kommen innerhalb von Metropolis. Aber gemach mit den Analogien, wir sind ja im Bereich ‚Technisches‘ ^^

Ein versuchter Umstieg auf die aktuelle 0.7.0.2 scheiterte kläglich daran, dass diese Version nicht in der Lage ist, sich vollständig mit den Metagrid-Servern zu verständigen. Im Standalone-Mode läuft sie wunderbar, und hier konnte auch schön getestet werden was die Ursache für die fehlenden Permissions ist, denn die ’serverside_permissions‘ sollten beibehalten werden, sonst ist jeder Estate-Manager, jeder kann alles erzeugen auch wenn es verboten ist. Das ist – bei aller Freude am Teilen – nicht das was man möchte. Auch nicht in virtuellen Welten 😉 Aber damit ist es im GridMode nicht getan, denn dann läuft die 0.7.0.2er auf eine Exception wegen fehlender Friends-Module, eine schnelle Recherche hierzu brachte keine Workarounds, lediglich den lapidaren Hinweis darauf, dass alles ab 0.7 nicht im Gridmode lauffähig ist, bzw. es strengstens empfohlen wird die aktuell angebotene Version zu benutzen (das ist die 0.6.8er, +räusper+ …) Schade eigentlich, denn ansonsten macht sie einen fitten und flotten Eindruck. Und schade auch, dass die viele Arbeit die beiden Konfigurationen der 0.6.8er und der 0.7er zu mischen vergeblich war, denn – hey Leute – wenn etwas dazu kommt ist das ja kein Problem, aber im Bereich von 1000 Zeilen wild Parameter hinzuzufügen, wegzulassen oder zu ersetzen … Gäbe es nicht wunderbare Unix-Tools eine von Kommentaren und Leerzeilen bereinigte Version herzustellen (danke grep, und insbesondere egrep mit seinen regulären Ausdrücken) dann käme man so schnell nicht zum Ziel.

Die 0.6.8er wird zwar offiziell empfohlen, hat aber ihre Tücken in anderer Richtung: Schaltet man nämlich die Serverside-Permissions an (will heißen, der RegionsServer, also derjenige auf dem der SIM eigentlich läuft hat noch die Kontrolle über die Rechte), dann sieht zunächst alles gut aus, weil Fremde nichts mehr dürfen. Das Problem ist aber, dass auch man selbst kaum noch etwas kann, das fängt schon dabei an die Parzelle zu benennen, und schaut man in die Land-Infos wird schnell klar warum: Noone ist der Owner, nun gut, dann ist einiges klar. Außerdem will die Region sich partout nicht anständig beim Login verständigen, so dass man immer darauf angewiesen ist zunächst irgendwo anzukommen und dann per Flug oder Teleport nach Hause zu gelangen, nicht die ideale Art. Wer will schon immer den Nachbar fragen, ob man mal gerade den Trampelpfad benutzen darf, da die Strasse zum eigenen Grundstück noch nicht fertig ist. Obwohl das natürlich zugegebenermaßen die Kontakte intensiviert (wie gehabt, danke Paul von FluffyIsland 🙂 ).

Da schon aufgefallen ist, dass einige Nachbarn die 0.6.9er am laufen haben (seltsamerweise FluffyIsland nicht, aber die 0.6.8er dort wird nicht die offizielle sein schätze ich mal ;)), obwohl diese – wie gesagt – noch nicht empfohlen wird, mal eben schnell von SourceForge diese gezogen (wget ist wirklich so genial wie simpel), ein kleines Script aufgesetzt, das es ermöglicht die Konfigurationen flott zu übertragen, und in der Standard-Config gestartet: Siehe da, sie läuft. Ein versuchter Login: Yeah, jetzt kommt man auch direkt auf die eigene Region. Es wird. Und nachdem die serverside_permissions wieder eingeschaltet wurden – oh Wunder – jetzt ist es wie es sein soll: Der Owner bleibt erhalten, andere sind keine Estate-Manager mehr und erzeugte Objekte werden geschützt. Dann noch schnell das Ganze an screen übergeben, denn es macht keine Laune den eigenen Rechner laufen lassen zu müssen damit die Konsole erhalten bleibt. Außerdem sind hiermit nächtliche automatisierte Neustarts möglich, mono bläht sich im Laufe der Zeit gerne etwas auf, aber da es sich um eine Interpretation von Windows-Bibliotheken handelt hab ich volles Verständnis für ein tägliches Frischmachen der Windeln :P. Aber das soll jetzt nicht böse klingen, die Kombination von mono und nant (Compiler) um das originär für .net-libs geschriebene Zeugs zum Rennen zu bringen ist schon sehr tauglich. Fast könnte man Lust bekommen sich in c# einzuarbeiten 🙂

Insgesamt zwar ein seltsamer aber erfolgreicher Weg zum Ziel. Bobtails find ich eh netter, wer mag schon Wadenbeisser? 😉

Kontakt …

Nun, das war gar nicht so schwer. Nur schade, dass screen diesen Bug hat der es notwendig macht das Terminal-Device zu besitzen. Bis ich hier einen Workaround geschaffen habe ist es notwendig alles unter meinem User laufen zu haben. Aber naja, es gibt Schlimmeres.

Dafür sind wir jetzt im Metaversum, und nach einigen Anpassungen befinden wir uns inmitten bunter Regionen, mal was anderes als bisher. Schade nur, dass offensichtlich eine Menge die OpenSim-Version 0.6.9 laufen haben, bei Metropolis zum Download die 0.6.8 angeboten wird (Zitat „solltest du sicherstellen, dass du die neueste freigegebene OpenSim-Version (Link weiter unten) installiert hast“), die aktuelle freigegebene Version jedoch die 0.7.0.2 ist, da hat man dann die Wahl zwischen Teufel und Beelzebub ;).

Interessanterweise verschwinden die Nachbar-Regionen von Zeit zu Zeit, kein Übergang nach dort ist mehr möglich, aber portiert man sich auf der Karte irgendwo hin ist wieder alles in Ordnung. Nun ja, das wird sich auch noch klären.

Einige Zeit später stellt sich aber heraus, dass die Region mit dieser Version oder in dieser Art nicht betrieben werden sollte, denn hier ist ohne weiteres für fremde User das Einschalten des Godmodes und damit die Übernahme einer Parzelle möglich. Und selbst ohne Eigentümer zu sein kann man die gesamten Regions-Eigenschaften ändern. Am Hippo-Viewer liegt es diesmal nicht (er war gelegentlich im Verdacht den Godmode nicht richtig zu nutzen), sondern offensichtlich an der Zusammenarbeit des Userservers vom Metagrid mit der spezifischen OpenSim-Version. Andere Regionen scheinen – zumindest oberflächlich betrachtet – sicher zu sein.