public void AddObject(IffFile iff, OBJD obj) { lock (Entries) { GameObjectSource source; switch (iff.RuntimeInfo.State) { case IffRuntimeState.PIFFClone: source = GameObjectSource.PIFFClone; break; case IffRuntimeState.Standalone: source = GameObjectSource.Standalone; break; default: source = GameObjectSource.Far; break; } Entries.Add(obj.GUID, new GameObjectReference(this) { ID = obj.GUID, FileName = iff.RuntimeInfo.Path, Source = source, Name = obj.ChunkLabel, Group = (short)obj.MasterID, SubIndex = obj.SubIndex }); } }
private void PrintOBJD(OBJD item) { string[] fieldLabels = null; switch (item.Version) { case 142: fieldLabels = OBJD.VERSION_142_Fields; break; } Printer.H1(item.ChunkID + " (" + item.ChunkLabel + ") GUID = " + item.GUID.ToString("x") + " Version = " + item.Version); var table = Printer.CreateTable(new string[] { "Field", "Value" }); for (var i = 0; i < item.RawData.Length; i++) { if (fieldLabels != null && i < fieldLabels.Length) { table.AddRow(new object[] { i.ToString() + " (" + fieldLabels[i] + ")", item.RawData[i].ToString() }); } else { table.AddRow(new object[] { i.ToString(), item.RawData[i].ToString() }); } } Printer.Add(table); }
public void DisableIfTSOCategoryWrong(VMContext context) { //if (context.VM.TS1) return; OBJD obj = Object.OBJ; if (MasterDefinition != null) { obj = MasterDefinition; } var category = context.VM.TSOState.PropertyCategory; var flag = (1 << category); if (category == 7) { flag |= 2; //money objects are allowed on welcome lots too. (fso change, disabling this is todo) } if (category != 255 && obj.LotCategories > 0 && (obj.LotCategories & flag) == 0) { Disabled |= VMGameObjectDisableFlags.LotCategoryWrong; } else { Disabled &= ~VMGameObjectDisableFlags.LotCategoryWrong; } }
/// <summary> /// Tests the FAR1Archive class. /// </summary> private static void FAR1Test() { Console.WriteLine("Attempting to parse IFF..."); //Testcases: djbooth.iff, trashcanvacation.iff, stair2.iff, stereos.iff, maid.iff, mask.iff, medicinecabinet.iff Iff IffObject = FileManager.GetIFF("medicinecabinet.iff"); OBJD Master = IffObject.Master; }
public DGRP3DMesh Get(DGRP dgrp, OBJD obj) { DGRP3DMesh result = null; var repldir = Path.Combine(FSOEnvironment.ContentDir, "MeshReplace/"); var dir = Path.Combine(FSOEnvironment.UserDir, "MeshCache/"); if (!Cache.TryGetValue(dgrp, out result)) { //does it exist in replacements var name = obj.ChunkParent.Filename.Replace('.', '_') + "_" + dgrp.ChunkID + ".fsom"; try { using (var file = File.OpenRead(Path.Combine(repldir, name))) { result = new DGRP3DMesh(dgrp, file, GD); } } catch (Exception) { result = null; } if (result == null) { //does it exist in iff try { result = dgrp.ChunkParent.Get <FSOM>(dgrp.ChunkID)?.Get(dgrp, GD); } catch (Exception) { result = null; } } if (result == null && !IgnoreRCCache.Contains(dgrp)) { //does it exist in rc cache try { using (var file = File.OpenRead(Path.Combine(dir, name))) { result = new DGRP3DMesh(dgrp, file, GD); } } catch (Exception) { result = null; } } //create it anew if (result == null) { result = new DGRP3DMesh(dgrp, obj, GD, dir); } Cache[dgrp] = result; } return(result); }
//hilariously large switch case. there's got to be a better way public static short GetEntityDefinitionVar(OBJD objd, VMOBJDVariable var, VMStackFrame context) { switch (var) { case VMOBJDVariable.Version1: return((short)(objd.Version % 0xFFFF)); case VMOBJDVariable.Version2: return((short)(objd.Version >> 16)); default: return((short)objd.RawData[((int)var) - 2]); } }
public void SetSelectors(OBJD objd, IffChunk active, OBJDSelector[] selectors) { Active = active; Definition = objd; SelectButton.Dock = DockStyle.Fill; SelectCombo.Dock = DockStyle.Fill; SelectButton.Visible = selectors.Length == 1; SelectCombo.Visible = selectors.Length > 1; Selectors = selectors; if (selectors.Length > 1) { SelectCombo.Items.Clear(); SelectCombo.Items.Add("-- Not Selected --"); int i = 1; OwnChange = true; SelectCombo.SelectedIndex = 0; foreach (var sel in selectors) { SelectCombo.Items.Add(sel); if (sel.FieldName != null && objd.GetPropertyByName <ushort>(sel.FieldName) == active.ChunkID) { SelectCombo.SelectedIndex = i; } i++; } OwnChange = false; } else if (selectors.Length > 0) { var sel = selectors[0]; if (sel.FieldName != null && objd.GetPropertyByName <ushort>(sel.FieldName) == active.ChunkID) { SelectButton.Text = "Selected as " + sel.Name; SelectButton.Enabled = false; } else { SelectButton.Text = "Select as " + sel.Name; SelectButton.Enabled = true; } } else { Enabled = false; Visible = false; } }
public void DisableIfTSOCategoryWrong(VMContext context) { OBJD obj = Object.OBJ; if (MasterDefinition != null) { obj = MasterDefinition; } var category = context.VM.TSOState.PropertyCategory; if (category != 255 && obj.LotCategories > 0 && (obj.LotCategories & (1 << category)) == 0) { Disabled |= VMGameObjectDisableFlags.LotCategoryWrong; } else { Disabled &= ~VMGameObjectDisableFlags.LotCategoryWrong; } }
/// <summary> /// Creates a new SimulationObject instance. /// </summary> /// <param name="Obj">The OBJD for this object. Assumed to be the master OBJD if the object is multi-tile.</param> /// <param name="Container">The IFF archive where the OBJD resides.</param> public SimulationObject(OBJD Obj, Iff Container, string GUID) { m_GUID = GUID; if (!Obj.IsMultiTile) { m_MasterOBJD = Obj; m_ObjectContainer = Container; } else //Load the OBJDs for the other tiles... { foreach (OBJD O in m_ObjectContainer.OBJDs) { if (O.MasterID == Obj.MasterID) { m_Slaves.Add(O); } } } }
public OBJfFunctionEntry[] GenerateFunctionTable(OBJD obj) { OBJfFunctionEntry[] result = new OBJfFunctionEntry[33]; result[0].ActionFunction = obj.BHAV_Init; result[1].ActionFunction = obj.BHAV_MainID; result[2].ActionFunction = obj.BHAV_Load; result[3].ActionFunction = obj.BHAV_Cleanup; result[4].ActionFunction = obj.BHAV_QueueSkipped; result[5].ActionFunction = obj.BHAV_AllowIntersectionID; result[6].ActionFunction = obj.BHAV_WallAdjacencyChanged; result[7].ActionFunction = obj.BHAV_RoomChange; result[8].ActionFunction = obj.BHAV_DynamicMultiTileUpdate; result[9].ActionFunction = obj.BHAV_Place; result[10].ActionFunction = obj.BHAV_Pickup; result[11].ActionFunction = obj.BHAV_UserPlace; result[12].ActionFunction = obj.BHAV_UserPickup; result[13].ActionFunction = obj.BHAV_LevelInfo; result[14].ActionFunction = obj.BHAV_ServingSurface; result[15].ActionFunction = obj.BHAV_Portal; //portal result[16].ActionFunction = obj.BHAV_GardeningID; result[17].ActionFunction = obj.BHAV_WashHandsID; result[18].ActionFunction = obj.BHAV_PrepareFoodID; result[19].ActionFunction = obj.BHAV_CookFoodID; result[20].ActionFunction = obj.BHAV_PlaceSurfaceID; result[21].ActionFunction = obj.BHAV_DisposeID; result[22].ActionFunction = obj.BHAV_EatID; result[23].ActionFunction = obj.BHAV_PickupFromSlotID; //pickup from slot result[24].ActionFunction = obj.BHAV_WashDishID; result[25].ActionFunction = obj.BHAV_EatSurfaceID; result[26].ActionFunction = obj.BHAV_SitID; result[27].ActionFunction = obj.BHAV_StandID; result[28].ActionFunction = obj.BHAV_Clean; result[29].ActionFunction = obj.BHAV_Repair; //repair result[30].ActionFunction = 0; //client house join result[31].ActionFunction = 0; //prepare for sale result[32].ActionFunction = 0; //house unload return(result); }
public virtual void Load(VMEntityMarshal input) { ObjectID = input.ObjectID; PersistID = input.PersistID; ObjectData = input.ObjectData; MyList = new LinkedList <short>(input.MyList); MainParam = input.MainParam; //parameters passed to main on creation. MainStackOBJ = input.MainStackOBJ; if (input.MasterGUID != 0) { var masterDef = FSO.Content.Content.Get().WorldObjects.Get(input.MasterGUID); MasterDefinition = masterDef.OBJ; UseTreeTableOf(masterDef); } else { MasterDefinition = null; } ContainerSlot = input.ContainerSlot; Attributes = new List <short>(input.Attributes); MeToObject = new Dictionary <ushort,List <short> >(); foreach (var obj in input.MeToObject) { MeToObject[obj.Target] = new List <short>(obj.Values); } DynamicSpriteFlags = input.DynamicSpriteFlags; Position = input.Position; if (UseWorld) { WorldUI.Visible = GetValue(VMStackObjectVariable.Hidden) == 0; } }
/// <summary> /// Adds an object that will be run by this virtual machine. /// </summary> /// <param name="Obj">The object to run.</param> /// <param name="ObjectContainer">The object's container.</param> public void AddObject(OBJD Obj, Iff ObjectContainer, string GUID) { VirtualThread VThread = new VirtualThread(new SimulationObject(Obj, ObjectContainer, GUID)); m_Threads.Add(VThread); }
public DGRPRenderer(DGRP group, OBJD source) { this.DrawGroup = group; this.Source = source; }
public PackageType getType(Database db, bool loopAll) { // Do some quick sanity checks switch (db.dbpf.packageType) { case PackageTypes.genericPackage: break; case PackageTypes.corruptBadDownload: case PackageTypes.corruptChaavik: case PackageTypes.corruptIndex: case PackageTypes.corruptPeggy: case PackageTypes.corruptNotADBPF: case PackageTypes.corruptTXTC: this.isCorrupt = true; this.pType.SubType = ""; this.pType.MainType = db.dbpf.packageType; return(this.pType); case PackageTypes.sims3Store: case PackageTypes.sims2Package: case PackageTypes.pngThumbnail: this.pType.SubType = ""; this.pType.MainType = db.dbpf.packageType; return(this.pType); } rc.Clear(); this.pType = new PackageType(); //print(db.dbpf.Entries.Count + " entries found"); for (int i = 0; i < db.dbpf.Entries.Count; i++) { DatabasePackedFile.Entry entry = db.dbpf.Entries[i]; if ((entry.Key.typeId == (uint)ResourceTypes.NULL) && (entry.Key.groupId == (uint)ResourceTypes.NULL) && (entry.Key.instanceId == (uint)ResourceTypes.NULL)) { // Check the first 4 bytes of the stream Stream checkDbpf = db.GetResourceStream(entry.Key); string magic = MadScience.StreamHelpers.ReadStringASCII(checkDbpf, 4); if (magic == "DBPF" || magic == "DBBF") // DBPF & DBBF { this.isCorrupt = true; this.pType.MainType = PackageTypes.corruptRecursive; this.pType.SubType = "This package contains another package inside it."; if (!loopAll) { return(this.pType); } } checkDbpf.Close(); } if (entry.Key.typeId == (uint)ResourceTypes.TXTC) { int isValid = checkValidEntry(entry, db); if (isValid > 0) { if (isValid == 2) { this.isCorrupt = true; this.pType.MainType = PackageTypes.corruptTXTC; if (!loopAll) { return(this.pType); } } } } if (entry.Key.typeId == (uint)ResourceTypes.PTRN) { if (this.pType.MainType == PackageTypes.genericPackage) { this.pType.MainType = PackageTypes.patternGeneric; } if (!loopAll) { return(this.pType); } } if (Enum.IsDefined(typeof(ResourceTypes), entry.Key.typeId)) { if (rc.ContainsKey(Enum.GetName(typeof(ResourceTypes), entry.Key.typeId))) { rc[Enum.GetName(typeof(ResourceTypes), entry.Key.typeId)]++; } else { rc.Add(Enum.GetName(typeof(ResourceTypes), entry.Key.typeId), 1); } } } //print("Done"); if (rc.ContainsKey("WLOT") && rc.ContainsKey("UNKW1")) { if (this.pType.MainType == PackageTypes.genericPackage) { this.pType.MainType = PackageTypes.neighbourhood; } this.isCorrupt = true; return(this.pType); } if (rc.ContainsKey("WLTL") && rc.ContainsKey("ARY2")) { this.pType.MainType = PackageTypes.lot; return(this.pType); } if (rc.ContainsKey("SIMO") && rc.ContainsKey("SIME") && rc.ContainsKey("SNAP") && rc.ContainsKey("SNAPL")) { this.pType.MainType = PackageTypes.sim; return(this.pType); } //this.pType.MainType = PackageTypes.genericPackage; // Check Objects if (rc.ContainsKey("OBJD")) { if (this.pType.MainType == PackageTypes.genericPackage) { this.pType.MainType = PackageTypes.objectGeneric; } Stream objStream = MadScience.Package.Search.getStream(db, 0x319E4F1D, -1, -1); if (StreamHelpers.isValidStream(objStream)) { OBJD objd = new OBJD(objStream); this.pType.SubType = objd.ToString(); objd = null; } return(this.pType); } if (rc.ContainsKey("S3SA")) { if (this.pType.MainType == PackageTypes.genericPackage) { this.pType.MainType = PackageTypes.coremod; } } if (rc.ContainsKey("CASP")) { if (this.pType.MainType == PackageTypes.genericPackage) { this.pType.MainType = PackageTypes.casPartGeneric; } Stream casStream = MadScience.Package.Search.getStream(db, 0x034AEECB, -1, -1); if (StreamHelpers.isValidStream(casStream)) { casPartFile cFile = new casPartFile(); cFile.Load(casStream); this.pType.SubType = cFile.clothingType(); switch (cFile.casType()) { case "Hair": this.pType.MainType = PackageTypes.casPartHair; break; case "Scalp": break; case "Face Overlay": switch (cFile.clothingType()) { case "Lipstick": case "Eyeshadow": case "Eyeliner": case "Blush": case "Makeup": case "Mascara": this.pType.MainType = PackageTypes.casPartMakeup; break; default: this.pType.MainType = PackageTypes.casPartFaceOverlay; break; } break; case "Body": this.pType.MainType = PackageTypes.casPartClothing; this.pType.SubType = cFile.clothingCategory(); // Check the TYPE of clothing we have switch (cFile.clothingType()) { case "Body": case "Top": case "Bottom": case "Shoes": // Check the age too // If we have Toddler OR Child OR Teen, plus other ages bool ageCorrupt = false; //if ((cFile.cFile.ageGender.baby || cFile.cFile.ageGender.toddler || cFile.cFile.ageGender.child || cFile.cFile.ageGender.teen) && (cFile.cFile.ageGender.youngAdult || cFile.cFile.ageGender.adult || cFile.cFile.ageGender.elder)) //{ // ageCorrupt = true; //} // If we have Baby AND any other age... if (cFile.cFile.ageGender.baby && (cFile.cFile.ageGender.toddler || cFile.cFile.ageGender.child || cFile.cFile.ageGender.teen || cFile.cFile.ageGender.youngAdult || cFile.cFile.ageGender.adult || cFile.cFile.ageGender.elder)) { ageCorrupt = true; } // If we have Toddler AND any other age... if (cFile.cFile.ageGender.toddler && (cFile.cFile.ageGender.child || cFile.cFile.ageGender.teen || cFile.cFile.ageGender.youngAdult || cFile.cFile.ageGender.adult || cFile.cFile.ageGender.elder)) { ageCorrupt = true; } // If we have Child AND any other age if (cFile.cFile.ageGender.child && (cFile.cFile.ageGender.teen || cFile.cFile.ageGender.youngAdult || cFile.cFile.ageGender.adult || cFile.cFile.ageGender.elder)) { ageCorrupt = true; } // If we have Teen AND any other age if (cFile.cFile.ageGender.teen && (cFile.cFile.ageGender.youngAdult || cFile.cFile.ageGender.adult || cFile.cFile.ageGender.elder)) { ageCorrupt = true; } if (ageCorrupt) { this.isCorrupt = true; this.pType.MainType = PackageTypes.corruptBadAges; if (!loopAll) { return(this.pType); } } break; default: break; } break; case "Accessory": this.pType.MainType = PackageTypes.casPartAccessory; break; } this.pType.SubType += " (" + cFile.ageGender() + ")"; } return(this.pType); } if (rc.ContainsKey("FBLN") && rc.ContainsKey("FACE") && rc.ContainsKey("BOND")) { if (this.pType.MainType == PackageTypes.genericPackage) { this.pType.MainType = PackageTypes.casSlider; } return(this.pType); } if (rc.ContainsKey("_IMG") && rc.Count == 1) { if (this.pType.MainType == PackageTypes.genericPackage) { this.pType.MainType = PackageTypes.textureReplacement; } } if (rc.Count == 1 && (rc.ContainsKey("_XML") || rc.ContainsKey("_XML2"))) { if (this.pType.MainType == PackageTypes.genericPackage) { this.pType.MainType = PackageTypes.xmltuningmod; } } return(this.pType); }
public DGRPRendererRC(DGRP group, OBJD source) : base(group) { Source = source; }
private void OKButton_Click(object sender, EventArgs e) { var name = ChunkLabelEntry.Text; var guidT = GUIDEntry.Text; uint guid; var objProvider = Content.Content.Get().WorldObjects; if (name == "") { MessageBox.Show("Name cannot be empty!", "Invalid Object Name"); } else if (guidT == "") { MessageBox.Show("GUID cannot be empty!", "Invalid GUID"); } else if (!uint.TryParse(guidT, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out guid)) { MessageBox.Show("GUID is invalid! Make sure it is a hex string of size 8. (eg. 6789ABCD)", "Invalid GUID"); } else { lock (objProvider.Entries) { if (objProvider.Entries.ContainsKey(guid)) { MessageBox.Show("This GUID is already being used!", "GUID is Taken!"); return; } //OK, it's valid. Now to add it to the objects system... //This is a little tricky because we want to add an object that does not exist yet. //There's a special function just for this! But first, we need an OBJD... var obj = new OBJD() { GUID = guid, ObjectType = OBJDType.Normal, ChunkLabel = name, ChunkID = 1, ChunkProcessed = true, ChunkType = "OBJD", ChunkParent = TargetIff, AnimationTableID = 128, AddedByPatch = true }; Content.Content.Get().Changes.BlockingResMod(new ResAction(() => { //find a free space to place the object ushort id = 16807; //todo: why??? var list = TargetIff.List <OBJD>(); if (list != null) { foreach (var chk in list.OrderBy(x => x.ChunkID)) { if (chk.ChunkID == id) { id++; } } } obj.ChunkID = id; //add it to the iff file TargetIff.AddChunk(obj); }, obj)); if (IsNew) { //add a default animation table, for quality of life reasons var anim = new STR() { ChunkLabel = name, ChunkID = 128, ChunkProcessed = true, ChunkType = "STR#", ChunkParent = TargetIff, }; anim.InsertString(0, new STRItem { Value = "", Comment = "" }); TargetIff.AddChunk(anim); var filename = TargetIff.RuntimeInfo.Path; Directory.CreateDirectory(Path.GetDirectoryName(filename)); using (var stream = new FileStream(filename, FileMode.Create)) TargetIff.Write(stream); } //add it to the provider objProvider.AddObject(TargetIff, obj); DialogResult = DialogResult.OK; ResultGUID = guid; Close(); } } }
//hilariously large switch case. there's got to be a better way public static short GetEntityDefinitionVar(OBJD objd, VMOBJDVariable var, VMStackFrame context) { switch (var) { case VMOBJDVariable.Version1: return((short)(objd.Version % 0xFFFF)); case VMOBJDVariable.Version2: return((short)(objd.Version >> 16)); case VMOBJDVariable.InitialStackSize: return((short)objd.StackSize); case VMOBJDVariable.BaseGraphic: return((short)objd.BaseGraphicID); case VMOBJDVariable.NumGraphics: return((short)objd.NumGraphics); case VMOBJDVariable.MainTreeID: return((short)objd.BHAV_MainID); // should this use OBJf functions? case VMOBJDVariable.GardeningTreeID: return((short)objd.BHAV_GardeningID); case VMOBJDVariable.TreeTableID: return((short)objd.TreeTableID); case VMOBJDVariable.InteractionGroup: return((short)objd.InteractionGroupID); case VMOBJDVariable.Type: return((short)objd.ObjectType); case VMOBJDVariable.MasterID: return((short)objd.MasterID); case VMOBJDVariable.SubIndex: return((short)objd.SubIndex); case VMOBJDVariable.WashHandsTreeID: return((short)objd.BHAV_WashHandsID); case VMOBJDVariable.AnimTableID: return((short)objd.AnimationTableID); case VMOBJDVariable.GUID1: return((short)(objd.GUID % 0xFFFF)); case VMOBJDVariable.GUID2: return((short)(objd.GUID >> 16)); case VMOBJDVariable.Disabled: return((short)objd.Disabled); case VMOBJDVariable.PortalTreeID: throw new VMSimanticsException("Not Implemented!", context); case VMOBJDVariable.Price: return((short)objd.Price); case VMOBJDVariable.BodyStringsID: return((short)objd.BodyStringID); case VMOBJDVariable.SlotsID: return((short)objd.SlotID); case VMOBJDVariable.AllowIntersectionTreeID: return((short)objd.BHAV_AllowIntersectionID); case VMOBJDVariable.UsesFnTable: return((short)objd.UsesFnTable); case VMOBJDVariable.Bitfield1: return((short)objd.BitField1); case VMOBJDVariable.PrepareFoodTreeID: return((short)objd.BHAV_PrepareFoodID); case VMOBJDVariable.CookFoodTreeID: return((short)objd.BHAV_CookFoodID); case VMOBJDVariable.PlaceOnSurfaceTreeID: return((short)objd.BHAV_PlaceSurfaceID); case VMOBJDVariable.DisposeTreeID: return((short)objd.BHAV_DisposeID); case VMOBJDVariable.EatFoodTreeID: return((short)objd.BHAV_EatID); case VMOBJDVariable.PickupFromSlotTreeID: return((short)objd.BHAV_PickupFromSlotID); //uh case VMOBJDVariable.WashDishTreeID: return((short)objd.BHAV_WashDishID); case VMOBJDVariable.EatingSurfaceTreeID: return((short)objd.BHAV_EatSurfaceID); case VMOBJDVariable.SitTreeID: return((short)objd.BHAV_SitID); case VMOBJDVariable.StandTreeID: return((short)objd.BHAV_StandID); case VMOBJDVariable.SalePrice: return((short)objd.SalePrice); case VMOBJDVariable.Unused35: throw new VMSimanticsException("Not Implemented!", context); case VMOBJDVariable.Unused36: throw new VMSimanticsException("Not Implemented!", context); case VMOBJDVariable.BrokenBaseGraphicOffset: throw new VMSimanticsException("Not Implemented!", context); case VMOBJDVariable.Unused38: throw new VMSimanticsException("Not Implemented!", context); case VMOBJDVariable.HasCriticalAttributes: throw new VMSimanticsException("Not Implemented!", context); case VMOBJDVariable.BuyModeType: return((short)objd.FunctionFlags); case VMOBJDVariable.CatalogStringsID: return((short)objd.CatalogStringsID); case VMOBJDVariable.IsGlobalSimObject: return((short)objd.Global); case VMOBJDVariable.InitTreeID: return((short)objd.BHAV_Init); case VMOBJDVariable.PlaceTreeID: return((short)objd.BHAV_Place); case VMOBJDVariable.UserPickupTreeID: return((short)objd.BHAV_UserPickup); case VMOBJDVariable.WallStyle: return((short)objd.WallStyle); case VMOBJDVariable.LoadTreeID: return((short)objd.BHAV_Load); case VMOBJDVariable.UserPlaceTreeID: return((short)objd.BHAV_UserPlace); case VMOBJDVariable.ObjectVersion: return((short)objd.ObjectVersion); case VMOBJDVariable.RoomChangedTreeID: return((short)objd.BHAV_RoomChange); case VMOBJDVariable.MotiveEffectsID: return((short)objd.MotiveEffectsID); case VMOBJDVariable.CleanupTreeID: return((short)objd.BHAV_Cleanup); case VMOBJDVariable.LevelInfoRequestTreeID: return((short)objd.BHAV_LevelInfo); case VMOBJDVariable.CatalogPopupID: return((short)objd.CatalogID); case VMOBJDVariable.ServingSurfaceTreeID: return((short)objd.CatalogID); case VMOBJDVariable.LevelOffset: return((short)objd.LevelOffset); case VMOBJDVariable.Shadow: return((short)objd.Shadow); case VMOBJDVariable.NumAttributes: return((short)objd.NumAttributes); case VMOBJDVariable.CleanTreeID: return((short)objd.BHAV_Clean); case VMOBJDVariable.QueueSkippedTreeID: return((short)objd.BHAV_QueueSkipped); case VMOBJDVariable.FrontDirection: return((short)objd.FrontDirection); case VMOBJDVariable.WallAdjacencyChangedTreeID: return((short)objd.BHAV_WallAdjacencyChanged); case VMOBJDVariable.MyLeadObject: return((short)objd.MyLeadObject); case VMOBJDVariable.DynamicSpritesBaseID: return((short)objd.DynamicSpriteBaseId); case VMOBJDVariable.NumDynamicSprites: return((short)objd.NumDynamicSprites); case VMOBJDVariable.ChairEntryFlags: return((short)objd.ChairEntryFlags); case VMOBJDVariable.TileWidth: return((short)objd.TileWidth); case VMOBJDVariable.LotCategories: return(0); //NOT IN OBJD RIGHT NOW! case VMOBJDVariable.BuildModeType: return((short)objd.BuildModeType); case VMOBJDVariable.OriginalGUID1: return((short)objd.OriginalGUID1); case VMOBJDVariable.OriginalGUID2: return((short)objd.OriginalGUID2); case VMOBJDVariable.SuitGUID1: return((short)objd.SuitGUID1); case VMOBJDVariable.SuitGUID2: return((short)objd.SuitGUID2); case VMOBJDVariable.PickupTreeID: return((short)objd.BHAV_Pickup); case VMOBJDVariable.ThumbnailGraphic: return((short)objd.ThumbnailGraphic); case VMOBJDVariable.ShadowFlags: return((short)objd.ShadowFlags); case VMOBJDVariable.FootprintMask: return((short)objd.FootprintMask); case VMOBJDVariable.DynamicMultiTileUpdateTreeID: return((short)objd.BHAV_DynamicMultiTileUpdate); case VMOBJDVariable.ShadowBrightness: return((short)objd.ShadowBrightness); case VMOBJDVariable.RepairTreeID: return((short)objd.BHAV_Repair); case VMOBJDVariable.WallStyleSpriteID: return((short)objd.WallStyleSpriteID); case VMOBJDVariable.RatingHunger: return((short)objd.RatingHunger); case VMOBJDVariable.RatingComfort: return((short)objd.CatalogID); case VMOBJDVariable.RatingHygiene: return((short)objd.RatingHygiene); case VMOBJDVariable.RatingBladder: return((short)objd.RatingBladder); case VMOBJDVariable.RatingEnergy: return((short)objd.RatingEnergy); case VMOBJDVariable.RatingFun: return((short)objd.RatingFun); case VMOBJDVariable.RatingRoom: return((short)objd.RatingRoom); case VMOBJDVariable.RatingSkillFlags: return((short)objd.RatingSkillFlags); case VMOBJDVariable.NumTypeAttributes: throw new VMSimanticsException("Not Implemented!", context); //?? case VMOBJDVariable.MiscFlags: throw new VMSimanticsException("Not Implemented!", context); //?? case VMOBJDVariable.TypeAttrGUID1: throw new VMSimanticsException("Not Implemented!", context); case VMOBJDVariable.TypeAttrGUID2: throw new VMSimanticsException("Not Implemented!", context); case VMOBJDVariable.InteractionResultStrings: throw new VMSimanticsException("Not Implemented!", context); case VMOBJDVariable.ClientHouseJoinTreeID: throw new VMSimanticsException("Not Implemented!", context); case VMOBJDVariable.PrepareForSaleTreeID: throw new VMSimanticsException("Not Implemented!", context); default: throw new VMSimanticsException("Unknown definition var", context); } }
public DGRP3DMesh(DGRP dgrp, OBJD obj, GraphicsDevice gd, string saveDirectory) { ReconstructVersion = CURRENT_RECONSTRUCT; SaveDirectory = saveDirectory; Geoms = new List <Dictionary <Texture2D, DGRP3DGeometry> >(); if (dgrp == null) { return; } Name = obj.ChunkParent.Filename.Replace('.', '_') + "_" + dgrp.ChunkID; var lower = obj.ChunkParent.Filename.ToLowerInvariant(); var config = obj.ChunkParent.List <FSOR>()?.FirstOrDefault()?.Params; if (config == null) { if (!ParamsByIff.TryGetValue(lower, out config)) { config = DefaultParams; } } if (!config.InRange(dgrp.ChunkID)) { config = DefaultParams; } int totalSpr = 0; for (uint rotation = 0; rotation < 4; rotation++) { if (config.DoorFix) { if ((obj.SubIndex & 0xFF) == 1) { if ((rotation + 1) % 4 > 1) { continue; } } else { if ((rotation + 1) % 4 < 2) { continue; } } } else if (!config.Rotations[rotation]) { continue; } var img = dgrp.GetImage(1, 3, rotation); var zOff = (config.BlenderTweak) ? -57.5f : -55f; var mat = Matrix.CreateTranslation(new Vector3(-72, -344, zOff)); mat *= Matrix.CreateScale((1f / (128)) * 1.43f);//1.4142135623730f); mat *= Matrix.CreateScale(1, -1, 1); mat *= Matrix.CreateRotationX((float)Math.PI / -6); mat *= Matrix.CreateRotationY(((float)Math.PI / 4) * (1 + rotation * 2)); var factor = (config.BlenderTweak) ? 0.40f : 0.39f; int curSpr = 0; foreach (var sprite in img.Sprites) { var sprMat = mat * Matrix.CreateTranslation(new Vector3(sprite.ObjectOffset.X, sprite.ObjectOffset.Z, sprite.ObjectOffset.Y) * new Vector3(1f / 16f, 1f / 5f, 1f / 16f)); var inv = Matrix.Invert(sprMat); var tex = sprite.GetTexture(gd); if (tex == null) { curSpr++; continue; } var isDynamic = sprite.SpriteID >= obj.DynamicSpriteBaseId && sprite.SpriteID < (obj.DynamicSpriteBaseId + obj.NumDynamicSprites); var dynid = (isDynamic) ? (int)(1 + sprite.SpriteID - obj.DynamicSpriteBaseId) : 0; while (Geoms.Count <= dynid) { Geoms.Add(new Dictionary <Texture2D, DGRP3DGeometry>()); } DGRP3DGeometry geom = null; if (!Geoms[dynid].TryGetValue(tex, out geom)) { geom = new DGRP3DGeometry() { Pixel = tex }; Geoms[dynid][geom.Pixel] = geom; } geom.PixelDir = (ushort)rotation; geom.PixelSPR = (ushort)(curSpr++); totalSpr++; var depthB = sprite.GetDepth(); var useDequantize = false; float[] depth = null; int iterations = 125; int triDivisor = 100; float aggressiveness = 3.5f; if (useDequantize) { var dtex = new Texture2D(gd, ((TextureInfo)tex.Tag).Size.X, ((TextureInfo)tex.Tag).Size.Y, false, SurfaceFormat.Color); dtex.SetData(depthB.Select(x => new Color(x, x, x, x)).ToArray()); depth = DepthTreatment.DequantizeDepth(gd, dtex); dtex.Dispose(); iterations = 500; aggressiveness = 2.5f; MaxAllowedSq = 0.05f * 0.05f; } else if (depthB != null) { depth = depthB.Select(x => x / 255f).ToArray(); iterations = 125; aggressiveness = 3.5f; } if (depth == null) { continue; } QueueWork(() => { var boundPts = new List <Vector3>(); //begin async part var w = ((TextureInfo)tex.Tag).Size.X; var h = ((TextureInfo)tex.Tag).Size.Y; var pos = sprite.SpriteOffset + new Vector2(72, 348 - h); var tl = Vector3.Transform(new Vector3(pos, 0), sprMat); var tr = Vector3.Transform(new Vector3(pos + new Vector2(w, 0), 0), sprMat); var bl = Vector3.Transform(new Vector3(pos + new Vector2(0, h), 0), sprMat); var tlFront = Vector3.Transform(new Vector3(pos, 110.851251f), sprMat); var xInc = (tr - tl) / w; var yInc = (bl - tl) / h; var dFactor = (tlFront - tl) / (factor); if (sprite.Flip) { tl = tr; xInc *= -1; } var dict = new Dictionary <int, int>(); var verts = new List <VertexPositionTexture>(); var indices = new List <int>(); var lastPt = new Vector3(); var i = 0; var verti = 0; for (int y = 0; y < h; y++) { if (y > 0) { boundPts.Add(lastPt); } bool first = true; var vpos = tl; for (int x = 0; x < w; x++) { var d = depth[i++]; if (d < 0.999f) { lastPt = vpos + (1f - d) * dFactor; if (first) { boundPts.Add(lastPt); first = false; } var vert = new VertexPositionTexture(lastPt, new Vector2((float)x / w, (float)y / h)); verts.Add(vert); dict.Add(y * w + x, verti++); } vpos += xInc; } tl += yInc; } for (int y = 0; y < h - 1; y++) { for (int x = 0; x < w - 1; x++) { //try make a triangle or two var quad = new int?[] { QuickTryGet(dict, x + y * w), QuickTryGet(dict, x + 1 + y * w), QuickTryGet(dict, x + 1 + (y + 1) * w), QuickTryGet(dict, x + (y + 1) * w) }; var total = quad.Sum(v => (v == null) ? 0 : 1); if (total == 4) { var d1 = Vector3.DistanceSquared(verts[quad[0].Value].Position, verts[quad[2].Value].Position); var d2 = Vector3.DistanceSquared(verts[quad[1].Value].Position, verts[quad[3].Value].Position); if (d1 > MaxAllowedSq || d2 > MaxAllowedSq) { continue; } indices.Add(quad[0].Value); indices.Add(quad[1].Value); indices.Add(quad[2].Value); indices.Add(quad[0].Value); indices.Add(quad[2].Value); indices.Add(quad[3].Value); } else if (total == 3) { //clockwise anyways. we can only make one int?last = null; int?first = null; bool exit = false; foreach (var v in quad) { if (v != null) { if (last != null && Vector3.DistanceSquared(verts[last.Value].Position, verts[v.Value].Position) > MaxAllowedSq) { exit = true; break; } last = v.Value; if (first == null) { first = last; } } } if (!exit && Vector3.DistanceSquared(verts[last.Value].Position, verts[first.Value].Position) > MaxAllowedSq) { exit = true; } if (exit) { continue; } foreach (var v in quad) { if (v != null) { indices.Add(v.Value); } } } } } if (config.CounterFix) { //x axis extrapolation //clip: -0.4 to 0.4 //identify vertices very close to clipping range(border) //! for each vertex outwith clipping range //- idendify closest border pixel bp in image space //- result.zy = bp.zy //- result.x = (resultIMAGE.x - bpIMAGE.x) / 64; //- clip x to -0.5, 0.5f. var clip = 0.4; var bWidth = 0.02; var border1 = new List <Tuple <Vector2, Vector3> >(); var invalid1 = new List <KeyValuePair <int, int> >(); var border2 = new List <Tuple <Vector2, Vector3> >(); var invalid2 = new List <KeyValuePair <int, int> >(); foreach (var vert in dict) { var vpos = verts[vert.Value].Position; var dist = Math.Abs(vpos.X); if (dist > clip) { if (vpos.X > 0) { invalid1.Add(vert); } else { invalid2.Add(vert); } } else if (dist > (clip - bWidth)) { if (vpos.X > 0) { border1.Add(new Tuple <Vector2, Vector3>(new Vector2(vert.Key % w, vert.Key / w), vpos)); } else { border2.Add(new Tuple <Vector2, Vector3>(new Vector2(vert.Key % w, vert.Key / w), vpos)); } } } var edge = 0.498f + 0.001f * (rotation % 2); if (border1.Count > 0) { foreach (var vert in invalid1) { var vstr = verts[vert.Value]; var pos2d = new Vector2(vert.Key % w, vert.Key / w); var vpos = vstr.Position; var closest = border1.OrderBy(x => Vector2.DistanceSquared(x.Item1, pos2d)).First(); vpos.X = closest.Item2.X + Vector2.Distance(closest.Item1, pos2d) / 71.55f; if (vpos.X > 0.5f) { vpos.X = edge; } else { vpos.Y = closest.Item2.Y; vpos.Z = closest.Item2.Z; } vstr.Position = vpos; verts[vert.Value] = vstr; } } if (border2.Count > 0) { foreach (var vert in invalid2) { var vstr = verts[vert.Value]; var pos2d = new Vector2(vert.Key % w, vert.Key / w); var vpos = vstr.Position; var closest = border2.OrderBy(x => Vector2.DistanceSquared(x.Item1, pos2d)).First(); vpos.X = closest.Item2.X - Vector2.Distance(closest.Item1, pos2d) / 71.55f; if (vpos.X < -0.5f) { vpos.X = -edge; } else { vpos.Y = closest.Item2.Y; vpos.Z = closest.Item2.Z; } vstr.Position = vpos; verts[vert.Value] = vstr; } } } lock (BoundPts) BoundPts.AddRange(boundPts); var useSimplification = config.Simplify; if (useSimplification) { var simple = new Simplify(); simple.vertices = verts.Select(x => new MSVertex() { p = x.Position, t = x.TextureCoordinate }).ToList(); for (int t = 0; t < indices.Count; t += 3) { simple.triangles.Add(new MSTriangle() { v = new int[] { indices[t], indices[t + 1], indices[t + 2] } }); } simple.simplify_mesh(simple.triangles.Count / triDivisor, agressiveness: aggressiveness, iterations: iterations); verts = simple.vertices.Select(x => { var iv = Vector3.Transform(x.p, inv); //DGRP3DVert return(new VertexPositionTexture(x.p, new Vector2( (sprite.Flip) ? (1 - ((iv.X - pos.X + 0.5f) / w)) : ((iv.X - pos.X + 0.5f) / w), (iv.Y - pos.Y + 0.5f) / h))); } ).ToList(); indices.Clear(); foreach (var t in simple.triangles) { indices.Add(t.v[0]); indices.Add(t.v[1]); indices.Add(t.v[2]); } GameThread.NextUpdate(x => { if (geom.SVerts == null) { geom.SVerts = new List <DGRP3DVert>(); geom.SIndices = new List <int>(); } var bID = geom.SVerts.Count; foreach (var id in indices) { geom.SIndices.Add(id + bID); } var verts2 = verts.Select(v => new DGRP3DVert(v.Position, Vector3.Zero, v.TextureCoordinate)).ToList(); DGRP3DVert.GenerateNormals(!sprite.Flip, verts2, indices); geom.SVerts.AddRange(verts2); lock (this) { if (++CompletedCount == TotalSprites) { Complete(gd); } } }); } else { GameThread.NextUpdate(x => { if (geom.SVerts == null) { geom.SVerts = new List <DGRP3DVert>(); geom.SIndices = new List <int>(); } var baseID = geom.SVerts.Count; foreach (var id in indices) { geom.SIndices.Add(id + baseID); } var verts2 = verts.Select(v => new DGRP3DVert(v.Position, Vector3.Zero, v.TextureCoordinate)).ToList(); DGRP3DVert.GenerateNormals(!sprite.Flip, verts2, indices); geom.SVerts.AddRange(verts2); lock (this) { if (++CompletedCount == TotalSprites) { Complete(gd); } } }); } }); } } TotalSprites = totalSpr; }