はじめに
2012年のアドベントカレンダーからlibopenmetaverse関連の事を紹介してきて、この時期じゃないとlibopenmetaverseについて触れていない気がします。libopenmetaverse カテゴリーの記事一覧 - なんとなく
やらなくちゃと自分自身に厳しくできるので、こういう企画は好きです。
さて、 セカンドライフ技術系 Advent Calendar 2014 - Adventarの1個目のエントリです。 当初、プロフィールを表示することをネタにしようと思って書き始めたのですが、長くなってしまいました。完走させるためにも2部構成にしようと思います。 なので、1個目のエントリです。
概要
全体的な流れとしては、フレンドリストの対象項目(青で囲んだところ)を押下したら、ダイアログで対象のアバターのプロフィールを表示させるということを説明していきたいと思います。とりあえず、今回はフレンドリストの作成です。
libopenmetaverseはC#で書かれているのに、Androidなの?と疑問を持つ方もいらっしゃるかもしれません。 Xamarin.Androidで実現しています。
フレンドリストの作成
画像の左側のリスト作成の説明です。
使用するlibopenmetaverseのメンバーの説明とか
libopenmetaverseにおいて、アバターのフレンドリストは、OpenMetaverse.FriendsManager.FriendList
というプロパティに格納されています。
public InternalDictionary<UUID, FriendInfo> FriendList
と定義されています。
http://lib.openmetaverse.org/docs/trunk/?topic=html/F_OpenMetaverse_FriendsManager_FriendList.htm
FriendInfo
クラスは
Member | Description |
---|---|
CanModifyMyObjects | True if the freind can modify my objects |
CanModifyTheirObjects | True if I can modify my friend's objects |
CanSeeMeOnline | True if the friend can see if I am online |
CanSeeMeOnMap | True if the friend can see me on the map |
CanSeeThemOnline | True if I can see if my friend is online |
CanSeeThemOnMap | True if I can see if my friend is on the map |
IsOnline | True if the avatar is online |
MyFriendRights | My rights represented as bitmapped flags |
Name | full name of the avatar |
TheirFriendRights | My friend's rights represented as bitmapped flags |
ToString() | FriendInfo represented as a string(Overrides Object.ToString().) |
UUID | System ID of the avatar |
と定義されています。
http://lib.openmetaverse.org/docs/trunk/?topic=html/T_OpenMetaverse_FriendInfo.htm
InternalDictionary
もlibopenmetaverse独自のクラスのようです。
http://lib.openmetaverse.org/docs/trunk/?topic=html/T_OpenMetaverse_InternalDictionary_2.htm
フレンドリストは以上を使って取得できます。今回はUUIDとIsOnlineを取得し、Nameについては取得しません。 Nameにはついて、2010年ごろにDisplayNameが実装されたため、DisplayNameに対応していません。 そのため別途DisplayNameの取得をする必要があります。
そこで、DisplayNameは、
OpenMetaverse.AvatarManagerGetDisplayNames
というメッソッドで取得出来ます。
public void GetDisplayNames( List<UUID> ids, AvatarManager.DisplayNamesCallback callback )
と定義されています。
DisplayNamesCallbackは
public delegate void DisplayNamesCallback( bool success, AgentDisplayName[] names, UUID[] badIDs )
と定義されています。
AgentDisplayName
クラスは、
Member | Description |
---|---|
AgentDisplayName() | Initializes a new instance of the AgentDisplayName class |
DisplayName | Display name |
FromOSD(OSD) | Creates AgentDisplayName object from OSD |
GetOSD() | Return object as OSD map |
ID | Agent UUID |
IsDefaultDisplayName | Is display name default display name |
LegacyFirstName | First name (legacy) |
LegacyFullName | Full name (legacy) |
LegacyLastName | Last name (legacy) |
NextUpdate | Cache display name until |
ToString() | (Overrides Object.ToString().) |
Updated | Last updated timestamp |
UserName | Username |
と定義されています。
http://lib.openmetaverse.org/docs/trunk/?topic=html/T_OpenMetaverse_AgentDisplayName.htm
GetDisplayNamesを使用し、DisplayNamesCallbackで得られるAgentDisplayName[]からDisplayNameとUserNameを取得します。
なお、DisplayNameの仕様としてUsernames and display names - Second Lifeにおいて、
You can choose whether or not to show other Residents' display names and usernames inworld. If you choose to view display names or usernames, they appear in the name tags above every avatar and in chat.
とあるように、 displaynameを表示させるのかusernameを表示させるのか選択できるので、それにしたがって表示を対応させます。
IsDefaultDisplayName
を使って判断します。
また、そもそもdisplaynameを設定していない場合もあり、いわゆるレガシーなfullnameを取得します。
OpenMetaverse.AvatarManager.RequestAvatarNames
を使用します。以前にも紹介したと思いますので、URIを参照ください。
http://lib.openmetaverse.org/docs/trunk/?topic=html/E_OpenMetaverse_AvatarManager_UUIDNameReply.htm
実装
省きながらではあるけど、実際にどういうふうに実装しているかについて見て行きたいと思います。ソースコードとその説明です。
ソース
List<UUID> Buddy = new List<UUID>(); //フレンドリスト取得 Client.Friends.FriendList.ForEach(delegate(FriendInfo friendInfo){ //UUIDとIsOnlineの値をList<AvatarData>な入れ物に格納 BuddyIDisOnline.Add(new AvatarData(friendInfo.UUID,null,null,false,friendInfo.IsOnline)); Buddy.Add(friendInfo.UUID); }); //DisplayName取得、取れない場合は名前を取得する DisplayNamesDone = new AutoResetEvent (false); Client.Avatars.GetDisplayNames(Buddy,BuddyDisplayNamesCallback); DisplayNamesDone.WaitOne(); Client.Avatars.RequestAvatarNames(BuddyBadIDs); BuddyBadIDs.Clear(); //List<AvatarData>な入れ物をUUIDをキーにjoinして、オンラインでソートし、asciiコード順でソート var query = from s in BuddyIDName join t in BuddyIDisOnline on s.AvatarID equals t.AvatarID orderby t.IsOnline descending,s.AvatarName ascending select new {AvatarID= s.AvatarID,AvatarName = s.AvatarName,AvatarDisplayName = s.AvatarDisplayName,IsDefaultDisplayName = s.IsDefaultDisplayName,IsOnline = t.IsOnline}; BuddyIDNameisOnline.Clear(); //adapterに入れるものに入れなおす foreach(var t in query) { BuddyIDNameisOnline.Add(new AvatarData(t.AvatarID,t.AvatarName,t.AvatarDisplayName,t.IsDefaultDisplayName,t.IsOnline)); } BuddyIDName.Clear(); BuddyIDisOnline.Clear();
イベントハンドラやコールバックなど
Client.Avatars.UUIDNameReply += (object sender, UUIDNameReplyEventArgs e) => { foreach (KeyValuePair<UUID,string> kvp in e.Names) { //UUIDとNAMEを取得 BuddyIDName.Add(new AvatarData(kvp.Key,kvp.Value,null,false)); } }; DisplayNamesCallback += new AvatarManager.DisplayNamesCallback (BuddyDisplayNamesCallback);
コールバックの実態
private void BuddyDisplayNamesCallback(bool success,AgentDisplayName[] DisplayNames,UUID[] BadIDs) { //得られたUUID,username(takeshich.nakamura),DisplayName,IsDefaultDisplayName(デフォルトの表示をDisplayNameにするか)を格納 foreach(AgentDisplayName displayname in DisplayNames) { BuddyIDName.Add(new AvatarData(displayname.ID,displayname.UserName,displayname.DisplayName,displayname.IsDefaultDisplayName)); } //DisplayNameを得られなかったものについて取得 foreach (UUID s in BadIDs) { BuddyBadIDs.Add(s); } }
実装説明
- DisplayNameを取得するため、FriendListにおいてFriendInfoクラスのUUIDをList
に格納します。 - オンラインかについて判断したいので、FriendInfoクラスのUUIDとIsOnlineをカスタムクラスに格納します。
- DisplayNameを取得します。
- UUID,usename(例Takeshich.Nakamura),DisplayName,IsDefaultDisplayName(デフォルトの表示をDisplayNameにするか)を格納しています。
- DisplayNameを得られなかったものについて、UUIDとNAMEを格納しています。
- それぞれを格納したものをUUIDをキーにjoinして、リストを表示させるために並び順を変更します。
- 再度ListAdapterに入れるための入れ物に入れ直します。
フレンドリストのうちオンラインのアバターを先に表示(UserName,DisplayName)し、さらに赤い文字にしています。 そして、それらをasciiコード順で表示、オフラインのアバターについてもasciiコード順で表示しています。
まとめ
ざっと説明してきました。Xamarin.Androidの視点からみるところは、省いてたりします。。。(ListViewにcustomadapterいれるところとか、Dialogを表示するために必要な値の渡し方とか)
まぁ、Viewerの中ではこんな感じなんだよということを少しでも感じていただければと思います。 これでフレンドリストが作成できたので、アバターのUUIDを使って、プロフィールを取得し、表示するということを次回見ていくことにします。