2007-07-08 04:35:04 +00:00
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Drawing;
|
2008-07-21 21:12:59 +00:00
|
|
|
using OpenMetaverse;
|
|
|
|
|
using OpenMetaverse.Capabilities;
|
|
|
|
|
using OpenMetaverse.Imaging;
|
2007-07-08 04:35:04 +00:00
|
|
|
|
|
|
|
|
namespace importprimscript
|
|
|
|
|
{
|
|
|
|
|
class Sculpt
|
|
|
|
|
{
|
|
|
|
|
public string Name;
|
|
|
|
|
public string TextureFile;
|
2008-07-25 05:15:05 +00:00
|
|
|
public UUID TextureID;
|
2007-07-08 04:35:04 +00:00
|
|
|
public string SculptFile;
|
2008-07-25 05:15:05 +00:00
|
|
|
public UUID SculptID;
|
|
|
|
|
public Vector3 Scale;
|
|
|
|
|
public Vector3 Offset;
|
2007-07-08 04:35:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class importprimscript
|
|
|
|
|
{
|
2008-07-21 21:12:59 +00:00
|
|
|
static GridClient Client = new GridClient();
|
2007-07-08 04:35:04 +00:00
|
|
|
static Sculpt CurrentSculpt = null;
|
|
|
|
|
static AutoResetEvent RezzedEvent = new AutoResetEvent(false);
|
2008-07-25 05:15:05 +00:00
|
|
|
static Vector3 RootPosition = Vector3.Zero;
|
2007-07-08 04:35:04 +00:00
|
|
|
static List<uint> RezzedPrims = new List<uint>();
|
2008-07-25 05:15:05 +00:00
|
|
|
static UUID UploadFolderID = UUID.Zero;
|
2007-07-08 04:35:04 +00:00
|
|
|
|
|
|
|
|
static void Main(string[] args)
|
|
|
|
|
{
|
2008-01-04 22:51:24 +00:00
|
|
|
if (args.Length != 8 && args.Length != 9)
|
2007-07-08 04:35:04 +00:00
|
|
|
{
|
|
|
|
|
Console.WriteLine("Usage: importprimscript.exe [firstname] [lastname] [password] " +
|
2008-01-03 21:27:10 +00:00
|
|
|
"[loginuri] [Simulator] [x] [y] [z] [input.primscript]" +
|
2007-07-08 04:35:04 +00:00
|
|
|
Environment.NewLine + "Example: importprimscript.exe My Bot password " +
|
2008-01-03 21:27:10 +00:00
|
|
|
"Hooper 128 128 40 maya-export" + Path.DirectorySeparatorChar + "ant.primscript" +
|
|
|
|
|
Environment.NewLine + "(the loginuri is optional and only used for logging in to another grid)");
|
2007-07-08 04:35:04 +00:00
|
|
|
Environment.Exit(-1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Strip quotes from any arguments
|
|
|
|
|
for (int i = 0; i < args.Length; i++)
|
|
|
|
|
args[i] = args[i].Trim(new char[] { '"' });
|
|
|
|
|
|
|
|
|
|
// Parse the primscript file
|
2008-01-03 21:27:10 +00:00
|
|
|
string scriptfilename = args[args.Length - 1];
|
2007-07-08 04:35:04 +00:00
|
|
|
string error;
|
2007-11-06 09:26:10 +00:00
|
|
|
List<Sculpt> sculpties = ParsePrimscript(scriptfilename, out error);
|
|
|
|
|
scriptfilename = Path.GetFileNameWithoutExtension(scriptfilename);
|
2007-07-08 04:35:04 +00:00
|
|
|
|
|
|
|
|
// Check for parsing errors
|
|
|
|
|
if (error != String.Empty)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("An error was encountered reading the input file: " + error);
|
|
|
|
|
Environment.Exit(-2);
|
|
|
|
|
}
|
|
|
|
|
else if (sculpties.Count == 0)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("No primitives were read from the input file");
|
|
|
|
|
Environment.Exit(-3);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add callback handlers for asset uploads finishing. new prims spotted, and logging
|
|
|
|
|
Client.Objects.OnNewPrim += new ObjectManager.NewPrimCallback(Objects_OnNewPrim);
|
2008-07-16 16:26:57 +00:00
|
|
|
Logger.OnLogMessage += new Logger.LogCallback(Client_OnLogMessage);
|
2007-07-08 04:35:04 +00:00
|
|
|
|
|
|
|
|
// Optimize the connection for our purposes
|
2007-11-06 09:26:10 +00:00
|
|
|
Client.Self.Movement.Camera.Far = 64f;
|
2007-07-08 04:35:04 +00:00
|
|
|
Client.Settings.MULTIPLE_SIMS = false;
|
|
|
|
|
Client.Settings.SEND_AGENT_UPDATES = true;
|
2008-07-16 16:26:57 +00:00
|
|
|
Client.Settings.DISABLE_AGENT_UPDATE_DUPLICATE_CHECK = true;
|
2008-05-08 17:05:35 +00:00
|
|
|
Settings.LOG_LEVEL = Helpers.LogLevel.None;
|
2007-07-08 04:35:04 +00:00
|
|
|
Client.Settings.ALWAYS_REQUEST_OBJECTS = true;
|
|
|
|
|
Client.Settings.ALWAYS_DECODE_OBJECTS = true;
|
|
|
|
|
Client.Throttle.Land = 0;
|
|
|
|
|
Client.Throttle.Wind = 0;
|
|
|
|
|
Client.Throttle.Cloud = 0;
|
|
|
|
|
// Not sure if Asset or Texture will help with uploads, but it won't hurt
|
|
|
|
|
Client.Throttle.Asset = 220000.0f;
|
|
|
|
|
Client.Throttle.Texture = 446000.0f;
|
|
|
|
|
Client.Throttle.Task = 446000.0f;
|
|
|
|
|
|
2007-11-06 09:26:10 +00:00
|
|
|
// Create a handler for the event queue connecting, so we know when
|
|
|
|
|
// it is safe to start uploading
|
|
|
|
|
AutoResetEvent eventQueueEvent = new AutoResetEvent(false);
|
|
|
|
|
NetworkManager.EventQueueRunningCallback eventQueueCallback =
|
|
|
|
|
delegate(Simulator simulator)
|
|
|
|
|
{
|
|
|
|
|
if (simulator == Client.Network.CurrentSim)
|
|
|
|
|
eventQueueEvent.Set();
|
|
|
|
|
};
|
|
|
|
|
Client.Network.OnEventQueueRunning += eventQueueCallback;
|
|
|
|
|
|
2008-01-03 21:27:10 +00:00
|
|
|
int x = Int32.Parse(args[args.Length - 4]);
|
|
|
|
|
int y = Int32.Parse(args[args.Length - 3]);
|
|
|
|
|
int z = Int32.Parse(args[args.Length - 2]);
|
|
|
|
|
string start = NetworkManager.StartLocation(args[args.Length - 5], x, y, z);
|
|
|
|
|
|
|
|
|
|
LoginParams loginParams = Client.Network.DefaultLoginParams(args[0], args[1], args[2],
|
|
|
|
|
"importprimscript", "1.4.0");
|
|
|
|
|
loginParams.Start = start;
|
|
|
|
|
if (args.Length == 9) loginParams.URI = args[3];
|
2007-07-08 04:35:04 +00:00
|
|
|
|
|
|
|
|
// Attempt to login
|
2008-01-03 21:27:10 +00:00
|
|
|
if (!Client.Network.Login(loginParams))
|
2007-07-08 04:35:04 +00:00
|
|
|
{
|
|
|
|
|
Console.WriteLine("Login failed: " + Client.Network.LoginMessage);
|
|
|
|
|
Environment.Exit(-4);
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-06 09:26:10 +00:00
|
|
|
// Need to be connected to the event queue before we can upload
|
|
|
|
|
Console.WriteLine("Login succeeded, waiting for the event handler to connect...");
|
|
|
|
|
if (!eventQueueEvent.WaitOne(1000 * 90, false))
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("Event queue connection timed out, disconnecting...");
|
|
|
|
|
Client.Network.Logout();
|
|
|
|
|
Environment.Exit(-5);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Don't need this anymore
|
|
|
|
|
Client.Network.OnEventQueueRunning -= eventQueueCallback;
|
2007-07-08 04:35:04 +00:00
|
|
|
|
|
|
|
|
// Set the root position for the import
|
2007-11-06 09:26:10 +00:00
|
|
|
RootPosition = Client.Self.SimPosition;
|
2007-07-08 04:35:04 +00:00
|
|
|
RootPosition.Z += 3.0f;
|
|
|
|
|
|
2007-11-06 09:26:10 +00:00
|
|
|
// TODO: Check if our account balance is high enough to upload everything
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
// Create a folder to hold all of our texture uploads
|
2008-07-29 21:36:53 +00:00
|
|
|
UploadFolderID = Client.Inventory.CreateFolder(Client.Inventory.InventorySkeleton.RootUUID, scriptfilename);
|
2007-11-06 09:26:10 +00:00
|
|
|
|
|
|
|
|
// Loop through each sculpty and do what we need to do
|
2007-07-08 04:35:04 +00:00
|
|
|
for (int i = 0; i < sculpties.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
// Upload the sculpt map and texture
|
|
|
|
|
sculpties[i].SculptID = UploadImage(sculpties[i].SculptFile, true);
|
|
|
|
|
sculpties[i].TextureID = UploadImage(sculpties[i].TextureFile, false);
|
|
|
|
|
|
|
|
|
|
// Check for failed uploads
|
2008-07-25 05:15:05 +00:00
|
|
|
if (sculpties[i].SculptID == UUID.Zero)
|
2007-07-08 04:35:04 +00:00
|
|
|
{
|
2007-11-06 09:26:10 +00:00
|
|
|
Console.WriteLine("Sculpt map " + sculpties[i].SculptFile + " failed to upload, skipping " + sculpties[i].Name);
|
2007-07-08 04:35:04 +00:00
|
|
|
continue;
|
|
|
|
|
}
|
2008-07-25 05:15:05 +00:00
|
|
|
else if (sculpties[i].TextureID == UUID.Zero)
|
2007-07-08 04:35:04 +00:00
|
|
|
{
|
2007-11-06 09:26:10 +00:00
|
|
|
Console.WriteLine("Texture " + sculpties[i].TextureFile + " failed to upload, skipping " + sculpties[i].Name);
|
2007-07-08 04:35:04 +00:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-06 09:26:10 +00:00
|
|
|
// Create basic spherical volume parameters. It will be set to
|
|
|
|
|
// a scultpy in the callback for new objects being created
|
|
|
|
|
LLObject.ObjectData volume = new LLObject.ObjectData();
|
2007-11-30 03:55:08 +00:00
|
|
|
volume.PCode = PCode.Prim;
|
2007-11-06 09:26:10 +00:00
|
|
|
volume.Material = LLObject.MaterialType.Wood;
|
|
|
|
|
volume.PathScaleY = 0.5f;
|
|
|
|
|
volume.PathCurve = LLObject.PathCurve.Circle;
|
2007-12-19 01:11:16 +00:00
|
|
|
volume.ProfileCurve = LLObject.ProfileCurve.Circle;
|
2007-07-08 04:35:04 +00:00
|
|
|
|
|
|
|
|
// Rez this prim
|
|
|
|
|
CurrentSculpt = sculpties[i];
|
2008-07-25 05:15:05 +00:00
|
|
|
Client.Objects.AddPrim(Client.Network.CurrentSim, volume, UUID.Zero,
|
|
|
|
|
RootPosition + CurrentSculpt.Offset, CurrentSculpt.Scale, Quaternion.Identity);
|
2007-07-08 04:35:04 +00:00
|
|
|
|
|
|
|
|
// Wait for the prim to rez and the properties be set for it
|
|
|
|
|
if (!RezzedEvent.WaitOne(1000 * 10, false))
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("Timed out waiting for prim " + CurrentSculpt.Name + " to rez, skipping");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CurrentSculpt = null;
|
|
|
|
|
|
|
|
|
|
lock (RezzedPrims)
|
|
|
|
|
{
|
2007-11-06 09:26:10 +00:00
|
|
|
// Set full permissions for all of the objects
|
2007-07-08 04:35:04 +00:00
|
|
|
Client.Objects.SetPermissions(Client.Network.CurrentSim, RezzedPrims, PermissionWho.All,
|
|
|
|
|
PermissionMask.All, true);
|
|
|
|
|
|
2007-11-06 09:26:10 +00:00
|
|
|
// Link the entire object together
|
2007-07-08 04:35:04 +00:00
|
|
|
Client.Objects.LinkPrims(Client.Network.CurrentSim, RezzedPrims);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Console.WriteLine("Rezzed, textured, and linked " + RezzedPrims.Count + " sculpted prims, logging out...");
|
|
|
|
|
|
|
|
|
|
Client.Network.Logout();
|
|
|
|
|
}
|
|
|
|
|
|
2008-07-16 16:26:57 +00:00
|
|
|
static void Client_OnLogMessage(object message, Helpers.LogLevel level)
|
|
|
|
|
{
|
|
|
|
|
if (level >= Helpers.LogLevel.Warning)
|
|
|
|
|
Console.WriteLine(level + ": " + message);
|
|
|
|
|
}
|
|
|
|
|
|
2008-07-25 05:15:05 +00:00
|
|
|
static UUID UploadImage(string filename, bool lossless)
|
2007-07-08 04:35:04 +00:00
|
|
|
{
|
2008-07-25 05:15:05 +00:00
|
|
|
UUID newAssetID = UUID.Zero;
|
2007-07-08 04:35:04 +00:00
|
|
|
byte[] jp2data = null;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
Bitmap image = (Bitmap)Bitmap.FromFile(filename);
|
2008-07-18 10:29:16 +00:00
|
|
|
jp2data = OpenJPEG.EncodeFromImage(image, lossless);
|
2007-07-08 04:35:04 +00:00
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
2007-11-06 09:26:10 +00:00
|
|
|
Console.WriteLine("Failed to encode image file " + filename + ": " + ex.ToString());
|
2008-07-25 05:15:05 +00:00
|
|
|
return UUID.Zero;
|
2007-07-08 04:35:04 +00:00
|
|
|
}
|
|
|
|
|
|
2007-11-06 09:26:10 +00:00
|
|
|
AutoResetEvent uploadEvent = new AutoResetEvent(false);
|
|
|
|
|
Client.Inventory.RequestCreateItemFromAsset(jp2data, Path.GetFileNameWithoutExtension(filename),
|
|
|
|
|
"Uploaded with importprimscript", AssetType.Texture, InventoryType.Texture, UploadFolderID,
|
2008-05-05 23:41:41 +00:00
|
|
|
|
|
|
|
|
delegate(CapsClient client, long bytesReceived, long bytesSent, long totalBytesToReceive, long totalBytesToSend)
|
|
|
|
|
{
|
|
|
|
|
// FIXME: Do something with progress?
|
|
|
|
|
},
|
|
|
|
|
|
2008-07-25 05:15:05 +00:00
|
|
|
delegate(bool success, string status, UUID itemID, UUID assetID)
|
2007-07-08 04:35:04 +00:00
|
|
|
{
|
2007-11-06 09:26:10 +00:00
|
|
|
if (success)
|
|
|
|
|
{
|
2007-11-30 13:15:31 +00:00
|
|
|
Console.WriteLine("Finished uploading image " + filename + ", AssetID: " + assetID.ToString());
|
2007-11-06 09:26:10 +00:00
|
|
|
newAssetID = assetID;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("Failed to upload image file " + filename + ": " + status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uploadEvent.Set();
|
2007-07-08 04:35:04 +00:00
|
|
|
}
|
2007-11-06 09:26:10 +00:00
|
|
|
);
|
2007-07-08 04:35:04 +00:00
|
|
|
|
2007-11-06 09:26:10 +00:00
|
|
|
// The images are small, 60 seconds should be plenty
|
|
|
|
|
uploadEvent.WaitOne(1000 * 60, false);
|
|
|
|
|
|
|
|
|
|
return newAssetID;
|
2007-07-08 04:35:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void Objects_OnNewPrim(Simulator simulator, Primitive prim, ulong regionHandle, ushort timeDilation)
|
|
|
|
|
{
|
|
|
|
|
if (CurrentSculpt != null && (prim.Flags & LLObject.ObjectFlags.CreateSelected) != 0 &&
|
|
|
|
|
!RezzedPrims.Contains(prim.LocalID))
|
|
|
|
|
{
|
|
|
|
|
lock (RezzedPrims) RezzedPrims.Add(prim.LocalID);
|
|
|
|
|
|
|
|
|
|
Console.WriteLine("Rezzed prim " + CurrentSculpt.Name + ", setting properties");
|
|
|
|
|
|
|
|
|
|
// Deselect the prim
|
|
|
|
|
Client.Objects.DeselectObject(Client.Network.CurrentSim, prim.LocalID);
|
|
|
|
|
|
|
|
|
|
// Set the prim position
|
|
|
|
|
Client.Objects.SetPosition(Client.Network.CurrentSim, prim.LocalID,
|
|
|
|
|
RootPosition + CurrentSculpt.Offset);
|
|
|
|
|
|
|
|
|
|
// Set the texture
|
|
|
|
|
LLObject.TextureEntry textures = new LLObject.TextureEntry(CurrentSculpt.TextureID);
|
|
|
|
|
Client.Objects.SetTextures(Client.Network.CurrentSim, prim.LocalID, textures);
|
|
|
|
|
|
|
|
|
|
// Turn it in to a sculpted prim
|
|
|
|
|
Primitive.SculptData sculpt = new Primitive.SculptData();
|
|
|
|
|
sculpt.SculptTexture = CurrentSculpt.SculptID;
|
|
|
|
|
sculpt.Type = Primitive.SculptType.Sphere;
|
|
|
|
|
Client.Objects.SetSculpt(Client.Network.CurrentSim, prim.LocalID, sculpt);
|
|
|
|
|
|
|
|
|
|
// Set the prim name
|
|
|
|
|
if (!String.IsNullOrEmpty(CurrentSculpt.Name))
|
|
|
|
|
Client.Objects.SetName(Client.Network.CurrentSim, prim.LocalID, CurrentSculpt.Name);
|
|
|
|
|
|
|
|
|
|
RezzedEvent.Set();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static List<Sculpt> ParsePrimscript(string primscriptfile, out string error)
|
|
|
|
|
{
|
|
|
|
|
string line;
|
|
|
|
|
Sculpt current = null;
|
|
|
|
|
List<Sculpt> sculpties = new List<Sculpt>();
|
|
|
|
|
error = String.Empty;
|
|
|
|
|
StreamReader primscript = null;
|
|
|
|
|
|
|
|
|
|
// Parse a directory out of the primscriptfile string, if one exists
|
|
|
|
|
string path = Path.GetDirectoryName(primscriptfile);
|
|
|
|
|
if (!String.IsNullOrEmpty(path))
|
|
|
|
|
path += Path.DirectorySeparatorChar;
|
|
|
|
|
else
|
|
|
|
|
path = String.Empty;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
primscript = File.OpenText(primscriptfile);
|
|
|
|
|
|
|
|
|
|
while ((line = primscript.ReadLine()) != null)
|
|
|
|
|
{
|
|
|
|
|
string[] words = line.Split(new char[] { ' ' });
|
|
|
|
|
|
|
|
|
|
if (words.Length > 0)
|
|
|
|
|
{
|
|
|
|
|
if (current != null)
|
|
|
|
|
{
|
|
|
|
|
switch (words[0])
|
|
|
|
|
{
|
|
|
|
|
case "newPrim":
|
2008-07-25 05:15:05 +00:00
|
|
|
if (current.Scale != Vector3.Zero &&
|
2007-07-08 04:35:04 +00:00
|
|
|
!String.IsNullOrEmpty(current.SculptFile) &&
|
|
|
|
|
!String.IsNullOrEmpty(current.TextureFile))
|
|
|
|
|
{
|
|
|
|
|
// Add the previous prim to the list as it is now finalized
|
|
|
|
|
sculpties.Add(current);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Start a new prim
|
|
|
|
|
current = new Sculpt();
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
case "prim":
|
|
|
|
|
// The only useful bit of information here is the prim name
|
|
|
|
|
if (words.Length >= 3)
|
|
|
|
|
current.Name = words[2];
|
|
|
|
|
break;
|
|
|
|
|
case "shape":
|
|
|
|
|
// This line has the name of the sculpt texture
|
|
|
|
|
if (words.Length >= 3)
|
|
|
|
|
current.SculptFile = path + words[2] + ".bmp";
|
|
|
|
|
break;
|
|
|
|
|
case "texture":
|
|
|
|
|
// This line has the name of the actual texture
|
|
|
|
|
if (words.Length >= 3)
|
|
|
|
|
current.TextureFile = path + words[2] + ".bmp";
|
|
|
|
|
break;
|
|
|
|
|
case "transform":
|
|
|
|
|
// Get some primitive params
|
|
|
|
|
if (words.Length >= 9)
|
|
|
|
|
{
|
|
|
|
|
float x, y, z;
|
|
|
|
|
x = Single.Parse(words[2]);
|
|
|
|
|
y = Single.Parse(words[3]);
|
|
|
|
|
z = Single.Parse(words[4]);
|
2008-07-25 05:15:05 +00:00
|
|
|
current.Scale = new Vector3(x, y, z);
|
2007-07-08 04:35:04 +00:00
|
|
|
|
|
|
|
|
x = Single.Parse(words[6]);
|
|
|
|
|
y = Single.Parse(words[7]);
|
|
|
|
|
z = Single.Parse(words[8]);
|
2008-07-25 05:15:05 +00:00
|
|
|
current.Offset = new Vector3(x, y, z);
|
2007-07-08 04:35:04 +00:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (words[0] == "newPrim")
|
|
|
|
|
{
|
|
|
|
|
// Start a new prim
|
|
|
|
|
current = new Sculpt();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add the final prim
|
2008-07-25 05:15:05 +00:00
|
|
|
if (current != null && current.Scale != Vector3.Zero &&
|
2007-07-08 04:35:04 +00:00
|
|
|
!String.IsNullOrEmpty(current.SculptFile) &&
|
|
|
|
|
!String.IsNullOrEmpty(current.TextureFile))
|
|
|
|
|
{
|
|
|
|
|
// Add the previous prim to the list as it is now finalized
|
|
|
|
|
sculpties.Add(current);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
error = ex.ToString();
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
if (primscript != null)
|
|
|
|
|
primscript.Close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return sculpties;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|