public static void RemoveChild(Session session, LandblockInstanceLink link, List <LandblockInstance> instances) { var child = instances.FirstOrDefault(i => i.Guid == link.ChildGuid); if (child == null) { session.Network.EnqueueSend(new GameMessageSystemChat($"Couldn't find child instance 0x{link.ChildGuid:X8}", ChatMessageType.Broadcast)); return; } instances.Remove(child); var wo = session.Player.CurrentLandblock.GetObject(child.Guid); if (wo != null) { wo.DeleteObject(); session.Network.EnqueueSend(new GameMessageSystemChat($"Removed child {wo.WeenieClassId} - {wo.Name} (0x{wo.Guid}) from landblock instances", ChatMessageType.Broadcast)); } else { session.Network.EnqueueSend(new GameMessageSystemChat($"Couldn't find child object for 0x{link.ChildGuid:X8}", ChatMessageType.Broadcast)); } foreach (var subLink in child.LandblockInstanceLink) { RemoveChild(session, subLink, instances); } }
/// <summary> /// Converts GDLE spawn map -> ACE landblock instances /// /// This will not alter the Guid. To sanitize the Guid for ACE usage, you should use GDLELoader.TryLoadWorldSpawnsConverted() instead. /// </summary> public static bool TryConvert(Models.Landblock input, out List <LandblockInstance> results, out List <LandblockInstanceLink> links) { try { results = new List <LandblockInstance>(); links = new List <LandblockInstanceLink>(); foreach (var value in input.value.weenies) { var result = new LandblockInstance(); result.Guid = value.id; // Collisions and other errors can be caused by invalid input. Data should be sanitized by the running ACE server. //result.Landblock = input.key; ACE uses a virtual column here of (result.ObjCellId >> 16) result.WeenieClassId = value.wcid; result.ObjCellId = value.pos.objcell_id; result.OriginX = value.pos.frame.origin.x; result.OriginY = value.pos.frame.origin.y; result.OriginZ = value.pos.frame.origin.z; result.AnglesW = value.pos.frame.angles.w; result.AnglesX = value.pos.frame.angles.x; result.AnglesY = value.pos.frame.angles.y; result.AnglesZ = value.pos.frame.angles.z; results.Add(result); } if (input.value.links != null) { foreach (var value in input.value.links) { var result = new LandblockInstanceLink(); result.ParentGuid = value.target; result.ChildGuid = value.source; links.Add(result); } } // reguid if needed var landblockId = (ushort)(input.key >> 16); ReGuidAndConvertLandblocks(results, links, landblockId); return(true); } catch { results = null; links = null; return(false); } }
/// <summary> /// This will not alter the Guid. To sanitize the Guid for ACE usage, you should use GDLELoader.TryLoadWorldSpawnsConverted() instead. /// </summary> public static bool TryConvert(Models.Landblock input, out List <Database.Models.World.LandblockInstance> results, out List <Database.Models.World.LandblockInstanceLink> links) { try { results = new List <LandblockInstance>(); links = new List <LandblockInstanceLink>(); foreach (var value in input.Value.Weenies) { var result = new LandblockInstance(); result.Guid = value.Id; // Collisions and other errors can be caused by invalid input. Data should be sanitized by the running ACE server. //result.Landblock = input.key; ACE uses a virtual column here of (result.ObjCellId >> 16) result.WeenieClassId = value.WCID; result.ObjCellId = value.Position.ObjCellId; result.OriginX = (float)value.Position.Frame.Origin.X; result.OriginY = (float)value.Position.Frame.Origin.Y; result.OriginZ = (float)value.Position.Frame.Origin.Z; result.AnglesW = (float)value.Position.Frame.Angles.W; result.AnglesX = (float)value.Position.Frame.Angles.X; result.AnglesY = (float)value.Position.Frame.Angles.Y; result.AnglesZ = (float)value.Position.Frame.Angles.Z; results.Add(result); } if (input.Value.Links != null) { foreach (var value in input.Value.Links) { var result = new LandblockInstanceLink(); result.ParentGuid = value.Target; result.ChildGuid = value.Source; links.Add(result); } } return(true); } catch { results = null; links = null; return(false); } }
private void AddRecord(List <string> fields) { if (CurrentTable == Table.LandblockInstance) { var record = new LandblockInstance(); PopulateFields(record, fields); LandblockInstances.Add(record); } else if (CurrentTable == Table.LandblockInstanceLink) { var record = new LandblockInstanceLink(); PopulateFields(record, fields); LandblockInstanceLinks.Add(record); } }
public static int GetNumChilds(Session session, LandblockInstanceLink link, List <LandblockInstance> instances) { var child = instances.FirstOrDefault(i => i.Guid == link.ChildGuid); if (child == null) { session.Network.EnqueueSend(new GameMessageSystemChat($"Couldn't find child instance 0x{link.ChildGuid:X8}", ChatMessageType.Broadcast)); return(0); } var numChilds = 1; foreach (var subLink in child.LandblockInstanceLink) { numChilds += GetNumChilds(session, subLink, instances); } return(numChilds); }
public static void RemoveInstance(Session session, bool confirmed = false) { var wo = CommandHandlerHelper.GetLastAppraisedObject(session); if (wo == null) { return; } var landblock = (ushort)wo.Location.Landblock; var instances = DatabaseManager.World.GetCachedInstancesByLandblock(landblock); var instance = instances.FirstOrDefault(i => i.Guid == wo.Guid.Full); if (instance == null) { session.Network.EnqueueSend(new GameMessageSystemChat($"Couldn't find landblock_instance for {wo.WeenieClassId} - {wo.Name} (0x{wo.Guid})", ChatMessageType.Broadcast)); return; } var numChilds = instance.LandblockInstanceLink.Count; if (numChilds > 0 && !confirmed) { // get total numChilds iteratively numChilds = 0; foreach (var link in instance.LandblockInstanceLink) { numChilds += GetNumChilds(session, link, instances); } // require confirmation for parent objects var msg = $"Are you sure you want to delete this parent object, and {numChilds} child object{(numChilds != 1 ? "s" : "")}?"; session.Player.ConfirmationManager.EnqueueSend(new Confirmation_Custom(session.Player.Guid, () => RemoveInstance(session, true)), msg); return; } if (instance.IsLinkChild) { LandblockInstanceLink link = null; foreach (var parent in instances.Where(i => i.LandblockInstanceLink.Count > 0)) { link = parent.LandblockInstanceLink.FirstOrDefault(i => i.ChildGuid == instance.Guid); if (link != null) { parent.LandblockInstanceLink.Remove(link); break; } } if (link == null) { session.Network.EnqueueSend(new GameMessageSystemChat($"Couldn't find parent link for child {wo.WeenieClassId} - {wo.Name} (0x{wo.Guid})", ChatMessageType.Broadcast)); return; } } wo.DeleteObject(); foreach (var link in instance.LandblockInstanceLink) { RemoveChild(session, link, instances); } instances.Remove(instance); SyncInstances(session, landblock, instances); session.Network.EnqueueSend(new GameMessageSystemChat($"Removed {(instance.IsLinkChild ? "child " : "")}{wo.WeenieClassId} - {wo.Name} (0x{wo.Guid}) from landblock instances", ChatMessageType.Broadcast)); }
public static void HandleCreateInst(Session session, params string[] parameters) { var loc = new Position(session.Player.Location); var param = parameters[0]; Weenie weenie = null; uint?parentGuid = null; var landblock = session.Player.CurrentLandblock.Id.Landblock; var firstStaticGuid = 0x70000000 | (uint)landblock << 12; if (parameters.Length > 1) { var allParams = string.Join(" ", parameters); var match = Regex.Match(allParams, @"-p ([\S]+) -c ([\S]+)", RegexOptions.IgnoreCase); if (match.Success) { var parentGuidStr = match.Groups[1].Value; param = match.Groups[2].Value; if (parentGuidStr.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) { parentGuidStr = parentGuidStr.Substring(2); } if (!uint.TryParse(parentGuidStr, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var _parentGuid)) { session.Network.EnqueueSend(new GameMessageSystemChat($"Couldn't parse parent guid {match.Groups[1].Value}", ChatMessageType.Broadcast)); return; } parentGuid = _parentGuid; if (parentGuid <= 0xFFF) { parentGuid = firstStaticGuid | parentGuid; } } else if (parameters[1].StartsWith("-c", StringComparison.OrdinalIgnoreCase)) { // get parent from last appraised object var parent = CommandHandlerHelper.GetLastAppraisedObject(session); if (parent == null) { session.Network.EnqueueSend(new GameMessageSystemChat($"Couldn't find parent object", ChatMessageType.Broadcast)); return; } parentGuid = parent.Guid.Full; } } if (uint.TryParse(param, out var wcid)) { weenie = DatabaseManager.World.GetCachedWeenie(wcid); // wcid } else { weenie = DatabaseManager.World.GetCachedWeenie(param); // classname } if (weenie == null) { session.Network.EnqueueSend(new GameMessageSystemChat($"Couldn't find weenie {param}", ChatMessageType.Broadcast)); return; } // clear any cached instances for this landblock DatabaseManager.World.ClearCachedInstancesByLandblock(landblock); var instances = DatabaseManager.World.GetCachedInstancesByLandblock(landblock); // for link mode, ensure parent guid instance exists WorldObject parentObj = null; LandblockInstance parentInstance = null; if (parentGuid != null) { parentInstance = instances.FirstOrDefault(i => i.Guid == parentGuid); if (parentInstance == null) { session.Network.EnqueueSend(new GameMessageSystemChat($"Couldn't find landblock instance for parent guid 0x{parentGuid:X8}", ChatMessageType.Broadcast)); return; } parentObj = session.Player.CurrentLandblock.GetObject(parentGuid.Value); if (parentObj == null) { session.Network.EnqueueSend(new GameMessageSystemChat($"Couldn't find parent object 0x{parentGuid:X8}", ChatMessageType.Broadcast)); return; } } var nextStaticGuid = GetNextStaticGuid(landblock, instances); var maxStaticGuid = firstStaticGuid | 0xFFF; // manually specify a start guid? if (parameters.Length == 2) { if (uint.TryParse(parameters[1].Replace("0x", ""), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var startGuid)) { if (startGuid <= 0xFFF) { startGuid = firstStaticGuid | startGuid; } if (startGuid < firstStaticGuid || startGuid > maxStaticGuid) { session.Network.EnqueueSend(new GameMessageSystemChat($"Landblock instance guid {startGuid:X8} must be between {firstStaticGuid:X8} and {maxStaticGuid:X8}", ChatMessageType.Broadcast)); return; } var existing = instances.FirstOrDefault(i => i.Guid == startGuid); if (existing != null) { session.Network.EnqueueSend(new GameMessageSystemChat($"Landblock instance guid {startGuid:X8} already exists", ChatMessageType.Broadcast)); return; } nextStaticGuid = startGuid; } } if (nextStaticGuid >= maxStaticGuid) { session.Network.EnqueueSend(new GameMessageSystemChat($"Landblock {landblock:X4} has reached the maximum # of static guids", ChatMessageType.Broadcast)); return; } // create and spawn object var wo = WorldObjectFactory.CreateWorldObject(weenie, new ObjectGuid(nextStaticGuid)); if (wo == null) { session.Network.EnqueueSend(new GameMessageSystemChat($"Failed to create new object for {weenie.ClassId} - {weenie.ClassName}", ChatMessageType.Broadcast)); return; } if (!wo.Stuck) { session.Network.EnqueueSend(new GameMessageSystemChat($"{weenie.ClassId} - {weenie.ClassName} is missing PropertyBool.Stuck, cannot spawn as landblock instance", ChatMessageType.Broadcast)); return; } // spawn as ethereal temporarily, to spawn directly on player position wo.Ethereal = true; wo.Location = new Position(loc); // even on flat ground, objects can sometimes fail to spawn at the player's current Z // Position.Z has some weird thresholds when moving around, but i guess the same logic doesn't apply when trying to spawn in... wo.Location.PositionZ += 0.05f; var isLinkChild = parentInstance != null; session.Network.EnqueueSend(new GameMessageSystemChat($"Creating new landblock instance {(isLinkChild ? "child object " : "")}@ {loc.ToLOCString()}\n{wo.WeenieClassId} - {wo.Name} ({nextStaticGuid:X8})", ChatMessageType.Broadcast)); if (!wo.EnterWorld()) { session.Network.EnqueueSend(new GameMessageSystemChat("Failed to spawn new object at this location", ChatMessageType.Broadcast)); return; } // create new landblock instance var instance = CreateLandblockInstance(wo, isLinkChild); instances.Add(instance); if (isLinkChild) { var link = new LandblockInstanceLink(); link.ParentGuid = parentGuid.Value; link.ChildGuid = wo.Guid.Full; link.LastModified = DateTime.Now; parentInstance.LandblockInstanceLink.Add(link); parentObj.LinkedInstances.Add(instance); // ActivateLinks? parentObj.SetLinkProperties(wo); parentObj.ChildLinks.Add(wo); wo.ParentLink = parentObj; } SyncInstances(session, landblock, instances); }