public Species AddNewOrganism(String assemblyPath, Point preferredLocation, Boolean reintroduction)
{
string fullPath = Path.GetFullPath(assemblyPath);
string reportPath = Path.Combine(GameConfig.ApplicationDirectory, Guid.NewGuid() + ".xml");
int validAssembly = PrivateAssemblyCache.checkAssemblyWithReporting(fullPath, reportPath);
if (validAssembly == 0)
{
throw OrganismAssemblyFailedValidationException.GenerateExceptionFromXml(reportPath);
}
if (File.Exists(reportPath))
{
File.Delete(reportPath);
}
byte[] asm;
using (FileStream sourceStream = File.OpenRead(assemblyPath))
{
if (sourceStream.Length > (100*1024))
{
throw new GameEngineException(
"Your organism is greater than 100k in size. Please try to reduce the size of your assembly.");
}
asm = new byte[sourceStream.Length];
sourceStream.Read(asm, 0, (int) sourceStream.Length);
}
// Load the debugging information if it exists
byte[] asmSymbols = null;
if (File.Exists(Path.ChangeExtension(assemblyPath, ".pdb")))
{
using (FileStream sourceStream = File.OpenRead(Path.ChangeExtension(assemblyPath, ".pdb")))
{
asmSymbols = new byte[sourceStream.Length];
sourceStream.Read(asmSymbols, 0, (int) sourceStream.Length);
}
}
// Actually load the assembly from the bytes
Species newSpecies;
Assembly organismAssembly;
try
{
organismAssembly = asmSymbols != null ? Assembly.Load(asm, asmSymbols) : Assembly.Load(asm);
// Make sure organism isn't signed with Terrarium key (e.g. has full trust)
if (SecurityUtils.AssemblyHasTerrariumKey(organismAssembly.GetName()))
{
throw new GameEngineException("You can't introduce assemblies signed with the Terrarium key");
}
newSpecies = Species.GetSpeciesFromAssembly(organismAssembly);
}
// Catch two common fusion errors that occur if you build against the wrong
// organismbase.dll
catch (FileNotFoundException e)
{
if (Path.GetFileName(e.FileName).ToLower(CultureInfo.InvariantCulture) == "organismbase.dll")
{
throw new GameEngineException(
"Your organism is built against the wrong version of organismbase.dll. Build using the version in '" +
Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + "'.");
}
throw;
}
catch (FileLoadException e)
{
if (Path.GetFileName(e.FileName).ToLower(CultureInfo.InvariantCulture).StartsWith("organismbase"))
{
throw new GameEngineException(
"The organism was built using a different version of organismbase.dll than the current client. You may need to change servers to one that supports the build of the client you are running.");
}
throw;
}
catch (BadImageFormatException)
{
throw new GameEngineException(
"Your organism doesn't appear to be a valid .NET Framework assembly. It is possible you're loading an old assembly.");
}
SpeciesServiceStatus speciesResult = SpeciesServiceStatus.Success;
if (!reintroduction)
{
// Load the species to make sure that its attributes conform to our rules (will throw an
// exception if this isn't true
SpeciesService service = new SpeciesService();
service.Url = GameConfig.WebRoot + "/species/addspecies.asmx";
service.Timeout = 60000;
if (EcosystemMode)
{
// If we're in ecosystem mode,
// make sure it has a unique assembly name (which is also the species name)
string speciesType;
if (newSpecies is AnimalSpecies)
{
speciesType = ((AnimalSpecies) newSpecies).IsCarnivore ? "Carnivore" : "Herbivore";
}
else
{
speciesType = "Plant";
}
if (!Regex.IsMatch(newSpecies.AssemblyInfo.ShortName, "[0-9a-zA-Z ]+"))
{
throw new GameEngineException(
"The assembly name of your organism must consist only of ASCII letters, digits, and spaces.");
}
speciesResult = service.Add(newSpecies.AssemblyInfo.ShortName,
Assembly.GetExecutingAssembly().GetName().Version.ToString(),
speciesType, newSpecies.AuthorName, newSpecies.AuthorEmail,
newSpecies.AssemblyInfo.FullName, asm);
}
}
if (reintroduction || speciesResult == SpeciesServiceStatus.Success)
{
if (!_pac.Exists(organismAssembly.FullName))
{
_pac.SaveOrganismAssembly(assemblyPath, Path.ChangeExtension(assemblyPath, ".pdb"),
organismAssembly.FullName);
}
else if (!reintroduction)
{
// If this is not a reintroduction, then the assembly should not be there. If it is, we can't
// ignore it because it could be a user testing out their organism in terrarium mode and if they
// introduce twice with two different assemblies, they'll all end up using the one that's already there
// and not the new one if they save and reload.
if (!EcosystemMode)
{
throw new GameEngineException(
"Organism assemblies can only be introduced once into a Terrarium. \r\n - If you are just trying to add more of these animals, select your animal in the 'Species' dropdown below and push the 'add' button.\r\n - If you are developing an animal and have a new assembly to try, create a new terrarium and introduce it there.");
}
// The server should prevent
throw new GameEngineException(
"Can't add this species because you already have an assembly with the same name in your Ecosystem.");
}
newSpecies = Species.GetSpeciesFromAssembly(_pac.LoadOrganismAssembly(organismAssembly.FullName));
for (int i = 0; i < 10; i++)
{
AddNewOrganism(newSpecies, Point.Empty);
}
}
else switch (speciesResult)
{
case SpeciesServiceStatus.AlreadyExists:
throw new GameEngineException(
"Species name already exists in universe, please choose a new assembly name.");
case SpeciesServiceStatus.FiveMinuteThrottle:
throw new GameEngineException(
"You have submitted another species within the last 5 minutes. Please wait at least 5 minutes between adding new species.");
case SpeciesServiceStatus.TwentyFourHourThrottle:
throw new GameEngineException(
"You have submitted 30 species within the last 24 hours. You now have to wait up to 24 hours to introduce a new species.");
case SpeciesServiceStatus.PoliCheckSpeciesNameFailure:
throw new GameEngineException(
"Your Species Name has failed our basic check for inflammatory terms. Please resubmit using a new name, or if your name was flagged in error, please try using initials or other monikers.");
case SpeciesServiceStatus.PoliCheckAuthorNameFailure:
throw new GameEngineException(
"Your Author Name has failed our basic check for inflammatory terms. Please resubmit using a new name, or if your name was flagged in error, please try using initials or other monikers.");
case SpeciesServiceStatus.PoliCheckEmailFailure:
throw new GameEngineException(
"Your Email has failed our basic check for inflammatory terms. Please resubmit using a different email address.");
default:
throw new GameEngineException("Terrarium is experience some server problems. Please try again later.");
}
return newSpecies;
}