/// <summary> /// This will create a new WorldObject with a new GUID. /// </summary> public static WorldObject CreateNewWorldObject(Weenie weenie) { var guid = GuidManager.NewDynamicGuid(); var worldObject = CreateWorldObject(weenie, guid); if (worldObject == null) { GuidManager.RecycleDynamicGuid(guid); } return(worldObject); }
public bool SummonCreature(Player player, uint wcid, DamageType damageType) { // since we are instantiating regular creatures instead of actual CombatPet weenies atm, // bypassing CreateNewWorldObject() here... //var combatPet = WorldObjectFactory.CreateNewWorldObject(wcid) as CombatPet; var weenie = DatabaseManager.World.GetCachedWeenie(wcid); if (weenie == null) { Console.WriteLine($"Couldn't find pet wcid #{wcid}"); return(false); } var combatPet = new CombatPet(weenie, GuidManager.NewDynamicGuid()); if (combatPet == null) { Console.WriteLine($"PetDevice.UseItem(): failed to create pet for wcid {wcid}"); return(false); } combatPet.Init(player, damageType); return(true); }
/// <summary> /// This will create a new WorldObject with a new GUID. /// </summary> public static WorldObject CreateNewWorldObject(Weenie weenie) { var worldObject = CreateWorldObject(weenie, GuidManager.NewDynamicGuid()); return(worldObject); }
/// <summary> /// This will create a list of WorldObjects, all with new GUIDs and for every position provided. /// </summary> public static List <WorldObject> CreateNewWorldObjects(List <LandblockInstances> sourceObjects) { var results = new List <WorldObject>(); foreach (var instance in sourceObjects.Where(x => x.LinkSlot is null)) { var weenie = DatabaseManager.World.GetCachedWeenie(instance.WeenieClassId); if (weenie == null) { continue; } ObjectGuid guid; if (instance.Guid != 0) { guid = new ObjectGuid(instance.Guid); } else { guid = GuidManager.NewDynamicGuid(); } var worldObject = CreateWorldObject(weenie, guid); if (worldObject != null) { worldObject.Location = new Position(instance.ObjCellId, instance.OriginX, instance.OriginY, instance.OriginZ, instance.AnglesX, instance.AnglesY, instance.AnglesZ, instance.AnglesW); results.Add(worldObject); } } foreach (var instance in sourceObjects.Where(x => !(x.LinkController is null))) { var weenie = DatabaseManager.World.GetCachedWeenie(instance.WeenieClassId); if (weenie == null) { continue; } ObjectGuid guid; if (instance.Guid != 0) { guid = new ObjectGuid(instance.Guid); } else { guid = GuidManager.NewDynamicGuid(); } var worldObject = CreateWorldObject(weenie, guid); if (worldObject != null) { worldObject.Location = new Position(instance.ObjCellId, instance.OriginX, instance.OriginY, instance.OriginZ, instance.AnglesX, instance.AnglesY, instance.AnglesZ, instance.AnglesW); foreach (var link in sourceObjects.Where(x => x.LinkSlot == instance.LinkSlot)) { worldObject.LinkedInstances.Add(link); } results.Add(worldObject); } } return(results); }
/// <summary> /// Import or migrate a character. /// </summary> /// <returns>the result</returns> public static ImportAndMigrateResult ImportAndMigrate(PackageMetadata metadata, byte[] importBytes = null) { if ((metadata.PackageType == PackageType.Backup && !TransferConfigManager.Config.AllowImport) || (metadata.PackageType == PackageType.Migrate && !TransferConfigManager.Config.AllowMigrate)) { return(new ImportAndMigrateResult() { FailReason = ImportAndMigrateFailiureReason.OperationNotAllowed }); } metadata.NewCharacterName = metadata.NewCharacterName.Trim(); if (metadata.NewCharacterName.Length < GameConfiguration.CharacterNameMinimumLength || metadata.NewCharacterName.Length > GameConfiguration.CharacterNameMaximumLength) { return(new ImportAndMigrateResult() { FailReason = ImportAndMigrateFailiureReason.NameTooShortOrTooLong }); } if (TransferManagerUtil.StringContainsInvalidChars(GameConfiguration.AllowedCharacterNameCharacters, metadata.NewCharacterName)) { return(new ImportAndMigrateResult() { FailReason = ImportAndMigrateFailiureReason.NameContainsInvalidCharacters }); } bool NameIsGood = false; ManualResetEvent mre = new ManualResetEvent(false); DatabaseManager.Shard.IsCharacterNameAvailable(metadata.NewCharacterName, isAvailable => { NameIsGood = isAvailable; mre.Set(); }); mre.WaitOne(); if (!NameIsGood) { return(new ImportAndMigrateResult() { FailReason = ImportAndMigrateFailiureReason.NameIsUnavailable }); } // TO-DO: restricted and weenie name matching if (DatManager.PortalDat.TabooTable.ContainsBadWord(metadata.NewCharacterName)) { return(new ImportAndMigrateResult() { FailReason = ImportAndMigrateFailiureReason.NameIsNaughty }); } mre = new ManualResetEvent(false); bool slotCheck = false; DatabaseManager.Shard.GetCharacters(metadata.AccountId, false, new Action <List <Character> >((chars) => { slotCheck = chars.Count + 1 <= GameConfiguration.SlotCount; mre.Set(); })); mre.WaitOne(); if (!slotCheck) { return(new ImportAndMigrateResult() { FailReason = ImportAndMigrateFailiureReason.NoCharacterSlotsAvailable }); } string selectedMigrationSourceThumb = null; CharacterMigrationDownloadResponseModel snapshotPack = null; CharacterTransfer xfer = null; if (importBytes == null) { mre = new ManualResetEvent(false); DatabaseManager.Shard.GetCharacterTransfers((xfers) => { xfer = xfers.FirstOrDefault(k => k.Cookie == metadata.Cookie); mre.Set(); }); mre.WaitOne(); if (xfer != null) { // don't fail here, prevents inter-account same-server transfers and name changes // return new ImportAndMigrateResult() { FailReason = ImportAndMigrateFailiureReason.CookieAlreadyUsed }; } // try to verify we trust the server before downloading package, since migrations cause source server to delete the original char upon download of the package string unverifiedThumbprintsSerialized = null; string nonce = ThreadSafeRandom.NextString(TransferManagerConstants.NonceChars, TransferManagerConstants.NonceLength); try { using (InsecureWebClient iwc = new InsecureWebClient()) { unverifiedThumbprintsSerialized = iwc.DownloadString(metadata.ImportUrl.ToString() + $"api/character/migrationCheck?Cookie={metadata.Cookie}&Nonce={nonce}"); } } catch { return(new ImportAndMigrateResult() { FailReason = ImportAndMigrateFailiureReason.CannotContactSourceServer }); } SignedMigrationCheckResponseModel signedMigrationCheckResult = null; try { signedMigrationCheckResult = JsonConvert.DeserializeObject <SignedMigrationCheckResponseModel>(unverifiedThumbprintsSerialized, TransferManagerUtil.GetSerializationSettings()); } catch { return(new ImportAndMigrateResult() { FailReason = ImportAndMigrateFailiureReason.ProtocolError }); } ImportAndMigrateFailiureReason SignedMigrationCheckResultValidationStatus = TransferManagerUtil.Verify(signedMigrationCheckResult, nonce, out selectedMigrationSourceThumb); if (SignedMigrationCheckResultValidationStatus != ImportAndMigrateFailiureReason.None) { return(new ImportAndMigrateResult() { FailReason = SignedMigrationCheckResultValidationStatus }); } if (!signedMigrationCheckResult.Result.Ready) { return(new ImportAndMigrateResult() { FailReason = ImportAndMigrateFailiureReason.MigrationCheckFailed }); } if ((metadata.PackageType == PackageType.Migrate && !TransferConfigManager.Config.AllowMigrationFrom.Any(k => k == signedMigrationCheckResult.Result.Config.MyThumbprint)) || (metadata.PackageType == PackageType.Backup && !TransferConfigManager.Config.AllowImportFrom.Any(k => k == signedMigrationCheckResult.Result.Config.MyThumbprint))) { return(new ImportAndMigrateResult() { FailReason = ImportAndMigrateFailiureReason.UnverifiedSourceServerNotAllowed }); } if (metadata.PackageType == PackageType.Migrate && !signedMigrationCheckResult.Result.Config.AllowMigrate) { return(new ImportAndMigrateResult() { FailReason = ImportAndMigrateFailiureReason.UnverifiedSourceServerDoesntAllowMigrate }); } try { using (InsecureWebClient iwc = new InsecureWebClient()) { string TransferManagerCharacterMigrationDownloadResponseModelSerialized = iwc.DownloadString(metadata.ImportUrl.ToString() + $"api/character/migrationDownload?Cookie={metadata.Cookie}"); snapshotPack = JsonConvert.DeserializeObject <CharacterMigrationDownloadResponseModel>(TransferManagerCharacterMigrationDownloadResponseModelSerialized, TransferManagerUtil.GetSerializationSettings()); } } catch (Exception) { return(new ImportAndMigrateResult() { FailReason = ImportAndMigrateFailiureReason.ProtocolError }); } if (snapshotPack == null) { return(new ImportAndMigrateResult()); } if (!snapshotPack.Success) { return(new ImportAndMigrateResult() { FailReason = ImportAndMigrateFailiureReason.SourceServerRejectedRequest }); } } string tmpFilePath = Path.GetTempFileName(); DirectoryInfo diTmpDirPath = Directory.CreateDirectory(Path.Combine(Path.GetDirectoryName(tmpFilePath), Path.GetFileNameWithoutExtension(tmpFilePath))); string signerCertPath = Path.Combine(diTmpDirPath.FullName, "signer.crt"); if (importBytes == null) { File.WriteAllBytes(tmpFilePath, snapshotPack.SnapshotPackage); } else { File.WriteAllBytes(tmpFilePath, importBytes); } using (ZipArchive zip = ZipFile.OpenRead(tmpFilePath)) { zip.ExtractToDirectory(diTmpDirPath.FullName); } File.Delete(tmpFilePath); if (!File.Exists(signerCertPath)) { Directory.Delete(diTmpDirPath.FullName, true); return(new ImportAndMigrateResult() { FailReason = ImportAndMigrateFailiureReason.PackageUnsigned }); } string verifiedSourceThumbprint = string.Empty; using (X509Certificate2 signer = new X509Certificate2(signerCertPath)) { verifiedSourceThumbprint = signer.Thumbprint; // verify that the signer is in the trusted signers list if ((metadata.PackageType == PackageType.Migrate && !TransferConfigManager.Config.AllowMigrationFrom.Any(k => k == verifiedSourceThumbprint)) || (metadata.PackageType == PackageType.Backup && !TransferConfigManager.Config.AllowImportFrom.Any(k => k == verifiedSourceThumbprint))) { Directory.Delete(diTmpDirPath.FullName, true); return(new ImportAndMigrateResult() { FailReason = ImportAndMigrateFailiureReason.VerifiedSourceServerNotAllowed }); } if (!string.IsNullOrWhiteSpace(selectedMigrationSourceThumb) && verifiedSourceThumbprint != selectedMigrationSourceThumb) { return(new ImportAndMigrateResult() { FailReason = ImportAndMigrateFailiureReason.VerifiedMigrationSourceThumbprintMismatch }); } // verify that the signatures are valid foreach (FileInfo fil in diTmpDirPath.GetFiles("*.json")) { if (!CertificateManager.VerifySignedFile(fil.FullName, signer)) { Directory.Delete(diTmpDirPath.FullName, true); return(new ImportAndMigrateResult() { FailReason = ImportAndMigrateFailiureReason.CharacterPackageSignatureInvalid }); } } } // deserialize PackageMetadata packInfo = null; List <Biota> snapshot = new List <Biota>(); foreach (FileInfo fil in diTmpDirPath.GetFiles("*.json")) { if (fil.Name == "packinfo.json") { packInfo = JsonConvert.DeserializeObject <PackageMetadata>(File.ReadAllText(fil.FullName), TransferManagerUtil.GetSerializationSettings()); } else { snapshot.Add(JsonConvert.DeserializeObject <Biota>(File.ReadAllText(fil.FullName), TransferManagerUtil.GetSerializationSettings())); } } if (packInfo == null) { Directory.Delete(diTmpDirPath.FullName, true); return(new ImportAndMigrateResult() { FailReason = ImportAndMigrateFailiureReason.PackInfoNotFound }); } if (packInfo.PackageType != metadata.PackageType) { return(new ImportAndMigrateResult() { FailReason = ImportAndMigrateFailiureReason.WrongPackageType }); } if (importBytes == null) { xfer = null; mre = new ManualResetEvent(false); DatabaseManager.Shard.GetCharacterTransfers((xfers) => { xfer = xfers.FirstOrDefault(k => k.SourceId == packInfo.CharacterId); mre.Set(); }); mre.WaitOne(); if (xfer != null) { return(new ImportAndMigrateResult() { FailReason = ImportAndMigrateFailiureReason.CharacterAlreadyPresent }); } } // isolate player biota List <Biota> playerCollection = snapshot.Where(k => ( k.WeenieType == (uint)WeenieType.Admin || k.WeenieType == (uint)WeenieType.Sentinel || k.WeenieType == (uint)WeenieType.Creature ) ).ToList(); if (playerCollection.Count > 1) { Directory.Delete(diTmpDirPath.FullName, true); return(new ImportAndMigrateResult() { FailReason = ImportAndMigrateFailiureReason.FoundMoreThanOneCharacter }); } if (playerCollection.Count < 1) { Directory.Delete(diTmpDirPath.FullName, true); return(new ImportAndMigrateResult() { FailReason = ImportAndMigrateFailiureReason.CannotFindCharacter }); } IEnumerable <Biota> possessedBiotas2 = snapshot.Except(playerCollection).ToList(); Biota newCharBiota = playerCollection.First(); uint playerOrigId = newCharBiota.Id; // refactor ObjectGuid guid = GuidManager.NewPlayerGuid(); newCharBiota = TransferManagerUtil.SetGuidAndScrubPKs(newCharBiota, guid.Full); List <BiotaPropertiesString> nameProp = newCharBiota.BiotaPropertiesString.Where(k => k.Type == (ushort)PropertyString.Name).ToList(); if (nameProp.Count != 1) { Directory.Delete(diTmpDirPath.FullName, true); return(new ImportAndMigrateResult() { FailReason = ImportAndMigrateFailiureReason.MalformedCharacterData }); } string FormerCharName = nameProp.First().Value; nameProp.First().Value = metadata.NewCharacterName; Collection <(Biota biota, ReaderWriterLockSlim rwLock)> possessedBiotas = new Collection <(Biota biota, ReaderWriterLockSlim rwLock)>(); foreach (Biota possession in possessedBiotas2) { possessedBiotas.Add((TransferManagerUtil.SetGuidAndScrubPKs(possession, GuidManager.NewDynamicGuid().Full), new ReaderWriterLockSlim())); } foreach ((Biota biota, ReaderWriterLockSlim rwLock)item in possessedBiotas) { IEnumerable <BiotaPropertiesIID> instances = item.biota.BiotaPropertiesIID.Where(k => k.Value == playerOrigId); foreach (BiotaPropertiesIID instance in instances) { instance.Value = guid.Full; } } foreach ((Biota biota, ReaderWriterLockSlim rwLock)item in possessedBiotas) { IEnumerable <BiotaPropertiesBookPageData> instances = item.biota.BiotaPropertiesBookPageData.Where(k => k.AuthorId == playerOrigId); foreach (BiotaPropertiesBookPageData instance in instances) { instance.AuthorId = guid.Full; } //TO-DO: scrub other authors? } // build Weenie weenie = DatabaseManager.World.GetCachedWeenie(newCharBiota.WeenieClassId); weenie.Type = newCharBiota.WeenieType; Player newPlayer = new Player(weenie, guid, metadata.AccountId) { Location = new Position(0xD655002C, 126.918549f, 81.756134f, 49.698814f, 0.794878f, 0.000000f, 0.000000f, -0.606769f), // Shoushi starter area Name = metadata.NewCharacterName, }; newPlayer.Character.Name = metadata.NewCharacterName; // insert mre = new ManualResetEvent(false); bool addCharResult = false; DatabaseManager.Shard.AddCharacterInParallel(newCharBiota, newPlayer.BiotaDatabaseLock, possessedBiotas, newPlayer.Character, newPlayer.CharacterDatabaseLock, new Action <bool>((res2) => { addCharResult = res2; mre.Set(); })); mre.WaitOne(); if (addCharResult) { // update server PlayerManager.AddOfflinePlayer(DatabaseManager.Shard.GetBiota(guid.Full)); DatabaseManager.Shard.GetCharacters(metadata.AccountId, false, new Action <List <Character> >((chars) => { Session session = WorldManager.Find(metadata.AccountId); if (session != null) { session.Characters.Add(chars.First(k => k.Id == guid.Full)); } })); DatabaseManager.Shard.SaveCharacterTransfer(new CharacterTransfer() { AccountId = metadata.AccountId, SourceId = packInfo.CharacterId, TransferType = (uint)metadata.PackageType, TransferTime = (ulong)Time.GetUnixTime(), Cookie = metadata.Cookie, SourceBaseUrl = (importBytes == null) ? metadata.ImportUrl.ToString() : null, SourceThumbprint = verifiedSourceThumbprint, TargetId = guid.Full, }, new ReaderWriterLockSlim(), null); } else { Directory.Delete(diTmpDirPath.FullName, true); return(new ImportAndMigrateResult() { FailReason = ImportAndMigrateFailiureReason.AddCharacterFailed }); } // cleanup Directory.Delete(diTmpDirPath.FullName, true); // done return(new ImportAndMigrateResult() { Success = true, NewCharacterName = metadata.NewCharacterName, NewCharacterId = guid.Full }); }
/// <summary> /// This will create a list of WorldObjects, all with new GUIDs and for every position provided. /// </summary> public static List <WorldObject> CreateNewWorldObjects(List <LandblockInstances> sourceObjects) { var results = new List <WorldObject>(); var linkSourceResults = new List <LandblockInstances>(); var linkResults = new Dictionary <int, List <LandblockInstances> >(); foreach (var aceO in sourceObjects) { if (aceO.LinkSlot > 0) { if (aceO.LinkController ?? false) { linkSourceResults.Add(aceO); continue; } if (!linkResults.ContainsKey((int)aceO.LinkSlot)) { linkResults.Add((int)aceO.LinkSlot, new List <LandblockInstances>()); } linkResults[(int)aceO.LinkSlot].Add(aceO); continue; } var weenie = DatabaseManager.World.GetCachedWeenie(aceO.WeenieClassId); if (weenie == null) { continue; } ObjectGuid guid; if (aceO.Guid != 0) { guid = new ObjectGuid(aceO.Guid); } else { guid = GuidManager.NewDynamicGuid(); } var worldObject = CreateWorldObject(weenie, guid); if (worldObject != null) { worldObject.SetPosition(PositionType.Location, new Position(aceO.ObjCellId, aceO.OriginX, aceO.OriginY, aceO.OriginZ, aceO.AnglesX, aceO.AnglesY, aceO.AnglesZ, aceO.AnglesW)); results.Add(worldObject); } } foreach (var aceO in linkSourceResults) { int linkSlot = (int)aceO.LinkSlot; var weenie = DatabaseManager.World.GetCachedWeenie(aceO.WeenieClassId); if (weenie == null) { continue; } ObjectGuid guid; if (aceO.Guid != 0) { guid = new ObjectGuid(aceO.Guid); } else { guid = GuidManager.NewDynamicGuid(); } var worldObject = CreateWorldObject(weenie, guid); if (worldObject == null) { continue; } worldObject.SetPosition(PositionType.Location, new Position(aceO.ObjCellId, aceO.OriginX, aceO.OriginY, aceO.OriginZ, aceO.AnglesX, aceO.AnglesY, aceO.AnglesZ, aceO.AnglesW)); if (linkResults.ContainsKey(linkSlot) && worldObject.GeneratorProfiles.Count > 0) { var profileTemplate = worldObject.GeneratorProfiles[0]; foreach (var link in linkResults[linkSlot]) { var profile = new BiotaPropertiesGenerator(); profile.WeenieClassId = link.WeenieClassId; profile.ObjCellId = link.ObjCellId; profile.OriginX = link.OriginX; profile.OriginY = link.OriginY; profile.OriginZ = link.OriginZ; profile.AnglesW = link.AnglesW; profile.AnglesX = link.AnglesX; profile.AnglesY = link.AnglesY; profile.AnglesZ = link.AnglesZ; profile.Probability = Math.Abs(profileTemplate.Probability); profile.InitCreate = profileTemplate.InitCreate; profile.MaxCreate = profileTemplate.MaxCreate; profile.WhenCreate = profileTemplate.WhenCreate; profile.WhereCreate = profileTemplate.WhereCreate; worldObject.GeneratorProfiles.Add(profile); } worldObject.SelectGeneratorProfiles(); worldObject.UpdateGeneratorInts(); worldObject.QueueGenerator(); } if (linkResults.ContainsKey(linkSlot) && worldObject.GeneratorProfiles.Count == 0) { log.Error($"Encountered an Instance ({aceO.Id}) Linked to a Weenie ({aceO.WeenieClassId}) with no GeneratorProfiles to template from."); } results.Add(worldObject); } return(results); }
/// <summary> /// This will create a new WorldObject with a new GUID. /// </summary> public static WorldObject CreateNewWorldObject(Weenie weenie, AppliedRuleset ruleset) { var worldObject = CreateWorldObject(weenie, GuidManager.NewDynamicGuid(), ruleset); return(worldObject); }