„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!“ 😀

Virtuelles (Zusammen-)Leben organisieren

Die Motivation, sich in eine 3D-Umgebung zu begeben, dürfte bei den meisten Menschen ähnlich sein, und vermutlich unterscheidet sie sich auch nicht von der Antriebskraft, die vor fünfhundert oder tausend Jahren Menschen bewegte, in neue Welten aufzubrechen: Neugier. Doch wie kann es gelingen, dass Menschen auch in einer virtuellen Welt bleiben, dass sie nicht die Lust daran nach einer gewissen Zeit verlieren oder gar aus Frust, Enttäuschung oder Ärger wieder ab- oder weiterziehen? Mit anderen Worten: Wie kann es gelingen, virtuelles Leben und Zusammenleben so zu organisieren, dass diejenigen, die daran teilhaben, den Spaß nicht verlieren?

Virtuelles (Zusammen-)Leben organisieren weiterlesen

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.

Ein Kongress-Zentrum

Kongresszentrum

Eine der freien Sims, die ich auf meinem lokalen Simulator mal importiert habe, enthält übrigens ein komplettes Kongress-Zentrum inklusive eines Vortragssaals mit (gefühlten) hundert Stühlen – wenn die mal alle besetzt sind, ist der Simulator wahrscheinlich so lahm, dass keine Kommunikation mehr möglich ist 😉 – und diversen anderen Einrichtungen. Wenn man es gerne großmächtig haben möchte, ist so etwas dann die ideale Startsim…

Die Sim stammt übrigens von OpenVCE.

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

Schaffe, schaffe, Möbel packe

Nachdem ich meine Hütte auf Utopia mit einem zweiten Geschoss versehen habe, fiel mir heute Nachmittag auf, dass die zweite Etage ja ziemlich leer und ungemütlich ist. Dabei bietet gerade sie sich als Platz zum Hocken an. Leider sind Möbelläden auf Metropolis noch Mangelware, aber ich wollte nicht auch noch die nächste Etage mit Baumstämmen ausstatten.

Also habe ich mein Second Inventory angeworfen. Das hatte ich ursprünglich mal angeschafft, um Objekte von SL auf die OpenSim zu transportieren, aber mit seiner restriktiven Rechtehandhabung erlaubt SL das nicht außer für vollkommen eigene Objekte.

Anders verhält sich das bei Open Sim, und so habe ich mal einen tollen Relax-Stuhl, den Bert vor Kurzem mal gebastelt hat, rübertransferiert. Das Ganze ging problemlos mitsamt Skripten und Animation.

Allerdings bin ich jetzt auf Utopia laut Eigenschaften der Creator – was natürlich nicht stimmt.

Basteln, basteln, basteln

Nun, es wird allmählich etwas belebt auf meinem Stück Land mit Namen ‚Vanaltens Restplace‘. Diese Parzelle erstreckt sich ja hier – anders als in unterteilten Regionen üblich – auf die gesamte Region ‚Vanalten‘. Erste Bäume hab ich heute ‚gepflanzt‘ und zwei Treppen an das Grundgerüst vom Haus angeflanscht. Ich mag diese Technik mit den cut-path-Zylindern die dann einen angenehmen Zugang ermöglichen aus jeder Richtung. Bin ja nicht so der Typ der Enge mag wie bekannt 😉

Apropos Bäume, wenn wir das Problem mit den Links in den Griff bekommen haben – das hat zunächst Priorität – dann möchte ich auch gerne die geliebten Copses wieder implementieren, so nenn ich sie immer: Es handelt sich um selbst wachsende und sich vermehrende Bäume, ein nettes Feature. Man sollte allerdings darauf achten das Ganze etwas zu begrenzen, sonst hat man schnell ein nahezu undurchdringliches Dickicht (gut, es ist alles phantom, insofern ^^). Diese sich selbst fortpflanzenden Teile sind tatsächlich nett, denn es kehrt etwas virtuelles Leben ein und die Situation die man vorfindet ist nicht immer dieselbe. Es kann sehr erstaunlich sein was es bedeutet wenn manchmal 100 unerwartete Bäume irgendwo rumstehen, ganz abgesehen davon dass man auch unter Umständen damit konfrontiert wird zumindest temporär im Wohnzimmer die Äste einer Eiche durch die Wände kommen zu sehen.

Die Geschichte mit den linked-Prims ist wirklich lästig, nun ich hab das Verzeichnis mal kopiert und eingefroren, werde übersichtliche Versionen der Config-Files erzeugen und dann in einen exakten Vergleich einsteigen um festzustellen, was da jetzt so anders ist im Vergleich zu unserer sauberen 0.6.6er (die übrigens immer noch stabil läuft, siehe hier). Im Moment müssen wir halt zur Not auf die Sandbox ausweichen, denn wie Roland mir erzählt hat klappt das Übertragen dort verlinkter Objekte zu unseren Regionen einwandfrei und der Verbund bleibt auch erhalten.