private void Analyze(Type mainType, EngineVersion version) { // Get the attribute for the main structure type Structure = GetStructureAttribute(mainType, version); if (Structure == null) throw new InvalidOperationException("No TagStructure attribute which matches the target version was found on " + mainType.Name); // Scan through the type's inheritance hierarchy and analyze each TagStructure attribute var currentType = mainType; Types = new List<Type>(); while (currentType != null) { var attrib = (currentType != mainType) ? GetStructureAttribute(currentType, version) : Structure; if (attrib != null) { Types.Add(currentType); TotalSize += attrib.Size; if (attrib.Class != null) { if (GroupTag.Value == -1) GroupTag = new Tag(attrib.Class); else if (ParentGroupTag.Value == -1) ParentGroupTag = new Tag(attrib.Class); else if (GrandparentGroupTag.Value == -1) GrandparentGroupTag = new Tag(attrib.Class); } } currentType = currentType.BaseType; } }
/// <summary> /// Connects a tag index to a tag in another version. /// </summary> /// <param name="version1">The first version.</param> /// <param name="index1">The tag index in the first version.</param> /// <param name="version2">The second version.</param> /// <param name="index2">The tag index in the second version.</param> public void Add(EngineVersion version1, int index1, EngineVersion version2, int index2) { // Get both version maps, creating them if they don't exist VersionMap map1, map2; if (!_versionMaps.TryGetValue(version1, out map1)) { map1 = new VersionMap(); _versionMaps[version1] = map1; } if (!_versionMaps.TryGetValue(version2, out map2)) { map2 = new VersionMap(); _versionMaps[version2] = map2; } // Check if the first index is in the map for the first version. // If it is, then we'll get a "global index" which can be used to look it up in other versions. // If it isn't, then we need to make a new global index for it. var globalIndex = map1.GetGlobalTagIndex(index1); if (globalIndex < 0) { globalIndex = _nextGlobalTagIndex; _nextGlobalTagIndex++; map1.Add(globalIndex, index1); } // Connect the global index to the second index in the second version map2.Add(globalIndex, index2); }
public void Read(EndianStream stream) { string signature = stream.ReadStringZeroTerm(); Type = ParseSignature(signature); Generation = (BundleGeneration)stream.ReadInt32(); PlayerVersion = stream.ReadStringZeroTerm(); string engineVersion = stream.ReadStringZeroTerm(); EngineVersion.Parse(engineVersion); switch (Type) { case BundleType.UnityRaw: case BundleType.UnityWeb: case BundleType.HexFA: ReadRawWeb(stream); break; case BundleType.UnityFS: ReadFileStream(stream); break; default: throw new Exception($"Unknown bundle signature '{Type}'"); } }
private int[,] readTextureChunkOffsets(EngineVersion engineVersion, byte[] data, int offset, int x1, int y1, int x2, int y2) { int[,] chunkOffsets = new int[100, 100]; int addr; for (int y = y1; y <= y2; ++y) { for (int x = x1; x <= x2; ++x) { int cellOffset = ((y - y1) * 100 + x - x1) * 8; // This test is needed to deal with town.world in BGDA which addresses textures outside of the maximum x range. if (data.Length >= offset + cellOffset + 4) { if (EngineVersion.ReturnToArms == engineVersion) { // TODO: Figure out what this should really be addr = 0x800; } else { addr = DataUtil.getLEInt(data, offset + cellOffset); } chunkOffsets[y, x] = addr; } } } return(chunkOffsets); }
public void CreateZonesFile(string inputFilename, string outputFilename, string guid, string userName, long userId, string completitionCode, DeviceType device, EngineVersion version) { FileStream inputStream = null; Cartridge cartridge; try { // Open Lua file inputStream = new FileStream(inputFilename, FileMode.Open); // Create input object for plain folders IInput input = new Folder(inputStream, inputFilename); // Check Lua file input.Check(); // Load Lua code and extract all required data cartridge = input.Load(); // Close input input = null; } finally { if (inputStream != null) { inputStream.Close(); inputStream = null; } } // Create selected engine IEngine engine = Compiler.CreateEngine(device); // Convert Lua code and insert special code for this player cartridge = engine.ConvertCartridge(cartridge); userName = engine.ConvertString(userName); // ---------- Compile Lua code into binary chunk ---------- // Compile Lua code cartridge.Chunk = LUA.Compile(cartridge.LuaCode, cartridge.LuaFileName); // ---------- Save cartridge as GWC file ---------- // Create object for output format (could be also WFC or any other IOutput) var outputFormat = new GWC(); // Write output file // Create output in correct format var ms = outputFormat.Create(cartridge, userName, userId, completitionCode); // Save output to file using(FileStream ofs = new FileStream(outputFilename, FileMode.Create)) { ms.CopyTo(ofs); // Close output ofs.Flush(); ofs.Close(); } }
public LmpFile(EngineVersion engineVersion, string name, byte[] data, int startOffset, int dataLen) { _engineVersion = engineVersion; Name = name; FileData = data; _startOffset = startOffset; _dataLen = dataLen; }
public GobFile(EngineVersion engineVersion, string filepath) { _engineVersion = engineVersion; _filepath = filepath; FileData = File.ReadAllBytes(filepath); ReadDirectory(); Filename = System.IO.Path.GetFileName(filepath); }
/// <summary> /// Gets the timestamp for a version. /// </summary> /// <param name="version">The version.</param> /// <returns>The timestamp, or -1 for <see cref="EngineVersion.Unknown"/>.</returns> public static long GetTimestamp(EngineVersion version) { if (version == EngineVersion.Unknown) { return(-1); } return(VersionTimestamps[(int)version]); }
/// <summary> /// Creates a stringID resolver for a given engine version. /// </summary> /// <param name="version">The version.</param> /// <returns>The resolver.</returns> public static StringIdResolverBase Create(EngineVersion version) { if (VersionDetection.Compare(version, EngineVersion.V12_1_700123_cert_ms30_oct19) >= 0) return new V12_1_700123.StringIdResolver(); if (VersionDetection.Compare(version, EngineVersion.V11_1_498295_Live) >= 0) return new V11_1_498295.StringIdResolver(); return new V1_106708.StringIdResolver(); }
/// <summary> /// Creates a vertex stream for a given engine version. /// </summary> /// <param name="version">The engine version.</param> /// <param name="stream">The base stream.</param> /// <returns>The created vertex stream.</returns> public static IVertexStream Create(EngineVersion version, Stream stream) { if (VersionDetection.Compare(version, EngineVersion.V1_235640_cert_ms25) >= 0) { return(new V1_235640.VertexStream(stream)); } return(new V1_106708.VertexStream(stream)); }
/// <summary> /// Constructs a <see cref="TagStructureInfo"/> object which contains info about a tag structure type. /// </summary> /// <param name="structureType">The tag structure type to analyze.</param> /// <param name="version">The engine version to compare attributes against.</param> public TagStructureInfo(Type structureType, EngineVersion version) { Version = version; GroupTag = new Tag(-1); ParentGroupTag = new Tag(-1); GrandparentGroupTag = new Tag(-1); Analyze(structureType, version); }
private void layoutAProjectLevelSelector_SelectedIndexChanged(object sender, EventArgs e) { LevelInfo level = project.GetLevelInfo(levels[layoutAProjectLevelSelector.SelectedIndex]); ringformat = level.RingFormat; SetRingFormat(); CheckOKButton(); }
/// <summary> /// Default constructor /// </summary> /// <param name="majorEngineVersion">The major engine version</param> /// <param name="engineVersion">The engine version</param> /// <param name="game">The game</param> /// <param name="displayName">The display name</param> /// <param name="managerType">The manager type</param> public GameModeAttribute(MajorEngineVersion majorEngineVersion, EngineVersion engineVersion, Game game, string displayName, Type managerType) { MajorEngineVersion = majorEngineVersion; EngineVersion = engineVersion; Game = game; DisplayName = displayName; ManagerType = managerType; }
public World(EngineVersion engineVersion, string dataPath, string name) { if (string.IsNullOrEmpty(dataPath)) Debug.Fail("Datapath is null"); EngineVersion = engineVersion; DataPath = dataPath; Name = name; }
/// <summary> /// Initializes a new instance of the <see cref="MeshReader"/> class. /// </summary> /// <param name="version">The engine version to target.</param> /// <param name="mesh">The mesh.</param> /// <param name="definition">The mesh's definition data.</param> public MeshReader(EngineVersion version, Mesh mesh, RenderGeometryResourceDefinition definition) { _version = version; Mesh = mesh; Definition = definition; VertexStreams = new VertexBufferDefinition[StreamCount]; IndexBuffers = new IndexBufferDefinition[IndexBufferCount]; BindVertexStreams(); BindIndexBuffers(); }
public World(EngineVersion engineVersion, string dataPath, string name) { if (string.IsNullOrEmpty(dataPath)) { Debug.Fail("Datapath is null"); } EngineVersion = engineVersion; DataPath = dataPath; Name = name; }
public override int GetHashCode() { int hash = 1; if (Raw.Length != 0) { hash ^= Raw.GetHashCode(); } if (Platform.Length != 0) { hash ^= Platform.GetHashCode(); } if (Os.Length != 0) { hash ^= Os.GetHashCode(); } if (OsVersion.Length != 0) { hash ^= OsVersion.GetHashCode(); } if (Engine.Length != 0) { hash ^= Engine.GetHashCode(); } if (EngineVersion.Length != 0) { hash ^= EngineVersion.GetHashCode(); } if (Browser.Length != 0) { hash ^= Browser.GetHashCode(); } if (BrowserVersion.Length != 0) { hash ^= BrowserVersion.GetHashCode(); } if (Localization.Length != 0) { hash ^= Localization.GetHashCode(); } if (Mobile != false) { hash ^= Mobile.GetHashCode(); } if (WalletCompatible != false) { hash ^= WalletCompatible.GetHashCode(); } if (_unknownFields != null) { hash ^= _unknownFields.GetHashCode(); } return(hash); }
/// <summary> /// Initializes a new instance of the <see cref="RenderModelBuilder"/> class for a particular engine version. /// </summary> public RenderModelBuilder(EngineVersion version) { _version = version; _model.Regions = new List<RenderModel.Region>(); _model.Nodes = new List<RenderModel.Node>(); _model.RuntimeNodes = new List<RenderModel.RuntimeNode>(); _model.Materials = new List<RenderModel.Material>(); _model.Meshes = new List<Mesh>(); _model.Unknown1C = -1; // "Flair Starting Model Section Index" in Assembly _model.Unknown64 = 7; // TODO: Figure out what this does, if anything }
public static AnimData Decode(EngineVersion engineVersion, byte[] data, int startOffset, int length) { if (engineVersion == EngineVersion.ReturnToArms) { return(DecodeCRTA(engineVersion, data, startOffset, length)); } else { return(DecodeBGDA(engineVersion, data, startOffset, length)); } }
public WorldTexFile(EngineVersion engineVersion, string filepath) { _engineVersion = engineVersion; _filepath = filepath; fileData = File.ReadAllBytes(filepath); Filename = Path.GetFileName(_filepath); if (EngineVersion.ReturnToArms == _engineVersion) { _entries = ReadEntries(fileData); } }
/// <summary> /// Creates a stringID resolver for a given engine version. /// </summary> /// <param name="version">The version.</param> /// <returns>The resolver.</returns> public static StringIdResolverBase Create(EngineVersion version) { if (VersionDetection.Compare(version, EngineVersion.V12_1_700123_cert_ms30_oct19) >= 0) { return(new V12_1_700123.StringIdResolver()); } if (VersionDetection.Compare(version, EngineVersion.V11_1_498295_Live) >= 0) { return(new V11_1_498295.StringIdResolver()); } return(new V1_106708.StringIdResolver()); }
public static Sprite MapDPLCToBmp(byte[] artfile, byte[] mapfile, EngineVersion mapversion, byte[] dplc, EngineVersion dplcversion, int frame, int startpal, bool priority = false) { if (mapversion == EngineVersion.Invalid) { mapversion = LevelData.Game.MappingsVersion; } if (dplcversion == EngineVersion.Invalid) { dplcversion = LevelData.Game.DPLCVersion; } return(LevelData.MapFrameToBmp(artfile, MappingsFrame.Load(mapfile, mapversion)[frame], DPLCFrame.Load(dplc, dplcversion)[frame], startpal, priority)); }
/// <summary> /// Determines whether a version number is between two other version numbers (inclusive). /// </summary> /// <param name="compare">The version number to compare. If this is <see cref="EngineVersion.Unknown"/>, this function will always return <c>true</c>.</param> /// <param name="min">The minimum version number. If this is <see cref="EngineVersion.Unknown"/>, then the lower bound will be ignored.</param> /// <param name="max">The maximum version number. If this is <see cref="EngineVersion.Unknown"/>, then the upper bound will be ignored.</param> /// <returns></returns> public static bool IsBetween(EngineVersion compare, EngineVersion min, EngineVersion max) { if (compare == EngineVersion.Unknown) { return(true); } if (min != EngineVersion.Unknown && Compare(compare, min) < 0) { return(false); } return(max == EngineVersion.Unknown || Compare(compare, max) <= 0); }
/// <summary> /// Gets the version string corresponding to an <see cref="EngineVersion"/> value. /// </summary> /// <param name="version">The version.</param> /// <returns>The version string.</returns> public static string GetVersionString(EngineVersion version) { switch (version) { case EngineVersion.V1_106708_cert_ms23: return("1.106708 cert_ms23"); case EngineVersion.V1_235640_cert_ms25: return("1.235640 cert_ms23"); case EngineVersion.V0_0_1_301003_cert_MS26_new: return("0.0.1.301003 cert_MS26_new"); case EngineVersion.V0_4_1_327043_cert_MS26_new: return("0.4.1.327043 cert_MS26_new"); case EngineVersion.V8_1_372731_Live: return("8.1.372731 Live"); case EngineVersion.V0_0_416097_Live: return("0.0.416097 Live"); case EngineVersion.V10_1_430475_Live: return("10.1.430475 Live"); case EngineVersion.V10_1_454665_Live: return("10.1.454665 Live"); case EngineVersion.V10_1_449175_Live: return("10.1.449175 Live"); case EngineVersion.V11_1_498295_Live: return("11.1.498295 Live"); case EngineVersion.V11_1_530605_Live: return("11.1.530605 Live"); case EngineVersion.V11_1_532911_Live: return("11.1.532911 Live"); case EngineVersion.V11_1_554482_Live: return("11.1.554482 Live"); case EngineVersion.V11_1_571627_Live: return("11.1.571627 Live"); case EngineVersion.V12_1_700123_cert_ms30_oct19: return("12.1.700123 cert_ms30_oct19"); default: return(version.ToString()); } }
public static Sprite MapASMDPLCToBmp(byte[] artfile, string mapfileloc, EngineVersion mapversion, string dplcloc, EngineVersion dplcversion, int frame, int startpal, bool priority = false) { if (mapversion == EngineVersion.Invalid) { mapversion = LevelData.Game.MappingsVersion; } if (dplcversion == EngineVersion.Invalid) { dplcversion = LevelData.Game.DPLCVersion; } return(MapDPLCToBmp(artfile, LevelData.ASMToBin(mapfileloc, mapversion), mapversion, LevelData.ASMToBin(dplcloc, dplcversion), dplcversion, frame, startpal, priority)); }
private static TagStructureAttribute GetStructureAttribute(Type type, EngineVersion version) { // First match against any TagStructureAttributes that have version restrictions var attrib = type.GetCustomAttributes(typeof(TagStructureAttribute), false) .Cast <TagStructureAttribute>() .Where(a => a.MinVersion != EngineVersion.Unknown || a.MaxVersion != EngineVersion.Unknown) .FirstOrDefault(a => VersionDetection.IsBetween(version, a.MinVersion, a.MaxVersion)); // If nothing was found, find the first attribute without any version restrictions return(attrib ?? type.GetCustomAttributes(typeof(TagStructureAttribute), false) .Cast <TagStructureAttribute>() .FirstOrDefault(a => a.MinVersion == EngineVersion.Unknown && a.MaxVersion == EngineVersion.Unknown)); }
public Model decodeModel(EngineVersion engineVersion, ILogger log, byte[] data, int startOffset, int length, int texWidth, int texHeight) { if (!modelMap.TryGetValue(startOffset, out var model)) { model = new Model { meshList = new List <Mesh>(1) }; model.meshList.Add(VifDecoder.DecodeMesh(log, data, startOffset, length, texWidth, texHeight)); modelMap.Add(startOffset, model); } return(model); }
/// <summary> /// Initializes a new instance of the <see cref="RenderModelBuilder"/> class for a particular engine version. /// </summary> public RenderModelBuilder(EngineVersion version) { _version = version; _model.Regions = new List <RenderModel.Region>(); _model.Nodes = new List <RenderModel.Node>(); _model.RuntimeNodes = new List <RenderModel.RuntimeNode>(); _model.Materials = new List <RenderMaterial>(); _model.Unknown1C = -1; // "Flair Starting Model Section Index" in Assembly _model.Geometry = new GeometryReference { Meshes = new List <Mesh>(), Unknown = 7 // TODO: Figure out what this does, if anything }; }
public async Task <IHttpActionResult> Post(int id, EngineVersionInputModel model) { EngineVersion engineVersion = new EngineVersion() { Id = model.Id, EngineVersionName = model.EngineVersionName }; CommentsStagingModel comment = new CommentsStagingModel() { Comment = model.Comment }; var attachments = SetUpAttachmentsModels(model.Attachments); var changeRequestId = await _engineVersionApplicationService.DeleteAsync(engineVersion, id, CurrentUser.Email, comment, attachments); return(Ok(changeRequestId)); }
public World(EngineVersion engineVersion, string dataPath, string name) { if (string.IsNullOrEmpty(dataPath)) { Debug.Fail("Datapath is null"); } if (!Directory.Exists(dataPath)) { Debug.Fail("Invalid datapath!"); } EngineVersion = engineVersion; DataPath = dataPath; Name = name; }
/// <summary> /// Translates a tag index between two versions. /// </summary> /// <param name="version1">The version of the index to translate.</param> /// <param name="index1">The tag index.</param> /// <param name="version2">The version to get the equivalent tag index in.</param> /// <returns>The equivalent tag index if found, or -1 otherwise.</returns> public int Translate(EngineVersion version1, int index1, EngineVersion version2) { // Get both version maps and fail if one doesn't exist VersionMap map1, map2; if (!_versionMaps.TryGetValue(version1, out map1)) return -1; if (!_versionMaps.TryGetValue(version2, out map2)) return -1; // Get the global index from the first map, then look up that index in the second one var globalIndex = map1.GetGlobalTagIndex(index1); if (globalIndex < 0) return -1; return map2.GetVersionedTagIndex(globalIndex); }
/// <summary> /// Detects the engine that a tags.dat was built for based on its timestamp. /// </summary> /// <param name="timestamp">The timestamp.</param> /// <param name="closestGuess">On return, the closest guess for the engine's version.</param> /// <returns>The engine version if the timestamp matched directly, otherwise <see cref="EngineVersion.Unknown"/>.</returns> public static EngineVersion DetectVersionFromTimestamp(long timestamp, out EngineVersion closestGuess) { var index = Array.BinarySearch(VersionTimestamps, timestamp); if (index >= 0) { // Version matches a timestamp directly closestGuess = (EngineVersion)index; return closestGuess; } // Match the closest timestamp index = Math.Max(0, Math.Min(~index - 1, VersionTimestamps.Length - 1)); closestGuess = (EngineVersion)index; return EngineVersion.Unknown; }
public static void ShowValue(ref int value) { int pid = EngineVersion.GetVersion(); DialogResult result = MessageBox.Show("C# Message Box ", "C# Message Box" + value + "ver" + pid, MessageBoxButtons.OKCancel); if (result == DialogResult.OK) { value = 1; } else { value = 2; } return; }
private ResourceLocation FixResourceLocation(ResourceLocation location, EngineVersion srcVersion, EngineVersion destVersion) { if (VersionDetection.Compare(destVersion, EngineVersion.V1_235640_cert_ms25) >= 0) { return(location); } switch (location) { case ResourceLocation.RenderModels: return(ResourceLocation.Resources); case ResourceLocation.Lightmaps: return(ResourceLocation.Textures); } return(location); }
/// <summary> /// Detects the engine that a tags.dat was built for based on its timestamp. /// </summary> /// <param name="timestamp">The timestamp.</param> /// <param name="closestGuess">On return, the closest guess for the engine's version.</param> /// <returns>The engine version if the timestamp matched directly, otherwise <see cref="EngineVersion.Unknown"/>.</returns> public static EngineVersion DetectVersionFromTimestamp(long timestamp, out EngineVersion closestGuess) { var index = Array.BinarySearch(VersionTimestamps, timestamp); if (index >= 0) { // Version matches a timestamp directly closestGuess = (EngineVersion)index; return(closestGuess); } // Match the closest timestamp index = Math.Max(0, Math.Min(~index - 1, VersionTimestamps.Length - 1)); closestGuess = (EngineVersion)index; return(EngineVersion.Unknown); }
public void FormatMessage(EngineStatus status, EngineModel model, EngineVersion version) { if (status == EngineStatus.Accelerating) { response.EngineStatus = "Accelerating"; } else if (status == EngineStatus.Decelerating) { response.EngineStatus = "Decelerating"; } else if (status == EngineStatus.Reverse) { response.EngineStatus = "Reverse"; } else if (status == EngineStatus.Stopped) { response.EngineStatus = "Stopped"; } else if (status == EngineStatus.SpeedReached) { response.EngineStatus = "Speed Reached"; } else if (status == EngineStatus.Fault) { response.EngineStatus = "Fault"; } else if (status == EngineStatus.Running) { response.EngineStatus = "Running"; } if (model == EngineModel.VegaDrive) { response.EngineModel = "VegaDrive"; } if (version == EngineVersion.Version_1_0_E) { response.EngineVersion = "Version 10_E"; } else if (version == EngineVersion.Version_5_0_E) { response.EngineVersion = "Version 50_E"; } response.TimeStamp = DateTime.Now.ToString(); }
private bool GetCurrentPropertyInfo() { // If the field has a TagFieldAttribute, use it, otherwise use the default Attribute = Field.GetCustomAttributes(typeof(TagFieldAttribute), false).FirstOrDefault() as TagFieldAttribute ?? DefaultFieldAttribute; if (Attribute.Offset >= Info.TotalSize) { throw new InvalidOperationException("Offset for property \"" + Field.Name + "\" is outside of its structure"); } // Read version restrictions, if any var minVersionAttrib = Field.GetCustomAttributes(typeof(MinVersionAttribute), false).FirstOrDefault() as MinVersionAttribute; var maxVersionAttrib = Field.GetCustomAttributes(typeof(MaxVersionAttribute), false).FirstOrDefault() as MaxVersionAttribute; MinVersion = (minVersionAttrib != null) ? minVersionAttrib.Version : EngineVersion.Unknown; MaxVersion = (maxVersionAttrib != null) ? maxVersionAttrib.Version : EngineVersion.Unknown; return(VersionDetection.IsBetween(Info.Version, MinVersion, MaxVersion)); }
public async Task <IHttpActionResult> Put(int id, EngineVersionInputModel engineVersionInputModel) { EngineVersion engineVersion = new EngineVersion() { Id = id, EngineVersionName = engineVersionInputModel.EngineVersionName, EngineConfigCount = engineVersionInputModel.EngineConfigCount, VehicleToEngineConfigCount = engineVersionInputModel.VehicleToEngineConfigCount }; CommentsStagingModel comment = new CommentsStagingModel() { Comment = engineVersionInputModel.Comment }; var attachments = SetUpAttachmentsModels(engineVersionInputModel.Attachments); var changeRequestId = await _engineVersionApplicationService.UpdateAsync(engineVersion, engineVersion.Id, CurrentUser.Email, comment, attachments); return(Ok(changeRequestId)); }
private static void CompareBlocks(object leftData, EngineVersion leftVersion, object rightData, EngineVersion rightVersion, TagVersionMap result, Queue<QueuedTag> tagQueue) { if (leftData == null || rightData == null) return; var type = leftData.GetType(); if (type == typeof(TagInstance)) { // If the objects are tags, then we've found a match var leftTag = (TagInstance)leftData; var rightTag = (TagInstance)rightData; if (leftTag.Group.Tag != rightTag.Group.Tag) return; if (leftTag.IsInGroup("rmt2") || leftTag.IsInGroup("rmdf") || leftTag.IsInGroup("vtsh") || leftTag.IsInGroup("pixl") || leftTag.IsInGroup("rm ") || leftTag.IsInGroup("bitm")) return; var translated = result.Translate(leftVersion, leftTag.Index, rightVersion); if (translated >= 0) return; result.Add(leftVersion, leftTag.Index, rightVersion, rightTag.Index); tagQueue.Enqueue(new QueuedTag { Tag = rightTag }); } else if (type.IsArray) { if (type.GetElementType().IsPrimitive) return; // If the objects are arrays, then loop through each element var leftArray = (Array)leftData; var rightArray = (Array)rightData; if (leftArray.Length != rightArray.Length) return; // If the sizes are different, we probably can't compare them for (var i = 0; i < leftArray.Length; i++) CompareBlocks(leftArray.GetValue(i), leftVersion, rightArray.GetValue(i), rightVersion, result, tagQueue); } else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>)) { if (type.GenericTypeArguments[0].IsPrimitive) return; // If the objects are lists, then loop through each element var countProperty = type.GetProperty("Count"); var leftCount = (int)countProperty.GetValue(leftData); var rightCount = (int)countProperty.GetValue(rightData); if (leftCount != rightCount) return; // If the sizes are different, we probably can't compare them var getItem = type.GetMethod("get_Item"); for (var i = 0; i < leftCount; i++) { var leftItem = getItem.Invoke(leftData, new object[] { i }); var rightItem = getItem.Invoke(rightData, new object[] { i }); CompareBlocks(leftItem, leftVersion, rightItem, rightVersion, result, tagQueue); } } else if (type.GetCustomAttributes(typeof(TagStructureAttribute), false).Length > 0) { // The objects are structures var left = new TagFieldEnumerator(new TagStructureInfo(leftData.GetType(), leftVersion)); var right = new TagFieldEnumerator(new TagStructureInfo(rightData.GetType(), rightVersion)); while (left.Next() && right.Next()) { // Keep going on the left until the field is on the right while (!VersionDetection.IsBetween(rightVersion, left.MinVersion, left.MaxVersion)) { if (!left.Next()) return; } // Keep going on the right until the field is on the left while (!VersionDetection.IsBetween(leftVersion, right.MinVersion, right.MaxVersion)) { if (!right.Next()) return; } if (left.Field.MetadataToken != right.Field.MetadataToken) throw new InvalidOperationException("WTF, left and right fields don't match!"); // Process the fields var leftFieldData = left.Field.GetValue(leftData); var rightFieldData = right.Field.GetValue(rightData); CompareBlocks(leftFieldData, leftVersion, rightFieldData, rightVersion, result, tagQueue); } } }
/// <summary> /// Gets the version string corresponding to an <see cref="EngineVersion"/> value. /// </summary> /// <param name="version">The version.</param> /// <returns>The version string.</returns> public static string GetVersionString(EngineVersion version) { switch (version) { case EngineVersion.V1_106708_cert_ms23: return "1.106708 cert_ms23"; case EngineVersion.V1_235640_cert_ms25: return "1.235640 cert_ms23"; case EngineVersion.V0_0_1_301003_cert_MS26_new: return "0.0.1.301003 cert_MS26_new"; case EngineVersion.V0_4_1_327043_cert_MS26_new: return "0.4.1.327043 cert_MS26_new"; case EngineVersion.V8_1_372731_Live: return "8.1.372731 Live"; case EngineVersion.V0_0_416097_Live: return "0.0.416097 Live"; case EngineVersion.V10_1_430475_Live: return "10.1.430475 Live"; case EngineVersion.V10_1_454665_Live: return "10.1.454665 Live"; case EngineVersion.V10_1_449175_Live: return "10.1.449175 Live"; case EngineVersion.V11_1_498295_Live: return "11.1.498295 Live"; case EngineVersion.V11_1_530605_Live: return "11.1.530605 Live"; case EngineVersion.V11_1_532911_Live: return "11.1.532911 Live"; case EngineVersion.V11_1_554482_Live: return "11.1.554482 Live"; case EngineVersion.V11_1_571627_Live: return "11.1.571627 Live"; case EngineVersion.V12_1_700123_cert_ms30_oct19: return "12.1.700123 cert_ms30_oct19"; default: return version.ToString(); } }
private int[,] readTextureChunkOffsets(EngineVersion engineVersion, byte[] data, int offset, int x1, int y1, int x2, int y2) { int[,] chunkOffsets = new int[100, 100]; int addr; for (int y = y1; y <= y2; ++y) { for (int x = x1; x <= x2; ++x) { int cellOffset = ((y - y1) * 100 + x - x1) * 8; // This test is needed to deal with town.world in BGDA which addresses textures outside of the maximum x range. if (data.Length >= offset + cellOffset + 4) { if (EngineVersion.ReturnToArms == engineVersion) { // TODO: Figure out what this should really be addr = 0x800; } else { addr = DataUtil.getLEInt(data, offset + cellOffset); } chunkOffsets[y, x] = addr; } } } return chunkOffsets; }
/// <summary> /// Creates a vertex stream for a given engine version. /// </summary> /// <param name="version">The engine version.</param> /// <param name="stream">The base stream.</param> /// <returns>The created vertex stream.</returns> public static IVertexStream Create(EngineVersion version, Stream stream) { if (VersionDetection.Compare(version, EngineVersion.V1_235640_cert_ms25) >= 0) return new V1_235640.VertexStream(stream); return new V1_106708.VertexStream(stream); }
private static TagStructureAttribute GetStructureAttribute(Type type, EngineVersion version) { // First match against any TagStructureAttributes that have version restrictions var attrib = type.GetCustomAttributes(typeof(TagStructureAttribute), false) .Cast<TagStructureAttribute>() .Where(a => a.MinVersion != EngineVersion.Unknown || a.MaxVersion != EngineVersion.Unknown) .FirstOrDefault(a => VersionDetection.IsBetween(version, a.MinVersion, a.MaxVersion)); // If nothing was found, find the first attribute without any version restrictions return attrib ?? type.GetCustomAttributes(typeof(TagStructureAttribute), false) .Cast<TagStructureAttribute>() .FirstOrDefault(a => a.MinVersion == EngineVersion.Unknown && a.MaxVersion == EngineVersion.Unknown); }
public WorldData Decode(EngineVersion engineVersion, WorldTexFile texFile, ILogger log, byte[] data, int startOffset, int length) { WorldData worldData = new WorldData(); var reader = new DataReader(data, startOffset, length); int numElements = reader.ReadInt32(); // 0 reader.Skip(12); // Skipping 3 ints int numCols = reader.ReadInt32(); // x10 int numRows = reader.ReadInt32(); // x14 reader.Skip(12); // Skipping 3 ints // x18 x1c x20 int elementArrayStart = reader.ReadInt32(); // x24 reader.Skip(8); // Skipping 2 ints int off38Cols = reader.ReadInt32(); int off38Rows = reader.ReadInt32(); int off38 = reader.ReadInt32(); reader.Skip(28); int texll = reader.ReadInt32(); int texur = reader.ReadInt32(); int texX0 = texll % 100; int texY0 = texll / 100; int texX1 = texur % 100; int texY1 = texur / 100; reader.Skip(4); int worldTexOffsetsOffset = reader.ReadInt32(); worldData.textureChunkOffsets = readTextureChunkOffsets(engineVersion, data, startOffset + worldTexOffsetsOffset, texX0, texY0, texX1+1, texY1); worldData.worldElements = new List<WorldElement>(numElements); for (int elementIdx = 0; elementIdx < numElements; ++elementIdx) { var element = new WorldElement(); if (EngineVersion.ReturnToArms == engineVersion) { reader.SetOffset(elementArrayStart + elementIdx * 0x3C); } else // Default to Dark Allience version { reader.SetOffset(elementArrayStart + elementIdx * 0x38); } int vifDataOffset = reader.ReadInt32(); if (EngineVersion.DarkAlliance == engineVersion) { int tex2 = reader.ReadInt32(); if (tex2 != 0) { log.LogLine("Tex2=" + tex2); } } int vifLen = reader.ReadInt32(); log.LogLine("-----------"); log.LogLine("vifdata: " + vifDataOffset + ", " + vifLen); float x1 = reader.ReadFloat(); float y1 = reader.ReadFloat(); float z1 = reader.ReadFloat(); float x2 = reader.ReadFloat(); float y2 = reader.ReadFloat(); float z2 = reader.ReadFloat(); element.boundingBox = new Rect3D(x1, y1, z1, x2 - x1, y2 - y1, z2 - z1); log.LogLine("Bounding Box: " + element.boundingBox.ToString()); int textureNum = reader.ReadInt32() / 0x40; log.LogLine("Texture Num: " + textureNum); int texCellxy = reader.ReadInt16(); int y = texCellxy / 100; int x = texCellxy % 100; if (EngineVersion.ReturnToArms == engineVersion) { x += texX0; y += texY0; } if (textureNum != 0) { if (EngineVersion.ReturnToArms == engineVersion) { element.Texture = texFile.GetBitmapRTA(x, y, textureNum); } else { element.Texture = texFile.GetBitmap(worldData.textureChunkOffsets[y, x], textureNum); } } if (element.Texture != null) { log.LogLine("Found in texture chunk: " + x + ", " + y); } var vifLogger = new StringLogger(); int texWidth = 100; int texHeight = 100; if (element.Texture != null) { texWidth = element.Texture.PixelWidth; texHeight = element.Texture.PixelHeight; } byte nregs = data[startOffset + vifDataOffset + 0x10]; int vifStartOffset = (nregs + 2) * 0x10; element.VifDataOffset = startOffset + vifDataOffset + vifStartOffset; element.VifDataLength = vifLen*0x10 - vifStartOffset; element.model = decodeModel(engineVersion, vifLogger, data, startOffset + vifDataOffset + vifStartOffset, vifLen * 0x10 - vifStartOffset, texWidth, texHeight); if (EngineVersion.ReturnToArms == engineVersion) { int unk = reader.ReadInt16(); log.LogLine("Unknown: " + unk); } int posx = reader.ReadInt16(); int posy = reader.ReadInt16(); int posz = reader.ReadInt16(); log.LogLine("Position : " + posx + ", " + posy + ", " + posz); element.pos = new Vector3D(posx / 16.0, posy / 16.0, posz / 16.0); if (EngineVersion.ReturnToArms == engineVersion) { // Just a guess, maybe wrong. element.pos = new Vector3D(posx / 16.0, posz / 16.0, posy / 16.0); } // I don't think RTA uses this flags scheme. From the data it looks like there are // 2 shorts (or possibly floats) following. int flags = reader.ReadInt32(); if ((flags & 0x01) == 0) { log.LogLine("Flags : " + HexUtil.formatHexUShort(flags & 0xFFFF)); element.cosAlpha = (flags >> 16) / 32767.0; element.sinAlpha = reader.ReadInt16() / 32767.0; log.LogLine("cos alpha : " + element.cosAlpha); log.LogLine("sin alpha : " + element.sinAlpha); log.LogLine("alpha(cos, sin): " + Math.Acos(element.cosAlpha) * 180.0 / Math.PI + ", " + Math.Asin(element.sinAlpha) * 180.0 / Math.PI); element.usesRotFlags = false; } else { reader.ReadInt16(); // not necessary but makes the code more obvious. log.LogLine("Flags : " + HexUtil.formatHex(flags)); element.xyzRotFlags = (flags >> 16) & 7; element.usesRotFlags = true; log.LogLine("Rot Flags : " + element.xyzRotFlags); } element.negYaxis = (flags & 0x40) == 0x40; if (EngineVersion.ReturnToArms == engineVersion) { flags = 0; element.usesRotFlags = true; log.LogLine("Forcing flags to 0 until we know the format better"); } worldData.worldElements.Add(element); } return worldData; }
/// <summary> /// Compares two version numbers. /// </summary> /// <param name="lhs">The left-hand version number.</param> /// <param name="rhs">The right-hand version number.</param> /// <returns>A positive value if the left version is newer, a negative value if the right version is newer, and 0 if the versions are equivalent.</returns> public static int Compare(EngineVersion lhs, EngineVersion rhs) { // Assume the enum values are in order by release date return (int)lhs - (int)rhs; }
/// <summary> /// Detects the engine that a tags.dat was built for. /// </summary> /// <param name="cache">The cache file.</param> /// <param name="closestGuess">On return, the closest guess for the engine's version.</param> /// <returns>The engine version if it is known for sure, otherwise <see cref="EngineVersion.Unknown"/>.</returns> public static EngineVersion DetectVersion(TagCache cache, out EngineVersion closestGuess) { return DetectVersionFromTimestamp(cache.Timestamp, out closestGuess); }
public static Sprite MapASMDPLCToBmp(byte[] artfile, string mapfileloc, string label, string dplcloc, string dplclabel, EngineVersion dplcversion, int startpal) { byte[] mapfile = LevelData.ASMToBin(mapfileloc, label); byte[] dplcfile = LevelData.ASMToBin(dplcloc, dplclabel); BitmapBits[] bmp = null; Point off = new Point(); switch (LevelData.EngineVersion) { case EngineVersion.S2: case EngineVersion.S2NA: bmp = LevelData.S2MapFrameDPLCToBmp(artfile, new S2Mappings(mapfile, 0), new DPLC(dplcfile, 0, dplcversion), startpal, out off); break; case EngineVersion.S3K: case EngineVersion.SKC: bmp = LevelData.S3KMapFrameDPLCToBmp(artfile, new S3KMappings(mapfile, 0), new DPLC(dplcfile, 0, dplcversion), startpal, out off); break; } BitmapBits Image = new BitmapBits(bmp[0].Width, bmp[0].Height); Image.DrawBitmapComposited(bmp[0], Point.Empty); Image.DrawBitmapComposited(bmp[1], Point.Empty); return new Sprite(Image, off); }
public MinVersionAttribute(EngineVersion version) { Version = version; }
/// <summary> /// Gets the timestamp for a version. /// </summary> /// <param name="version">The version.</param> /// <returns>The timestamp, or -1 for <see cref="EngineVersion.Unknown"/>.</returns> public static long GetTimestamp(EngineVersion version) { if (version == EngineVersion.Unknown) return -1; return VersionTimestamps[(int)version]; }
public DPLCEntry(byte[] file, int address, EngineVersion version) { switch (version) { case EngineVersion.S2: case EngineVersion.S2NA: TileNum = ByteConverter.ToUInt16(file, address); TileCount = (byte)((TileNum >> 12) + 1); TileNum &= 0xFFF; break; case EngineVersion.S3K: case EngineVersion.SKC: TileNum = ByteConverter.ToUInt16(file, address); TileCount = (byte)((TileNum & 0xF) + 1); TileNum = (ushort)(TileNum >> 4); break; } }
public DPLC(byte[] file, int address, EngineVersion version) { Tiles = new DPLCEntry[ByteConverter.ToUInt16(file, address) + 1]; for (int i = 0; i < Tiles.Length; i++) { Tiles[i] = new DPLCEntry(file, (i * DPLCEntry.Size) + address + 2, version); } }
public static Sprite MapDPLCToBmp(byte[] artfile, byte[] mapfile, byte[] dplc, EngineVersion dplcversion, int frame, int startpal) { BitmapBits[] bmp = null; Point off = new Point(); DPLC dp = new DPLC(dplc, ByteConverter.ToInt16(dplc, frame * 2), dplcversion); switch (LevelData.EngineVersion) { case EngineVersion.S2: case EngineVersion.S2NA: S2Mappings s2map = new S2Mappings(mapfile, ByteConverter.ToInt16(mapfile, frame * 2)); bmp = LevelData.S2MapFrameDPLCToBmp(artfile, s2map, dp, startpal, out off); break; case EngineVersion.S3K: case EngineVersion.SKC: S3KMappings s3kmap = new S3KMappings(mapfile, ByteConverter.ToInt16(mapfile, frame * 2)); bmp = LevelData.S3KMapFrameDPLCToBmp(artfile, s3kmap, dp, startpal, out off); break; } BitmapBits Image = new BitmapBits(bmp[0].Width, bmp[0].Height); Image.DrawBitmapComposited(bmp[0], Point.Empty); Image.DrawBitmapComposited(bmp[1], Point.Empty); return new Sprite(Image, off); }
public static Sprite MapASMDPLCToBmp(byte[] artfile, string mapfileloc, string dplcloc, EngineVersion dplcversion, int frame, int startpal) { return MapDPLCToBmp(artfile, LevelData.ASMToBin(mapfileloc), LevelData.ASMToBin(dplcloc), dplcversion, frame, startpal); }
/// <summary> /// Determines whether a version number is between two other version numbers (inclusive). /// </summary> /// <param name="compare">The version number to compare. If this is <see cref="EngineVersion.Unknown"/>, this function will always return <c>true</c>.</param> /// <param name="min">The minimum version number. If this is <see cref="EngineVersion.Unknown"/>, then the lower bound will be ignored.</param> /// <param name="max">The maximum version number. If this is <see cref="EngineVersion.Unknown"/>, then the upper bound will be ignored.</param> /// <returns></returns> public static bool IsBetween(EngineVersion compare, EngineVersion min, EngineVersion max) { if (compare == EngineVersion.Unknown) return true; if (min != EngineVersion.Unknown && Compare(compare, min) < 0) return false; return (max == EngineVersion.Unknown || Compare(compare, max) <= 0); }
public YakFile(EngineVersion engineVersion, string name, byte[] data) { _engineVersion = engineVersion; Name = name; FileData = data; }