public GameBalance(MpqFile file) { var stream = file.Open(); this.Header = new Header(stream); this.Type = (BalanceType)stream.ReadValueS32(); Gbi = stream.ReadString(256, true); Xls = stream.ReadString(256, true); this.I0 = stream.ReadValueS32(); this.I1 = stream.ReadValueS32(); this.ItemType = stream.ReadSerializedData<ItemTypeTable>(); //536 stream.Position += 8; this.Item = stream.ReadSerializedData<ItemTable>(); //552 stream.Position += 8; this.Experience = stream.ReadSerializedData<ExperienceTable>(); //568 stream.Position += 8; this.HelpCodes = stream.ReadSerializedData<HelpCodesTable>(); //584 stream.Position += 8; this.MonsterLevel = stream.ReadSerializedData<MonsterLevelTable>(); //600 stream.Position += 8; this.Affixes = stream.ReadSerializedData<AffixTable>(); //616 stream.Position += 8; this.Heros = stream.ReadSerializedData<HeroTable>(); //632 stream.Position += 8; this.MovementStyles = stream.ReadSerializedData<MovementStyleTable>(); //648 stream.Position += 8; this.Labels = stream.ReadSerializedData<LabelGBIDTable>(); //664 stream.Position += 8; this.LootDistribution = stream.ReadSerializedData<LootDistTable>(); //680 stream.Position += 8; this.RareItemNames = stream.ReadSerializedData<RareItemNamesTable>(); //696 stream.Position += 8; this.MonsterAffixes = stream.ReadSerializedData<MonsterAffixesTable>(); //712 stream.Position += 8; this.RareMonsterNames = stream.ReadSerializedData<MonsterNamesTable>(); //728 stream.Position += 8; this.SocketedEffects = stream.ReadSerializedData<SocketedEffectTable>(); //744 stream.Position += 8; this.ItemEnhancement = stream.ReadSerializedData<ItemEnhancementTable>(); //760 stream.Position += 8; this.ItemDrop = stream.ReadSerializedData<ItemDropTable>(); //776 stream.Position += 8; this.ItemLevelMod = stream.ReadSerializedData<ItemLevelModTable>(); //792 stream.Position += 8; this.QualityClass = stream.ReadSerializedData<QualityClassTable>(); //808 stream.Position += 8; this.Hirelings = stream.ReadSerializedData<HirelingTable>(); //824 stream.Position += 8; this.SetItemBonus = stream.ReadSerializedData<SetItemBonusTable>(); //840 stream.Position += 8; this.EliteModifiers = stream.ReadSerializedData<EliteModTable>(); //856 stream.Position += 8; this.ItemTiers = stream.ReadSerializedData<ItemTierTable>(); //872 stream.Position += 8; this.PowerFormula = stream.ReadSerializedData<PowerFormulaTable>(); //888 stream.Position += 8; this.Recipes = stream.ReadSerializedData<RecipeTable>(); //904 stream.Position += 8; this.ScriptedAchievementEvents = stream.ReadSerializedData<ScriptedAchievementEventsTable>(); //920 stream.Close(); }
public QuestRange(MpqFile file) { var stream = file.Open(); this.Time0 = new QuestTime(stream); this.Time1 = new QuestTime(stream); stream.Close(); }
public MarkerSet(MpqFile file) { var stream = file.Open(); Header = new Header(stream); SNO = stream.ReadInt32(); unknown0 = stream.ReadInt32(); unknown1 = stream.ReadInt32(); serMarkers = new SerializeData(stream); long x = stream.Position; Markers = new Marker[serMarkers.Size / 208]; stream.Position = serMarkers.Offset + 16; for (int i = 0; i < serMarkers.Size / 208; i++) { Markers[i] = new Marker(stream); } stream.Position = x; stream.Position += (15 * 4); // pad 15 serNoSpawns = new SerializeData(stream); stream.Position += (14 * 4); aabb = new AABB_(stream); i0 = stream.ReadInt32(); byte[] buf = new byte[256]; stream.Read(buf, 0, 256); filename = Encoding.ASCII.GetString(buf); nLabel = stream.ReadInt32(); nSpecialIndexCount = stream.ReadInt32(); serSpecialIndexList = new SerializeData(stream); stream.Close(); }
public Power(MpqFile file) { var stream = file.Open(); this.Header = new Header(stream); LuaName = stream.ReadString(64, true); stream.Position += 4; // pad 1 Powerdef = new PowerDef(stream); stream.Position = 440; // Seems like theres a bit of a gap - DarkLotus I0 = stream.ReadValueS32(); I1 = stream.ReadValueS32(); Chararray2 = stream.ReadString(256, true); ScriptFormulaCount = stream.ReadValueS32(); ScriptFormulaDetails = stream.ReadSerializedData<ScriptFormulaDetails>(); stream.Position += (3 * 4); i3 = stream.ReadValueS32(); stream.Position += (3 * 4); // TODO: please fix this - use our serializable-data readers instead! /raist // TODO add a class for complied script so it can be deserialized properly. - DarkLotus // none of the .pow appear to have any data here, and stream position appears to be correct, unsure - DarkLotus var serCompliedScript = stream.GetSerializedDataPointer(); if (serCompliedScript.Size > 0) { long x = stream.Position; stream.Position = serCompliedScript.Offset + 16; var buf = new byte[serCompliedScript.Size]; stream.Read(buf, 0, serCompliedScript.Size); stream.Position = x; CompliedScript.AddRange(buf); } SNOQuestMetaData = stream.ReadValueS32(); stream.Close(); }
public Quest(MpqFile file) { MpqFileStream stream = file.Open(); Header = new Header(stream); QuestType = (QuestType)stream.ReadValueS32(); NumberOfSteps = stream.ReadValueS32(); NumberOfCompletionSteps = stream.ReadValueS32(); I2 = stream.ReadValueS32(); I3 = stream.ReadValueS32(); I4 = stream.ReadValueS32(); I5 = stream.ReadValueS32(); QuestUnassignedStep = new QuestUnassignedStep(stream); stream.Position += 8; QuestSteps = stream.ReadSerializedData<QuestStep>(); stream.Position += 8; QuestCompletionSteps = stream.ReadSerializedData<QuestCompletionStep>(); LevelRange1 = new QuestLevelRange(stream); LevelRange2 = new QuestLevelRange(stream); LevelRange3 = new QuestLevelRange(stream); LevelRange4 = new QuestLevelRange(stream); stream.Close(); }
public Conversation(MpqFile file) { MpqFileStream stream = file.Open(); this.Header = new Header(stream); this.ConversationType = (ConversationTypes)stream.ReadValueS32(); this.I0 = stream.ReadValueS32(); this.I1 = stream.ReadValueS32(); this.SNOQuest = stream.ReadValueS32(); this.I2 = stream.ReadValueS32(); this.I3 = stream.ReadValueS32(); this.SNOConvPiggyback = stream.ReadValueS32(); this.SNOConvUnlock = stream.ReadValueS32(); this.I4 = stream.ReadValueS32(); this.Unknown = stream.ReadString(128, true); this.SNOPrimaryNpc = stream.ReadValueS32(); this.SNOAltNpc1 = stream.ReadValueS32(); this.SNOAltNpc2 = stream.ReadValueS32(); this.SNOAltNpc3 = stream.ReadValueS32(); this.SNOAltNpc4 = stream.ReadValueS32(); this.I5 = stream.ReadValueS32(); stream.Position += (2 * 4); RootTreeNodes = stream.ReadSerializedData<ConversationTreeNode>(); this.Unknown2 = stream.ReadString(256, true); this.I6 = stream.ReadValueS32(); stream.Position += 12; CompiledScript = Encoding.ASCII.GetString(stream.ReadSerializedByteArray()); stream.Position += 40; this.SNOBossEncounter = stream.ReadValueS32(); stream.Close(); }
public MarkerSet(MpqFile file) { var stream = file.Open(); this.Header = new Header(stream); this.Markers = stream.ReadSerializedData<Marker>(); stream.Position += (15 * 4); var pointerSpawns = stream.GetSerializedDataPointer(); //TODO Load spawn locations stream.Position += (14 * 4); this.AABB = new AABB(stream); int i0 = stream.ReadValueS32(); if (i0 != 0 && i0 != 1) throw new System.Exception("Farmy thought this field is a bool, but apparently its not"); this.ContainsActorLocations = i0 == 1; this.FileName = stream.ReadString(256, true); this.NLabel = stream.ReadValueS32(); SpecialIndexCount = stream.ReadValueS32(); var pointerSpecialIndexList = stream.GetSerializedDataPointer(); // TODO Load PointerSpecialIndexList stream.Close(); }
public Recipe(MpqFile file) { var stream = file.Open(); this.Header = new Header(stream); ItemSpecifierData = new ItemSpecifierData(stream); stream.Close(); }
public Scene(MpqFile file) { var stream = file.Open(); this.Header = new Header(stream); Int0 = stream.ReadValueS32(); this.AABBBounds = new AABB(stream); this.AABBMarketSetBounds = new AABB(stream); this.NavMesh = new NavMeshDef(stream); this.Exclusions = stream.ReadSerializedInts(); stream.Position += (14 * 4); this.Inclusions = stream.ReadSerializedInts(); stream.Position += (14 * 4); this.MarkerSets = stream.ReadSerializedInts(); stream.Position += (14 * 4); this.LookLink = stream.ReadString(64, true); this.MsgTriggeredEvent = stream.ReadSerializedData<MsgTriggeredEvent>(); this.Int1 = stream.ReadValueS32(); stream.Position += (3 * 4); this.NavZone = new NavZoneDef(stream); this.SNOAppearance = stream.ReadValueS32(); this.SNOPhysMesh = stream.ReadValueS32(); stream.Close(); }
public Scene(MpqFile file) { var stream = file.Open(); this.Header = new Header(stream); Int0 = stream.ReadValueS32(); this.AABBBounds = new AABB(stream); this.AABBMarketSetBounds = new AABB(stream); this.NavMesh = new NavMeshDef(stream); //load NavMeshDef var exclusions = stream.GetSerializedDataPointer(); stream.Position += (14 * 4); var inclusions = stream.GetSerializedDataPointer(); stream.Position += (14 * 4); this.MarkerSets = stream.ReadSerializedInts(); stream.Position += (14 * 4); this.LookLink = stream.ReadString(64, true); // Maybe this is a list/array - DarkLotus this.MsgTriggeredEvent = stream.ReadSerializedItem<MsgTriggeredEvent>(); this.Int1 = stream.ReadValueS32(); stream.Position += (3 * 4); this.NavZone = new NavZoneDef(stream); stream.Close(); }
public QuestRange(MpqFile file) { var stream = file.Open(); this.Header = new Header(stream); this.Start = new QuestTime(stream); this.End = new QuestTime(stream); stream.Close(); }
/// <summary>Resolves the data corresponding to the base file of a given patch <see cref="MpqFile"/>.</summary> /// <param name="file">The patch file.</param> /// <returns>A <see cref="Stream"/> containing the data for the base file if it was found; otherwise <c>null</c>.</returns> internal Stream ResolveBaseFileInternal(MpqFile file) { if (ResolveBaseFile != null) lock (resolveStreamEventArgs) { ResolveBaseFile(file, resolveStreamEventArgs); return(resolveStreamEventArgs.TransferStreamOwnership()); } }
public ConversationList(MpqFile file) { MpqFileStream stream = file.Open(); this.Header = new Header(stream); stream.Position += (12); ConversationListEntries = stream.ReadSerializedData<ConversationListEntry>(); stream.Close(); }
public Recipe(MpqFile file) { var stream = file.Open(); this.Header = new Header(stream); this.SNO = stream.ReadValueS32(); stream.Position += (2 * 4); ItemSpecifierData = new ItemSpecifierData(stream); stream.Close(); }
public Tutorial(MpqFile file) { var stream = file.Open(); this.Header = new Header(stream); this.I0 = stream.ReadValueS32(); this.I1 = stream.ReadValueS32(); this.Time = stream.ReadValueS32(); stream.Close(); }
public Encounter(MpqFile file) { var stream = file.Open(); this.Header = new Header(stream); this.SNOSpawn = stream.ReadValueS32(); stream.Position += (2 * 4);// pad 2 int this.Spawnoptions = stream.ReadSerializedData<EncounterSpawnOptions>(); stream.Close(); }
public Actor(MpqFile file) { var stream = file.Open(); stream.Seek(16, SeekOrigin.Begin); this.ActorSNO = stream.ReadInt32(); stream.Position = 120; this.AnimSetSNO = stream.ReadInt32(); stream.Close(); }
public SkillKit(MpqFile file) { var stream = file.Open(); this.Header = new Header(stream); stream.Position += 12; this.TraitEntries = stream.ReadSerializedData<TraitEntry>(); stream.Position += 8; this.ActiveSkillEntries = stream.ReadSerializedData<ActiveSkillEntry>(); stream.Close(); }
public SceneGroup(MpqFile file) { var stream = file.Open(); this.Header = new Header(stream); this.I0 = stream.ReadValueS32(); this.Items = stream.ReadSerializedData<SceneGroupItem>(); stream.Position += 8; this.I1 = stream.ReadValueS32(); stream.Close(); }
public int BitField1 { get; private set; } // 25 bits - better this this would be an uint public Actor(MpqFile file) { var stream = file.Open(); Header = new Header(stream); this.Int0 = stream.ReadValueS32(); this.Type = (ActorType)stream.ReadValueS32(); this.ApperanceSNO = stream.ReadValueS32(); this.PhysMeshSNO = stream.ReadValueS32(); this.Cylinder = new AxialCylinder(stream); this.Sphere = new Sphere(stream); this.AABBBounds = new AABB(stream); this.TagMap = stream.ReadSerializedItem<TagMap>(); stream.Position += (2 * 4); this.AnimSetSNO = stream.ReadValueS32(); this.MonsterSNO = stream.ReadValueS32(); MsgTriggeredEvents = stream.ReadSerializedData<MsgTriggeredEvent>(); this.Int1 = stream.ReadValueS32(); stream.Position += (3 * 4); this.V0 = new Vector3D(stream.ReadValueF32(), stream.ReadValueF32(), stream.ReadValueF32()); this.Looks = new WeightedLook[8]; for (int i = 0; i < 8; i++) { this.Looks[i] = new WeightedLook(stream); } this.PhysicsSNO = stream.ReadValueS32(); this.Int2 = stream.ReadValueS32(); this.Int3 = stream.ReadValueS32(); this.Float0 = stream.ReadValueF32(); this.Float1 = stream.ReadValueF32(); this.Float2 = stream.ReadValueF32(); this.ActorCollisionData = new ActorCollisionData(stream); this.InventoryImages = new int[10]; //Was 5*8/4 - Darklotus for (int i = 0; i < 10; i++) { this.InventoryImages[i] = stream.ReadValueS32(); } this.Int4 = stream.ReadValueS32(); stream.Position += 4; BitField0 = stream.ReadValueS32(); CastingNotes = stream.ReadSerializedString(); VoiceOverRole = stream.ReadSerializedString(); // Updated based on BoyC's 010 template and Moack's work. Think we just about read all data from actor now.- DarkLotus stream.Close(); }
public TreasureClass(MpqFile file) { var stream = file.Open(); this.Header = new Header(stream); this.Percentage = stream.ReadValueF32(); this.I0 = stream.ReadValueS32(); this.I1 = stream.ReadValueS32(); stream.Position += 8; this.ModifierList = stream.ReadSerializedData<LootDropModifier>(); stream.Close(); }
public Lore(MpqFile file) { var stream = file.Open(); this.Header = new Header(stream); this.I0 = stream.ReadValueS32(); this.Category = (LoreCategory)stream.ReadValueS32(); this.I1 = stream.ReadValueS32(); this.I2 = stream.ReadValueS32(); this.SNOConversation = stream.ReadValueS32(); this.I3 = stream.ReadValueS32(); stream.Close(); }
public Lore(MpqFile file) { var stream = file.Open(); this.Header = new Header(stream); this.SNO = stream.ReadValueS32(); this.i0 = stream.ReadValueS32(); this.i1 = stream.ReadValueS32(); this.i2 = stream.ReadValueS32(); this.snoConversation = stream.ReadValueS32(); this.i3 = stream.ReadValueS32(); stream.Close(); }
public MpqFile[] FindFiles(string filename) { int[] blocks = hashTable.FindMulti(filename); MpqFile[] files = new MpqFile[blocks.Length]; for (int i = 0; i < blocks.Length; i++) { blockTable.Entries[blocks[i]].OnNameDetected(filename); files[i] = files[blockTable.Entries[blocks[i]].FileIndex]; } return(files); }
public Adventure(MpqFile file) { var stream = file.Open(); this.Header = new Header(stream); this.SNOSymbolActor = stream.ReadValueS32(); this.F0 = stream.ReadValueF32(); this.F1 = stream.ReadValueF32(); this.F2 = stream.ReadValueF32(); this.F3 = stream.ReadValueF32(); this.SNOMarkerSet = stream.ReadValueS32(); stream.Close(); }
public Globals(MpqFile file) { var stream = file.Open(); this.Header = new Header(stream); stream.Position += 8; this.ServerData = stream.ReadSerializedData<GlobalServerData>(); stream.Position += 4; this.I0 = stream.ReadValueS32(); //32 stream.Position += 12; this.StartLocationNames = new Dictionary<int, FileFormats.StartLocationName>(); foreach (var startLocation in stream.ReadSerializedData<StartLocationName>()) StartLocationNames.Add(startLocation.I0, startLocation); this.F0 = stream.ReadValueF32(); //56 this.F1 = stream.ReadValueF32(); //60 this.F2 = stream.ReadValueF32(); //64 this.F3 = stream.ReadValueF32(); //68 Colors = new RGBAColor[400]; //72 for (int i = 0; i < 400; i++) Colors[i] = new RGBAColor(stream); this.I1 = stream.ReadValueS32(); //1672 this.F4 = stream.ReadValueF32(); //1676 this.I2 = stream.ReadValueS32(); //1680 this.F5 = stream.ReadValueF32(); //1684 this.F6 = stream.ReadValueF32(); //1688 this.I3 = stream.ReadValueS32(); //1692 this.I4 = stream.ReadValueS32(); //1696 this.F7 = stream.ReadValueF32(); //1700 this.F8 = stream.ReadValueF32(); //1704 this.F9 = stream.ReadValueF32(); //1708 this.I5 = stream.ReadValueS32(); //1712 this.I6 = new int[4]; //1716 for (int i = 0; i < 4; i++) this.I6[i] = stream.ReadValueS32(); stream.Position += 4; this.BannerParams = new BannerParams(stream); //1736 this.I7 = stream.ReadValueS32(); //1968 this.I8 = stream.ReadValueS32(); //1972 this.I9 = stream.ReadValueS32(); //1976 this.I10 = stream.ReadValueS32(); //1980 this.F10 = stream.ReadValueF32(); //1984 this.F11 = stream.ReadValueF32(); //1988 this.F12 = stream.ReadValueF32(); //1992 this.F13 = stream.ReadValueF32(); //1996 this.F14 = stream.ReadValueF32(); //2000 this.F15 = stream.ReadValueF32(); //2004 this.F16 = stream.ReadValueF32(); //2008 this.F17 = stream.ReadValueF32(); //2012 stream.Close(); }
public Actor(MpqFile file) { var stream = file.Open(); Header = new Header(stream); this.Int0 = stream.ReadValueS32(); this.Type = (ActorType)stream.ReadValueS32(); this.ApperanceSNO = stream.ReadValueS32(); this.PhysMeshSNO = stream.ReadValueS32(); this.Cylinder = new AxialCylinder(stream); this.Sphere = new Sphere(stream); this.AABBBounds = new AABB(stream); var tagmap = stream.GetSerializedDataPointer(); // we need to read tagmap. /raist. stream.Position += (2*4); this.AnimSetSNO = stream.ReadValueS32(); this.MonsterSNO = stream.ReadValueS32(); var msgTriggeredEvents = stream.GetSerializedDataPointer(); this.Int1 = stream.ReadValueS32(); stream.Position += (3*4); this.V0 = new Vector3D(stream.ReadValueF32(), stream.ReadValueF32(), stream.ReadValueF32()); this.Looks = new WeightedLook[8]; for (int i = 0; i < 8; i++) { this.Looks[i] = new WeightedLook(stream); } this.PhysicsSNO = stream.ReadValueS32(); this.Int2 = stream.ReadValueS32(); this.Int3 = stream.ReadValueS32(); this.Float0 = stream.ReadValueF32(); this.Float1 = stream.ReadValueF32(); this.Float2 = stream.ReadValueF32(); this.ActorCollisionData = new int[17]; // Was 68/4 - Darklotus for (int i = 0; i < 17; i++) { this.ActorCollisionData[i] = stream.ReadValueS32(); } this.InventoryImages = new int[10]; //Was 5*8/4 - Darklotus for (int i = 0; i < 10; i++) { this.InventoryImages[i] = stream.ReadValueS32(); } // Updated based on BoyC's 010editoer template, looks like some data at the end still isnt parsed - Darklotus stream.Close(); }
public PhysMesh(MpqFile file) { var stream = file.Open(); this.Header = new Header(stream); this.I0 = stream.ReadValueS32(); this.CollisionMeshCount = stream.ReadValueS32(); this.CollisionMeshes = stream.ReadSerializedData<CollisionMesh>(); stream.Position += 12; this.S0 = stream.ReadString(256); this.S1 = stream.ReadString(256); this.I1 = stream.ReadValueS32(); stream.Close(); }
public Anim(MpqFile file) { var stream = file.Open(); this.Header = new Header(stream); this.I0 = stream.ReadValueS32(); this.I1 = stream.ReadValueS32(); this.SNOAppearance = stream.ReadValueS32(); this.Permutations = stream.ReadSerializedData<AnimPermutation>(); this.I2 = stream.ReadValueS32(); stream.Position += 12; this.I3 = stream.ReadValueS32(); stream.Close(); }
public LevelArea(MpqFile file) { var stream = file.Open(); this.Header = new Header(stream); this.I0 = stream.ReadValueS32(); this.I1 = stream.ReadValueS32(); this.SNOLevelAreaOverrideForGizmoLocs = stream.ReadValueS32(); this.LocSet = new GizmoLocSet(stream); this.I2 = stream.ReadValueS32(); stream.Position += 12; this.SpawnPopulation = stream.ReadSerializedData<LevelAreaSpawnPopulation>(); stream.Close(); }
public Condition(MpqFile file) { var stream = file.Open(); this.Header = new Header(stream); this.I0 = stream.ReadValueS32(); this.I1 = stream.ReadValueS32(); this.Class = new int[5]; for (int i = 0; i < 5; i++) this.Class[i] = stream.ReadValueS32(); this.Difficulty = new int[4]; for (int i = 0; i < 4; i++) this.Difficulty[i] = stream.ReadValueS32(); this.LoreCondition = new LoreSubcondition[3]; for (int i = 0; i < 3; i++) this.LoreCondition[i] = new LoreSubcondition(stream); this.QuestCondition = new QuestSubcondition[3]; for (int i = 0; i < 3; i++) this.QuestCondition[i] = new QuestSubcondition(stream); this.ItemCondition = new ItemSubcondition[3]; for (int i = 0; i < 3; i++) this.ItemCondition[i] = new ItemSubcondition(stream); this.I4 = stream.ReadValueS32(); //176 this.I5 = stream.ReadValueS32(); this.I6 = stream.ReadValueS32(); this.I7 = stream.ReadValueS32(); stream.Position += 4; this.I8 = stream.ReadValueS32(); this.I9 = stream.ReadValueS32(); this.I10 = stream.ReadValueS32(); this.I11 = stream.ReadValueS32(); this.SNOCurrentWorld = stream.ReadValueS32(); this.SNOCurrentLevelArea = stream.ReadValueS32(); this.SNOQuestRange = stream.ReadValueS32(); this.FollowerCondition = new FollowerSubcondition(stream); this.LabelCondition = new LabelSubcondition[3]; for (int i = 0; i < 3; i++) this.LabelCondition[i] = new LabelSubcondition(stream); this.SkillCondition = new SkillSubcondition[3]; for (int i = 0; i < 3; i++) this.SkillCondition[i] = new SkillSubcondition(stream); this.MonsterCondition = new MonsterSubcondition[3]; for (int i = 0; i < 3; i++) this.MonsterCondition[i] = new MonsterSubcondition(stream); this.GameFlagCondition = new GameFlagSubcondition[3]; for (int i = 0; i < 3; i++) this.GameFlagCondition[i] = new GameFlagSubcondition(stream); this.PlayerFlagCondition = new PlayerFlagSubcondition[3]; for (int i = 0; i < 3; i++) this.PlayerFlagCondition[i] = new PlayerFlagSubcondition(stream); stream.Close(); }
public Scene(MpqFile file) { var stream = file.Open(); long pos = 0; // x DEADBEEF = stream.ReadInt32(); snoType = stream.ReadInt32(); unknown1 = stream.ReadInt32(); unknown2 = stream.ReadInt32(); SceneSNO = stream.ReadInt32(); unknown3 = stream.ReadInt32(); unknown4 = stream.ReadInt32(); i0 = stream.ReadInt32(); aabbBounds = new AABB(stream); aabbMarkerSetBounds = new AABB(stream); //load NavMeshDef NavMesh = new NavMeshDef(stream); // end navmeshdef var serExclusions = new SerializeData(stream); stream.Position += 56; var serInclusions = new SerializeData(stream); stream.Position += 56; //MarkerSet Time var serMarkerSets = new SerializeData(stream); pos = stream.Position; stream.Position = serMarkerSets.Offset + 16; MarkerSets = new int[serMarkerSets.Size/4]; for (int i = 0; i < serMarkerSets.Size/4; i++) { MarkerSets[i] = stream.ReadInt32(); } stream.Position = pos + 56; //TODO - parse LookLink /dark LookLink = new char[64]; for (int i = 0; i < 64; i++) { LookLink[i] = (char) stream.ReadByte(); } var sermsgTriggeredEvents = new SerializeData(stream); int i1 = stream.ReadInt32(); stream.Position += 12; //navzonedef NavZone = new NavZoneDef(stream); stream.Close(); }
private void CreateFiles(uint fileCount) { files = new MpqFile[fileCount]; for (uint i = 0, blockIndex = 0; i < fileCount; i++) { while ((blockTable.Entries[blockIndex].Flags & MpqFileFlags.Exists) == 0) { blockIndex++; } files[i] = new MpqFile(this, blockIndex++); } }
public MpqFile[] FindFiles(string filename) { foreach (var archive in archiveList) { var files = archive.FindFiles(filename); if (files.Length > 0) { int deletedFileCount = 0; foreach (var file in files) { if ((file.Flags & MpqFileFlags.Deleted) != 0) { deletedFileCount++; } } if (deletedFileCount == 0) { return(files); } else if (deletedFileCount == files.Length) { break; } var existingFiles = new MpqFile[files.Length - deletedFileCount]; int i = 0; foreach (var file in files) { if ((file.Flags & MpqFileFlags.Deleted) == 0) { existingFiles[i++] = file; } } return(existingFiles); } } return(new MpqFile[0]); }
private void OpenInternal(Stream stream, bool shouldParseListFile) { // MPQ offsets can be 32 bits, 48 bits or 64 bits depending on the MPQ version used… long hashTableOffset, hashTableCompressedSize, hashTableSize; long blockTableOffset, blockTableCompressedSize, blockTableSize; long highBlockTableOffset, highBlockTableCompressedSize, highBlockTableSize; long enhancedHashTableOffset, enhancedHashTableCompressedSize; long enhancedBlockTableOffset, enhancedBlockTableCompressedSize; uint hashTableLength, blockTableLength; uint rawChunkSize; uint signature; byte[] hashes; if (!stream.CanSeek) { throw new InvalidOperationException(ErrorMessages.GetString("SeekableStreamRequired")); } if (checked (stream.Position + stream.Length) < 0x20) { throw new InvalidDataException(ErrorMessages.GetString("NotEnoughData")); } // We use a lot of "long" and "int" variables here, but data is likely stored as ulong and uint… // So better test for overflow… Who knows what might happen in the future… ;) // The "safe" pattern is to read as unsigned and cast to signed where oferflow is possible. checked { this.stream = stream; archiveDataOffset = stream.Position; // We don't handle searching for MPQ data. The stream must already be positionned at the beginning of the MPQ data. signature = stream.ReadUInt32(); // The first part of the file may be MPQ user data. The next part should be regular MPQ archive data. if (signature == MpqUserDataSignature) { userDataOffset = archiveDataOffset; userDataLength = stream.ReadUInt32(); stream.Seek(stream.ReadUInt32() - 3 * sizeof(uint), SeekOrigin.Current); archiveDataOffset = stream.Position; signature = stream.ReadUInt32(); } // Checking for MPQ archive signature if (signature != MpqArchiveSignature) { throw new InvalidDataException(ErrorMessages.GetString("InvalidData")); } headerSize = stream.ReadUInt32(); archiveDataLength = stream.ReadUInt32(); // MPQ format detection // Unknown MPQ version will raise an error… This seems like a safe idea. ushort mpqVersion = stream.ReadUInt16(); switch (mpqVersion) // Read MPQ format { case 0: // Original MPQ format archiveFormat = MpqFormat.Original; if (headerSize < 0x20) { throw new InvalidDataException(ErrorMessages.GetString("InvalidArchiveHeader")); } break; case 1: // Extended MPQ format (WoW Burning Crusade) archiveFormat = MpqFormat.BurningCrusade; if (headerSize < 0x2C) { throw new InvalidDataException(ErrorMessages.GetString("InvalidArchiveHeader")); } break; case 2: // Enhanced MPQ format (Take 1) archiveFormat = MpqFormat.CataclysmFirst; // Header may not contain any additional field than BC extended MPQ format. // However, if additional fields are present, the header should be at least 68 bytes long. if (headerSize < 0x2C || (headerSize > 0x2C && headerSize < 0x44)) { throw new InvalidDataException(ErrorMessages.GetString("InvalidArchiveHeader")); } break; case 3: // Enhanced MPQ format (Take 2) archiveFormat = MpqFormat.CataclysmSecond; if (headerSize < 0xD0) { throw new InvalidDataException(ErrorMessages.GetString("InvalidArchiveHeader")); } break; default: throw new MpqVersionNotSupportedException(mpqVersion); // Newer MPQ versions can probably be read just as well by the existing code… But can't know for sure… } blockSize = 0x200 << stream.ReadUInt16(); // Calculate block size hashTableOffset = stream.ReadUInt32(); // Get Hash Table Offset blockTableOffset = stream.ReadUInt32(); // Get Block Table Offset hashTableLength = stream.ReadUInt32(); // Get Hash Table Size blockTableLength = stream.ReadUInt32(); // Get Block Table Size // Assign the compressed size for the various tables. // Since compression was non-existant with V1 & V2, we know the compressed size is the uncompressed size. // If the compressed size is different as specified in V4, this will be overwritten later. hashTableCompressedSize = 4 * sizeof(uint) * hashTableLength; if (blockTableOffset > hashTableOffset && blockTableOffset - hashTableOffset < hashTableCompressedSize) // Compute compressed hash table length if needed { hashTableCompressedSize = blockTableOffset - hashTableOffset; } blockTableCompressedSize = 4 * sizeof(uint) * blockTableLength; // Process additional values for "Burning Crusade" MPQ format if (archiveFormat >= MpqFormat.BurningCrusade) { ushort hashTableOffsetHigh, blockTableOffsetHigh; // Read extended information highBlockTableOffset = (long)stream.ReadUInt64(); highBlockTableCompressedSize = highBlockTableOffset != 0 ? sizeof(uint) * blockTableLength : 0; hashTableOffsetHigh = stream.ReadUInt16(); blockTableOffsetHigh = stream.ReadUInt16(); // Modify offsets accordingly hashTableOffset |= (long)hashTableOffsetHigh << 32; blockTableOffset |= (long)blockTableOffsetHigh << 32; // Handle MPQ version 3 (Cataclysm First) and newer if (archiveFormat >= MpqFormat.CataclysmFirst && headerSize >= 0x44) { archiveDataLength = (long)stream.ReadUInt64(); enhancedBlockTableOffset = (long)stream.ReadUInt64(); enhancedHashTableOffset = (long)stream.ReadUInt64(); // Handle MPQ version 4 (Cataclysm Second) if (archiveFormat >= MpqFormat.CataclysmSecond) { hashTableCompressedSize = (long)stream.ReadUInt64(); blockTableCompressedSize = (long)stream.ReadUInt64(); highBlockTableCompressedSize = (long)stream.ReadUInt64(); enhancedHashTableCompressedSize = (long)stream.ReadUInt64(); enhancedBlockTableCompressedSize = (long)stream.ReadUInt64(); rawChunkSize = stream.ReadUInt32(); hashes = new byte[6 * 16]; if (stream.Read(hashes, 0, hashes.Length) != hashes.Length) { throw new EndOfStreamException(); } } else { // TODO: Compute the uncompresed size for the new enhanced tables of version 3… (Will have to check how to do that…) highBlockTableCompressedSize = highBlockTableOffset > 0 ? sizeof(ushort) * blockTableLength : 0; } } else { #if DEBUG long oldArchiveSize = archiveDataLength; #endif // Compute 64 bit archive size (We don't really need it for MPQ reading, but for integrity checks, we do…) if (highBlockTableOffset > hashTableOffset && highBlockTableOffset > blockTableOffset) { archiveDataLength = highBlockTableOffset + sizeof(ushort) * blockTableLength; } else if (blockTableOffset > hashTableOffset) { archiveDataLength = blockTableOffset + 4 * sizeof(uint) * blockTableLength; } else { archiveDataLength = hashTableOffset + 4 * sizeof(uint) * hashTableLength; } #if DEBUG Debug.Assert(oldArchiveSize >= archiveDataLength); #endif } } else { highBlockTableOffset = 0; highBlockTableCompressedSize = 0; } if (!CheckOffset((uint)headerSize) || !CheckOffset(hashTableOffset) || !CheckOffset(blockTableOffset) || hashTableLength < blockTableLength) { throw new InvalidDataException(ErrorMessages.GetString("InvalidArchiveHeader")); } hashTableSize = 4 * sizeof(uint) * hashTableLength; blockTableSize = 4 * sizeof(uint) * blockTableLength; highBlockTableSize = highBlockTableOffset != 0 ? sizeof(ushort) * blockTableLength : 0; // Check for strong signature presence if (stream.Length >= archiveDataOffset + archiveDataLength + 2052) { stream.Seek(archiveDataOffset + archiveDataLength, SeekOrigin.Begin); hasStrongSignature = stream.ReadUInt32() == MpqStrongSignatureSignature; } } // Create buffers for table reading var tableReadBuffer = hashTableSize < hashTableCompressedSize || blockTableSize < blockTableCompressedSize || highBlockTableCompressedSize < highBlockTableSize ? new byte[Math.Max(Math.Max(hashTableCompressedSize, blockTableCompressedSize), highBlockTableCompressedSize)] : null; var tableBuffer = new byte[Math.Max(hashTableSize, blockTableSize)]; // Read Hash Table ReadHashTable(tableBuffer, hashTableLength, hashTableOffset, hashTableCompressedSize, tableReadBuffer); // Read Block Table ReadBlockTable(tableBuffer, blockTableLength, blockTableOffset, blockTableCompressedSize, highBlockTableOffset, highBlockTableCompressedSize, tableReadBuffer); // When possible, find and parse the listfile… listFile = FindFile(ListFileName); if (listFile == null) { return; } if (shouldParseListFile) { ParseListFile(); } }
internal MpqFileStream(MpqFile file, Stream baseStream = null) { try { PatchInfoHeader?patchInfoHeader; // Used to differentiate between regulat files and patch files. Also contains the patch header :p // Store bits of information as local variables, in order to adjust them later. bool singleUnit = (file.Flags & MpqFileFlags.SingleBlock) != 0; bool compressed = file.IsCompressed; uint compressedSize = (uint)file.CompressedSize; this.file = file; this.offset = file.Offset; // Process the patch information header first if (file.IsPatch) { // Resolving the base file this early may be a waste if the patch ever happens to be a COPY patch… Anyway, it allows for checking the base file's integrity. // But seriously, what's the point in COPY patches anyway ? Aren't those just like regular MPQ files, only with added (useless) weight ? if ((baseStream = baseStream ?? file.Archive.ResolveBaseFileInternal(file)) == null) { throw new FileNotFoundException(string.Format(ErrorMessages.GetString("PatchBaseFileNotFound"), file.Name)); } patchInfoHeader = ReadPatchInfoHeader(file.Archive, file.Offset); offset += patchInfoHeader.Value.HeaderLength; length = patchInfoHeader.Value.PatchLength; // No matter what crap may be written in the block table, it seems that this field is always right (I had to update the decompression method just for that…) if (patchInfoHeader.Value.PatchLength <= file.CompressedSize) { // As it seems, there are some bogus entries in the block table of mpq patch archives. (Only for patch files though) // If you browse the list of DBC files, i'd say there are about 10% of them which have a bogus block table entry. // So, for detecting them, we'll use the same method as in stormlib. We'll try to read the patch header to know is the patch is compressed or not. // By the way, we cannot detect whether the patch is compressed or not if it is encrypted. if (file.IsEncrypted) { throw new InvalidDataException(ErrorMessages.GetString("PatchInfoHeaderInvalidData")); } // Try to read the patch header in the data following the information header and adjust the compressed size dependign on the result: // Since we are “sure” of the uncompressed size (given in the patch header), there is no point in compression if the compressed data isn't even one byte less. // Thus, we can mostly safely decrease the compressed size by 1, which, by the way, is necessary to make decompression work in UpdateBuffer()… compressedSize = patchInfoHeader.Value.PatchLength - ((compressed = !TestPatchHeader(file.Archive, offset)) ? (uint)1 : 0); // It appears that the single unit flag is also lying on some patch entries. Files reported as blocky (such as some of the cataclysm mp3) are in fact single unit… // Forcing this single unit flag to true when the file is compressed seems to be a good solution. Also, we may (or not :p) save a bit of memory by using blocks for uncompressed files. singleUnit = compressed; } } else { patchInfoHeader = null; length = checked ((uint)file.Size); } // Set up the stream the same way for both patches and regular files… if (file.IsEncrypted) { if (file.Seed == 0) { throw new SeedNotFoundException(file.BlockIndex); } else { this.seed = file.Seed; } if ((file.Flags & MpqFileFlags.PositionEncrypted) != 0) { this.seed = (this.seed + (uint)file.Offset) ^ (uint)this.length; } } if (singleUnit) { this.fileHeader = new uint[] { 0, compressedSize } } ; else if (compressed) { this.fileHeader = ReadBlockOffsets(file.Archive, this.seed, this.offset, (int)((length + file.Archive.BlockSize - 1) / file.Archive.BlockSize + 1)); } else { this.fileHeader = new uint[(int)(length + file.Archive.BlockSize - 1) / file.Archive.BlockSize + 1]; this.fileHeader[0] = 0; for (int i = 1; i < this.fileHeader.Length; i++) { this.fileHeader[i] = this.fileHeader[i - 1] + (uint)file.Archive.BlockSize; if (this.fileHeader[i] > length) { this.fileHeader[i] = (uint)this.length; } } } // Treat the files smaller than the block size as single unit. (But only now that we've read the file header) singleUnit |= length <= file.Archive.BlockSize; this.blockBuffer = new byte[singleUnit ? length : (uint)file.Archive.BlockSize]; if (compressed) { this.compressedBuffer = new byte[singleUnit ? compressedSize : (uint)file.Archive.BlockSize]; } this.lastBlockLength = this.length > 0 ? this.length % (uint)this.blockBuffer.Length : 0; if (this.lastBlockLength == 0) { this.lastBlockLength = (uint)this.blockBuffer.Length; } this.currentBlock = -1; UpdateBuffer(); // If we finished initializing a stream to patch data, all there is left is to apply the patch if (patchInfoHeader != null) { // The patching methods will read from this stream instance (whose constructor has yet to finish… !) and return the patched data. this.blockBuffer = ApplyPatch(patchInfoHeader.Value, baseStream); // Once the patch has been applied, transform this stream into a mere memory stream. (The same as with single unit files, in fact) this.compressedBuffer = null; this.fileHeader = new uint[] { 0, (uint)this.blockBuffer.Length }; this.position = 0; this.currentBlock = 0; this.readBufferOffset = 0; this.length = (uint)this.blockBuffer.Length; } } finally { if (baseStream != null) { baseStream.Dispose(); } } }