mirror of
https://github.com/opensim/opensim.git
synced 2026-08-12 20:55:43 +08:00
Very early first implementation of grid based assets.
Run this on a major grid, and weep
This commit is contained in:
@@ -36,6 +36,7 @@ using libsecondlife.Packets;
|
||||
using OpenSim.Framework.Interfaces;
|
||||
using OpenSim.Framework.Types;
|
||||
using OpenSim.Framework.Utilities;
|
||||
using OpenSim.Framework.Console;
|
||||
|
||||
namespace OpenSim.Framework.Communications.Cache
|
||||
{
|
||||
@@ -319,17 +320,19 @@ namespace OpenSim.Framework.Communications.Cache
|
||||
|
||||
public void AssetNotFound(LLUUID assetID)
|
||||
{
|
||||
/*
|
||||
if (this.RequestedTextures.ContainsKey(assetID))
|
||||
{
|
||||
MainLog.Instance.Warn("ASSET CACHE", "sending image not found for {0}", assetID);
|
||||
AssetRequest req = this.RequestedTextures[assetID];
|
||||
ImageNotInDatabasePacket notFound = new ImageNotInDatabasePacket();
|
||||
notFound.ImageID.ID = assetID;
|
||||
req.RequestUser.OutPacket(notFound);
|
||||
//Console.WriteLine("sending image not found for " + assetID);
|
||||
|
||||
this.RequestedTextures.Remove(assetID);
|
||||
}*/
|
||||
}
|
||||
else
|
||||
{
|
||||
MainLog.Instance.Error("ASSET CACHE", "Cound not send image not found for {0}", assetID);
|
||||
}
|
||||
}
|
||||
|
||||
#region Assets
|
||||
|
||||
@@ -108,23 +108,23 @@ namespace OpenSim.Framework.Communications.Cache
|
||||
public virtual List<AssetBase> GetDefaultAssets()
|
||||
{
|
||||
List<AssetBase> assets = new List<AssetBase>();
|
||||
// These assets have been moved into the OpenSimAssetSet.XML file
|
||||
//assets.Add(CreateImageAsset("00000000-0000-1111-9999-000000000001", "Bricks", "bricks.jp2"));
|
||||
//assets.Add(CreateImageAsset("00000000-0000-1111-9999-000000000002", "Plywood", "plywood.jp2"));
|
||||
//assets.Add(CreateImageAsset("00000000-0000-1111-9999-000000000003", "Rocks", "rocks.jp2"));
|
||||
//assets.Add(CreateImageAsset("00000000-0000-1111-9999-000000000004", "Granite", "granite.jp2"));
|
||||
//assets.Add(CreateImageAsset("00000000-0000-1111-9999-000000000005", "Hardwood", "hardwood.jp2"));
|
||||
//assets.Add(CreateImageAsset("00000000-0000-1111-5005-000000000005", "Prim Base Texture", "plywood.jp2"));
|
||||
//assets.Add(CreateImageAsset("00000000-0000-1111-9999-000000000006", "Map Base Texture", "map_base.jp2"));
|
||||
//assets.Add(CreateImageAsset("00000000-0000-1111-9999-000000000007", "Map Texture", "map1.jp2"));
|
||||
//assets.Add(CreateImageAsset("00000000-0000-1111-9999-000000000010", "Female Body Texture", "femalebody.jp2"));
|
||||
//assets.Add(CreateImageAsset("00000000-0000-1111-9999-000000000011", "Female Bottom Texture", "femalebottom.jp2"));
|
||||
//assets.Add(CreateImageAsset("00000000-0000-1111-9999-000000000012", "Female Face Texture", "femaleface.jp2"));
|
||||
|
||||
assets.Add(CreateImageAsset("00000000-0000-0000-9999-000000000001", "Bricks", "bricks.jp2"));
|
||||
assets.Add(CreateImageAsset("00000000-0000-0000-9999-000000000002", "Plywood", "plywood.jp2"));
|
||||
assets.Add(CreateImageAsset("00000000-0000-0000-9999-000000000003", "Rocks", "rocks.jp2"));
|
||||
assets.Add(CreateImageAsset("00000000-0000-0000-9999-000000000004", "Granite", "granite.jp2"));
|
||||
assets.Add(CreateImageAsset("00000000-0000-0000-9999-000000000005", "Hardwood", "hardwood.jp2"));
|
||||
assets.Add(CreateImageAsset("00000000-0000-0000-5005-000000000005", "Prim Base Texture", "plywood.jp2"));
|
||||
assets.Add(CreateImageAsset("00000000-0000-0000-9999-000000000006", "Map Base Texture", "map_base.jp2"));
|
||||
assets.Add(CreateImageAsset("00000000-0000-0000-9999-000000000007", "Map Texture", "map1.jp2"));
|
||||
assets.Add(CreateImageAsset("00000000-0000-0000-9999-000000000010", "Female Body Texture", "femalebody.jp2"));
|
||||
assets.Add(CreateImageAsset("00000000-0000-0000-9999-000000000011", "Female Bottom Texture", "femalebottom.jp2"));
|
||||
assets.Add(CreateImageAsset("00000000-0000-0000-9999-000000000012", "Female Face Texture", "femaleface.jp2"));
|
||||
|
||||
assets.Add(CreateAsset("77c41e39-38f9-f75a-024e-585989bbabbb", "Skin", "base_skin.dat", false));
|
||||
assets.Add(CreateAsset("66c41e39-38f9-f75a-024e-585989bfab73", "Shape", "base_shape.dat", false));
|
||||
assets.Add(CreateAsset("00000000-38f9-1111-024e-222222111110", "Shirt", "newshirt.dat", false));
|
||||
assets.Add(CreateAsset("00000000-38f9-1111-024e-222222111120", "Shirt", "newpants.dat", false));
|
||||
//assets.Add(CreateAsset("77c41e39-38f9-f75a-024e-585989bbabbb", "Skin", "base_skin.dat", false));
|
||||
//assets.Add(CreateAsset("66c41e39-38f9-f75a-024e-585989bfab73", "Shape", "base_shape.dat", false));
|
||||
//assets.Add(CreateAsset("00000000-38f9-1111-024e-222222111110", "Shirt", "newshirt.dat", false));
|
||||
//assets.Add(CreateAsset("00000000-38f9-1111-024e-222222111120", "Shirt", "newpants.dat", false));
|
||||
|
||||
return assets;
|
||||
}
|
||||
@@ -185,4 +185,4 @@ namespace OpenSim.Framework.Communications.Cache
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
160
OpenSim/Framework/Communications/Cache/GridAssetClient.cs
Normal file
160
OpenSim/Framework/Communications/Cache/GridAssetClient.cs
Normal file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://www.openmetaverse.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSim Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Reflection;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
using libsecondlife;
|
||||
|
||||
using Nini.Config;
|
||||
using OpenSim.Framework.Console;
|
||||
using OpenSim.Framework.Interfaces;
|
||||
using OpenSim.Framework.Types;
|
||||
using OpenSim.Framework.Utilities;
|
||||
using OpenSim.Framework.Communications;
|
||||
|
||||
namespace OpenSim.Framework.Communications.Cache
|
||||
{
|
||||
public class GridAssetClient : IAssetServer
|
||||
{
|
||||
private string _assetServerUrl;
|
||||
private IAssetReceiver _receiver;
|
||||
|
||||
public GridAssetClient(string serverUrl)
|
||||
{
|
||||
_assetServerUrl = serverUrl;
|
||||
}
|
||||
|
||||
#region IAssetServer Members
|
||||
|
||||
public void SetReceiver(IAssetReceiver receiver)
|
||||
{
|
||||
_receiver = receiver;
|
||||
}
|
||||
|
||||
public void FetchAsset(LLUUID assetID, bool isTexture)
|
||||
{
|
||||
Stream s = null;
|
||||
try
|
||||
{
|
||||
|
||||
MainLog.Instance.Debug("ASSETCACHE", "Querying for {0}", assetID.ToString());
|
||||
|
||||
RestClient rc = new RestClient(_assetServerUrl);
|
||||
rc.AddResourcePath("assets");
|
||||
rc.AddResourcePath(assetID.ToString());
|
||||
if (isTexture)
|
||||
rc.AddQueryParameter("texture");
|
||||
|
||||
rc.RequestMethod = "GET";
|
||||
s = rc.Request();
|
||||
|
||||
if (s.Length > 0)
|
||||
{
|
||||
XmlSerializer xs = new XmlSerializer(typeof(AssetBase));
|
||||
AssetBase asset = (AssetBase)xs.Deserialize(s);
|
||||
|
||||
_receiver.AssetReceived(asset, isTexture);
|
||||
}
|
||||
else
|
||||
{
|
||||
MainLog.Instance.Debug("ASSETCACHE", "Asset not found {0}", assetID.ToString());
|
||||
_receiver.AssetNotFound(assetID);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MainLog.Instance.Error("ASSETCACHE", e.Message);
|
||||
MainLog.Instance.Error("ASSETCACHE", e.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateAsset(AssetBase asset)
|
||||
{
|
||||
throw new Exception("The method or operation is not implemented.");
|
||||
}
|
||||
|
||||
public void StoreAndCommitAsset(AssetBase asset)
|
||||
{
|
||||
try
|
||||
{
|
||||
MemoryStream s = new MemoryStream();
|
||||
|
||||
XmlSerializer xs = new XmlSerializer(typeof(AssetBase));
|
||||
xs.Serialize(s, asset);
|
||||
RestClient rc = new RestClient(_assetServerUrl);
|
||||
rc.AddResourcePath("assets");
|
||||
rc.RequestMethod = "POST";
|
||||
rc.Request(s);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MainLog.Instance.Error("ASSETS", e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
throw new Exception("The method or operation is not implemented.");
|
||||
}
|
||||
|
||||
public void LoadAsset(AssetBase info, bool image, string filename)
|
||||
{
|
||||
throw new Exception("The method or operation is not implemented.");
|
||||
}
|
||||
|
||||
public System.Collections.Generic.List<AssetBase> GetDefaultAssets()
|
||||
{
|
||||
throw new Exception("The method or operation is not implemented.");
|
||||
}
|
||||
|
||||
public AssetBase CreateImageAsset(string assetIdStr, string name, string filename)
|
||||
{
|
||||
throw new Exception("The method or operation is not implemented.");
|
||||
}
|
||||
|
||||
public void ForEachDefaultAsset(Action<AssetBase> action)
|
||||
{
|
||||
throw new Exception("The method or operation is not implemented.");
|
||||
}
|
||||
|
||||
public AssetBase CreateAsset(string assetIdStr, string name, string filename, bool isImage)
|
||||
{
|
||||
throw new Exception("The method or operation is not implemented.");
|
||||
}
|
||||
|
||||
public void ForEachXmlAsset(Action<AssetBase> action)
|
||||
{
|
||||
throw new Exception("The method or operation is not implemented.");
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace OpenSim.Framework.RestClient
|
||||
namespace OpenSim.Framework.Communications
|
||||
{
|
||||
internal class SimpleAsyncResult : IAsyncResult
|
||||
{
|
||||
|
||||
@@ -6,7 +6,9 @@ using System.Text;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace OpenSim.Framework.RestClient
|
||||
using OpenSim.Framework.Console;
|
||||
|
||||
namespace OpenSim.Framework.Communications
|
||||
{
|
||||
/// <summary>
|
||||
/// Implementation of a generic REST client
|
||||
@@ -25,8 +27,11 @@ namespace OpenSim.Framework.RestClient
|
||||
/// other threads to execute, while it waits for a response from the web-service. RestClient it self, can be
|
||||
/// invoked by the caller in either synchroneous mode or asynchroneous mode.
|
||||
/// </remarks>
|
||||
public class RestClient
|
||||
public class RestClient
|
||||
{
|
||||
|
||||
string realuri;
|
||||
#region member variables
|
||||
/// <summary>
|
||||
/// The base Uri of the web-service e.g. http://www.google.com
|
||||
/// </summary>
|
||||
@@ -55,7 +60,7 @@ namespace OpenSim.Framework.RestClient
|
||||
/// <summary>
|
||||
/// MemoryStream representing the resultiong resource
|
||||
/// </summary>
|
||||
MemoryStream _resource;
|
||||
Stream _resource;
|
||||
|
||||
/// <summary>
|
||||
/// WebRequest object, held as a member variable
|
||||
@@ -89,6 +94,9 @@ namespace OpenSim.Framework.RestClient
|
||||
/// </summary>
|
||||
private Exception _asyncException;
|
||||
|
||||
#endregion member variables
|
||||
|
||||
#region constructors
|
||||
/// <summary>
|
||||
/// Instantiate a new RestClient
|
||||
/// </summary>
|
||||
@@ -100,8 +108,12 @@ namespace OpenSim.Framework.RestClient
|
||||
_resource = new MemoryStream();
|
||||
_request = null;
|
||||
_response = null;
|
||||
_lock = new object();
|
||||
}
|
||||
|
||||
object _lock;
|
||||
#endregion constructors
|
||||
|
||||
/// <summary>
|
||||
/// Add a path element to the query, e.g. assets
|
||||
/// </summary>
|
||||
@@ -124,6 +136,15 @@ namespace OpenSim.Framework.RestClient
|
||||
_parameterElements.Add(HttpUtility.UrlEncode(name), HttpUtility.UrlEncode(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a query parameter to the Url
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the parameter, e.g. min</param>
|
||||
public void AddQueryParameter(string name)
|
||||
{
|
||||
_parameterElements.Add(HttpUtility.UrlEncode(name), null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Web-Request method, e.g. GET, PUT, POST, DELETE
|
||||
/// </summary>
|
||||
@@ -185,9 +206,10 @@ namespace OpenSim.Framework.RestClient
|
||||
sb.Append(kv.Value);
|
||||
}
|
||||
}
|
||||
realuri = sb.ToString();
|
||||
return new Uri(sb.ToString());
|
||||
}
|
||||
|
||||
#region Async communications with server
|
||||
/// <summary>
|
||||
/// Async method, invoked when a block of data has been received from the service
|
||||
/// </summary>
|
||||
@@ -199,7 +221,6 @@ namespace OpenSim.Framework.RestClient
|
||||
Stream s = (Stream)ar.AsyncState;
|
||||
int read = s.EndRead(ar);
|
||||
|
||||
// Read the HTML page and then print it to the console.
|
||||
if (read > 0)
|
||||
{
|
||||
_resource.Write(_readbuf, 0, read);
|
||||
@@ -207,7 +228,6 @@ namespace OpenSim.Framework.RestClient
|
||||
|
||||
// TODO! Implement timeout, without killing the server
|
||||
//ThreadPool.RegisterWaitForSingleObject(asynchronousResult.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), _request, DefaultTimeout, true);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -261,32 +281,83 @@ namespace OpenSim.Framework.RestClient
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion Async communications with server
|
||||
|
||||
/// <summary>
|
||||
/// Perform synchroneous request
|
||||
/// </summary>
|
||||
public Stream Request()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_request = (HttpWebRequest)WebRequest.Create(buildUri());
|
||||
_request.KeepAlive = false;
|
||||
_request.ContentType = "application/xml";
|
||||
_request.Timeout = 200000;
|
||||
_asyncException = null;
|
||||
|
||||
// IAsyncResult responseAsyncResult = _request.BeginGetResponse(new AsyncCallback(ResponseIsReadyDelegate), _request);
|
||||
_response = (HttpWebResponse)_request.GetResponse();
|
||||
Stream src = _response.GetResponseStream();
|
||||
int length = src.Read(_readbuf, 0, BufferSize);
|
||||
while(length > 0)
|
||||
{
|
||||
_resource.Write(_readbuf, 0, length);
|
||||
length = src.Read(_readbuf, 0, BufferSize);
|
||||
}
|
||||
|
||||
|
||||
// TODO! Implement timeout, without killing the server
|
||||
// this line implements the timeout, if there is a timeout, the callback fires and the request becomes aborted
|
||||
//ThreadPool.RegisterWaitForSingleObject(responseAsyncResult.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), _request, DefaultTimeout, true);
|
||||
|
||||
// _allDone.WaitOne();
|
||||
if (_response != null)
|
||||
_response.Close();
|
||||
if (_asyncException != null)
|
||||
throw _asyncException;
|
||||
|
||||
if (_resource != null)
|
||||
{
|
||||
_resource.Flush();
|
||||
_resource.Seek(0, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
return _resource;
|
||||
}
|
||||
}
|
||||
|
||||
public Stream Request(Stream src)
|
||||
{
|
||||
_request = (HttpWebRequest)WebRequest.Create(buildUri());
|
||||
_request.KeepAlive = false;
|
||||
_request.ContentType = "text/html";
|
||||
_request.Timeout = 200;
|
||||
_request.ContentType = "application/xml";
|
||||
_request.Timeout = 900000;
|
||||
_request.Method = RequestMethod;
|
||||
_asyncException = null;
|
||||
_request.ContentLength = src.Length;
|
||||
|
||||
IAsyncResult responseAsyncResult = _request.BeginGetResponse(new AsyncCallback(ResponseIsReadyDelegate), _request);
|
||||
src.Seek(0, SeekOrigin.Begin);
|
||||
Stream dst = _request.GetRequestStream();
|
||||
byte[] buf = new byte[1024];
|
||||
int length = src.Read(buf,0, 1024);
|
||||
while (length > 0)
|
||||
{
|
||||
dst.Write(buf, 0, length);
|
||||
length = src.Read(buf, 0, 1024);
|
||||
}
|
||||
_response = (HttpWebResponse)_request.GetResponse();
|
||||
|
||||
// IAsyncResult responseAsyncResult = _request.BeginGetResponse(new AsyncCallback(ResponseIsReadyDelegate), _request);
|
||||
|
||||
// TODO! Implement timeout, without killing the server
|
||||
// this line implements the timeout, if there is a timeout, the callback fires and the request becomes aborted
|
||||
//ThreadPool.RegisterWaitForSingleObject(responseAsyncResult.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), _request, DefaultTimeout, true);
|
||||
|
||||
_allDone.WaitOne();
|
||||
if(_response != null)
|
||||
_response.Close();
|
||||
if (_asyncException != null)
|
||||
throw _asyncException;
|
||||
return _resource;
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
#region Async Invocation
|
||||
public IAsyncResult BeginRequest(AsyncCallback callback, object state)
|
||||
{
|
||||
|
||||
@@ -71,22 +71,24 @@ namespace OpenSim.Framework.Data.MySQL
|
||||
public AssetBase FetchAsset(LLUUID assetID)
|
||||
{
|
||||
AssetBase asset = null;
|
||||
|
||||
MySqlCommand cmd = new MySqlCommand("SELECT name, description, assetType, invType, local, temporary, data FROM assets WHERE id=?id", _dbConnection.Connection);
|
||||
MySqlParameter p = cmd.Parameters.Add("?id", MySqlDbType.Binary, 16);
|
||||
p.Value = assetID.GetBytes();
|
||||
using (MySqlDataReader dbReader = cmd.ExecuteReader(System.Data.CommandBehavior.SingleRow))
|
||||
lock (_dbConnection)
|
||||
{
|
||||
if (dbReader.Read())
|
||||
MySqlCommand cmd = new MySqlCommand("SELECT name, description, assetType, invType, local, temporary, data FROM assets WHERE id=?id", _dbConnection.Connection);
|
||||
MySqlParameter p = cmd.Parameters.Add("?id", MySqlDbType.Binary, 16);
|
||||
p.Value = assetID.GetBytes();
|
||||
using (MySqlDataReader dbReader = cmd.ExecuteReader(System.Data.CommandBehavior.SingleRow))
|
||||
{
|
||||
asset = new AssetBase();
|
||||
asset.Data = (byte[])dbReader["data"];
|
||||
asset.Description = (string)dbReader["description"];
|
||||
asset.FullID = assetID;
|
||||
asset.InvType = (sbyte)dbReader["invType"];
|
||||
asset.Local = ((sbyte)dbReader["local"]) != 0 ? true : false;
|
||||
asset.Name = (string)dbReader["name"];
|
||||
asset.Type = (sbyte)dbReader["assetType"];
|
||||
if (dbReader.Read())
|
||||
{
|
||||
asset = new AssetBase();
|
||||
asset.Data = (byte[])dbReader["data"];
|
||||
asset.Description = (string)dbReader["description"];
|
||||
asset.FullID = assetID;
|
||||
asset.InvType = (sbyte)dbReader["invType"];
|
||||
asset.Local = ((sbyte)dbReader["local"]) != 0 ? true : false;
|
||||
asset.Name = (string)dbReader["name"];
|
||||
asset.Type = (sbyte)dbReader["assetType"];
|
||||
}
|
||||
}
|
||||
}
|
||||
return asset;
|
||||
|
||||
@@ -25,10 +25,12 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
using System;
|
||||
using libsecondlife;
|
||||
|
||||
namespace OpenSim.Framework.Types
|
||||
{
|
||||
[Serializable]
|
||||
public class AssetBase
|
||||
{
|
||||
public byte[] Data;
|
||||
|
||||
Reference in New Issue
Block a user