Hoy en día es muy difícil encontrar información sólida y ayuda real con respecto a S3PI, aún más si está intentando crear un programa que use S3PI como una biblioteca para interactuar con los archivos del paquete SIMS. Además, la biblioteca S3PI no está en GitHub y no tiene un repositorio aquí.
Por estas razones, decidí crear este repositorio para almacenar la biblioteca S3PI en su totalidad, con ejemplos de código y consejos sobre cómo usarla correctamente. ¡Además, he compilado aquí toda la información útil que encontré en Internet relacionada con S3PI!
Si desea contribuir con más información, cree una solicitud de extracción o informe a través de la pestaña "Problemas". Haré todo lo posible para mantener este repositorio con tanta información y ejemplos como pueda, pero si el autor de S3PI lo solicita, lo haré sin conexión este repositorio.
Importante
¡Recordando que todos los créditos para la creación de la biblioteca S3PI van al increíble "Peter L Jones"!
La "interfaz de paquete SIMS 3" proporciona una biblioteca central de código portátil que "entiende" los paquetes de juego SIMS3. Tenga en cuenta que (con algunos ajustes menores) el código de la biblioteca principal también comprende otros formatos de paquete de juego (por ejemplo, SimCity Online, SIMS4).
Junto con la biblioteca central hay una serie de "envoltorios" que proporcionan la parte principal del proyecto. Estos manejan la deserialización y la serialización de los datos dentro del paquete (o cualquier otra fuente).
Otras herramientas pueden usar esta biblioteca y envoltorios para manipular el contenido de datos de los archivos de paquetes de los juegos SIMS.
Tenga en cuenta que el desarrollo en esta biblioteca y envoltorios proporcionados aquí ahora ha terminado.
El "S3PI" es un acrónimo de "Interfaz del paquete SIMS3 ™". Proporciona soporte para acceder a los datos dentro del juego individual de "paquete" utilizados por Electronic Arts SIMS3 ™ Game. Un "paquete" es un archivo de disco con una extensión de archivo generalmente de ". Package" (pero se utilizan otras extensiones). Sin embargo, la característica de identificación principal utilizada por S3PI es la cookie mágica de cuatro bytes al comienzo del archivo, que debe ser "DBPF". Además, el número de versión de formato de archivo debe ser 2 para SIMS 3 ™ (o 3 para SIM City 5 ™, que apenas es compatible).
Tenga en cuenta que los paquetes "protegidos" (con una galleta mágica de "DBPP") no son compatibles. Tenga en cuenta que los paquetes "temporales" (con una galleta mágica de "DBBF") no son compatibles actualmente.
El S3PI es un conjunto de ensamblados .NET (documentados a continuación y disponibles aquí) que implementan las descripciones de la wiki SIMS 3 (con estas páginas alternativamente disponibles aquí como wiki-mirror). Tenga en cuenta que siempre vale la pena verificar allí si no está seguro de algo, ya sea sobre cómo debería funcionar algo o si cree que ha encontrado un problema en S3PI, lo que sigue siendo muy posible. Ni el wiki ni la biblioteca siempre son correctos; de hecho, puede ser que ambos estén equivocados de diferentes maneras.
La biblioteca S3PI viene con un archivo de ayuda compilado (.CHM) que describe gran parte de lo que necesita saber. También puede acceder a una versión de esto, aquí. Esta página intenta dar una visión general rápida, ya que la biblioteca es bastante extensa y puede ser difícil resolver lo que necesita saber.
Esta página se divide en tres secciones restantes.
Una vez que comprenda cómo usar un envoltorio para acceder a los datos en un paquete, debe consultar la lista SIMS3 Wiki de tipos de archivos para ver cuáles son compatibles y cómo obtener el soporte (si no parte de la distribución S3PI).
Consejo
Si tiene preguntas sin respuesta, no dude en publicar aquí en el foro/discusiones. ¡Será un placer ayudarlo!
La biblioteca es un conjunto de DLL de ensamblaje .NET. Si es probable que trabaje en más de un proyecto que usa la biblioteca, le aconsejo ponerlos en una carpeta separada de su proyecto y espacios de trabajo de solución, pero cerca de la estructura de su carpeta. De esta manera, es fácil reemplazarlos a todos sin tener que actualizar cada proyecto.
Para usar la biblioteca de un nuevo proyecto, primero debe saber qué partes de la biblioteca va a usar. Deliberadamente he mantenido las piezas dependientes separadas para que su proyecto solo necesite hacer referencia a las DLL que necesita, por lo tanto, manteniendo el tamaño de su proyecto. ¡La desventaja es que hay muchas DLL!
Lo primero que debe notar es que muchos de ellos son "envoltorios", cualquier cosa con un nombre como SomethingResource.DLL . Estos contienen el código para comprender el contenido de uno o más recursos dentro de un archivo de paquete SIMS 3.
Primero, echemos un vistazo a cada uno de los ensamblajes restantes. Después de esto, proporcionaré un resumen de cómo comenzar un nuevo proyecto. Terminaré con algunas ideas sobre la organización de sus prácticas de trabajo.
Nota
Debe aceptar la licencia GPLV3 antes de distribuir su código. Observe que, mientras está vinculando a una biblioteca GPLV3, esencialmente la está reutilizando y debe distribuir su código en términos equivalentes. Puede encontrar más detalles en el sitio de la Free Software Software Foundation.
Cuándo incluirlo: siempre, es requerido por varias otras partes de la biblioteca.
Resumen: contiene una serie de clases que no se relacionan directamente con "los Sims 3" y no tienen referencias a ninguno de los tipos s3pi.Interfaces . Podrían, posiblemente ser de uso para proyectos que no usan el resto de la biblioteca S3PI (por lo tanto, manteniéndola separada).
Lectura adicional: Al hacer referencia a esta asamblea, obtienes lo siguiente ...
System.Collections.Generic.AHandlerList<T> - Extensión abstracta de List<T> Proporcionar comentarios sobre las actualizaciones de la lista a través de un EventHandler suministrado.System.ArgumentLengthException : representa un error en la longitud de un argumento a un método.System.Extensions : métodos de extensión útiles no proporcionados por LINQ (y sin ejecución diferida). (El nombre de la clase es dudoso y puede cambiar ...)System.Security.Cryptography.FNV32 - rutina de hash fnv32System.Security.Cryptography.FNV64 - rutina de hash fnv64System.Text.SevenBitString : lea y escriba una cadena prefijada de longitud codificada de siete bits en una Encoding dada desde o hacia una Stream .System.Security.Cryptography.Sims3PackCRC : calcule el CRC de una fragmentación de datos almacenada en un archivo SIMS3pack. (Ok, podría decirse que esto no tiene razón aquí, pero en términos de dependencias del código, ¡tiene sentido!) Cuándo incluirlo: siempre.
Resumen: Originalmente destinado a permitir que se cambien varias configuraciones internas a la biblioteca reemplazando la DLL. Esto nunca ha sucedido.
Lectura adicional: nada.
Cuándo incluirlo: siempre. La biblioteca no solo requiere la biblioteca, sino que define la API pública.
Resumen: proporciona una serie de interfaces, clases abstractas y clases auxiliares utilizadas en toda la biblioteca y envoltorios, que definen los métodos públicos proporcionados por las diversas clases de biblioteca.
Lectura adicional:
s3pi.Interfaces Documentación del espacio de nombres de Interfaces. Tenga en cuenta que el espacio de nombres está "contaminado" por clases de s3pi.GenericRCOL . Los puristas también podrían considerar algunas de las clases de ayuda "contaminación" ...
Cuándo incluirlo: cuando trabaje con archivos de paquete SIMS 3.
Resumen: proporciona la implementación concreta de las clases e interfaces abstractas definidas en s3pi.Interfaces .
Lectura adicional: nada.
Cuándo incluirlo: cuando se trabaja con envoltorios de recursos.
Resumen: si está creando nuevos recursos o recursos de lectura de un paquete, este es el mecanismo recomendado. Sin embargo, existen alternativas.
Lectura adicional:
s3pi.WrapperDealer.WrapperDealer - Responsable de asociar ResourceType en IResourceIndexEntry con una clase particular (un "envoltorio") que lo comprende o el envoltorio predeterminado. El s3pi.DefaultResource y s3pi.GenericRCOLResource proporcionan los conceptos básicos para comprender cómo usar un recurso una vez que tenga una referencia a él.
Cuándo incluirlo: si desea nombres de archivos estándar de la comunidad.
Resumen: al comienzo del SIMS 3, la comunidad de modding acordó un formato establecido sobre cómo se debe nombrar un recurso empaquetado cuando fuera de un archivo de paquete. Este ensamblaje proporciona la implementación para la biblioteca S3PI.
Lecturas adicionales: s3pi.Extensions Space. Esta área de la biblioteca todavía necesita documentar adecuadamente.
Cuándo incluirlo: cuando desea CopyableMessageBox (o IssuEEXception).
Resumen: este ensamblaje proporciona una forma de mostrar mensajes que permiten al usuario copiar el contenido fácilmente. En el futuro, pueden aparecer otros controles generales aquí.
Lectura adicional: CopyableMessageBox Clase, CopyableMessageBoxButtons Enumeration y CopyableMessageBoxIcon Enumeration.
Cuándo incluirlo: cuando desee uno de los controles personalizados.
Resumen: este ensamblaje proporciona controles personalizados relacionados con tipos de datos en S3PI.
Lecturas adicionales: clase ResourceTypeCombo , clase TGIBlockCombo y clase TGIBlockListEditor . Esta área de la biblioteca todavía necesita documentar adecuadamente.
Cuándo incluirlo: cuando usa imágenes DDS y desea una forma de mostrarlas en una aplicación WinForms.
Resumen: este ensamblaje proporciona un control personalizado y soporte de recursos DDS.
Lecturas adicionales: clase DDSPanel y DDSPanel.MaskChannel enumeración.
Cuándo incluirlo: puede ser útil al escribir un ayudante para S3PE.
Resumen: proporciona soporte para mapear un recurso a uno o más programas que puedan estar interesados en ese tipo de recurso.
Lecturas adicionales: s3pi.Helpers Espacio de nombres. Esta área de la biblioteca todavía necesita documentar adecuadamente.
s3pi.Interfaces las referencias que necesita según el System.Custom de sección s3pi.Settings . Además, deberá considerar si desea hacer referencia a conjuntos de envoltura específicos. En la mayoría de los casos, este será el enfoque apropiado. Sus ensamblajes referenciados, de forma predeterminada, se copiarán en la carpeta de salida del proyecto, junto con su programa.
Tenga en cuenta que se utilizan ciertos componentes adicionales, como los archivos de configuración, que también deberá organizar la compilación de su proyecto para copiar (si es más nuevo) a la carpeta de salida.
Es posible que desee mirar las soluciones S3OC y S3PE Visual Studio para ver cómo lo he hecho.
S3PI proporciona una serie de clases de C# para ayudar a los programas que desean acceder a los archivos de paquetes SIMS 3 y los recursos almacenados dentro de ellos. La "biblioteca central" solo comprende el contenedor de paquetes en sí: no tiene comprensión del contenido de los recursos. Eso es delegado a "envoltorios". Los envoltorios se asocian con recursos al declarar la lista de ResourceTypes que admiten. La biblioteca central devuelve una instancia de la clase de recursos de Aproral a la biblioteca "Cliente".
Por lo tanto, los envoltorios tienen dos objetivos principales: proporcionar una "comprensión" del contenido de uno o más tipos de recursos y hacer que la biblioteca central sepa qué tipos de recursos entienden. Un envoltorio puede proporcionar uno o más manejadores de recursos como lo considera adecuado, pero se alienta a los autores a mantener diferentes preocupaciones separadas en diferentes envoltorios.
La biblioteca central identifica envoltorios buscando a través de los ensamblados en la carpeta de la biblioteca S3PI para aquellos con la interfaz apropiada.
WrapperDealer tiene una interfaz que permite a las aplicaciones de los clientes habilitar y deshabilitar combinaciones particulares de ResourceType y Wrapper.
Ahora he incluido DefaultResource en la documentación de la biblioteca S3PI.
El ejemplo más simple es el dado en DefaultResource en la distribución de la fuente. "No hace nada" más allá de lo que es esencial para cualquier envoltorio.
Define dos clases:
public class DefaultResource : AResource { }
public class DefaultResourceHandler : AResourceHandler { } Un ensamblaje que contiene un envoltorio debe contener una clase que implementa AResourceHandler . Esta clase proporciona una búsqueda IDictionary<Type, List<string>> entre una clase que implementa AResource y una lista de cadenas que contienen valores ResourceType . (Las cadenas utilizadas son los valores del TypedValue ResourceType fundido a una cadena, es decir, una cadena hexagonal).
DefaultResource usa "*" para que WrapperDealer sepa que está feliz de tomar todo. ¡No uses esto en tus envoltorios!
DefaultResource , entonces.
Se recomienda encarecidamente que tenga const Int32 recommendedApiVersion = 1; En la parte superior de su clase para la compatibilidad futura. Esto le permite "versión" de la API de su envoltorio si la necesita. Sin embargo, probablemente no sea tan útil en la práctica.
Debe tener la propiedad AApiVersionedFields RecommendedApiVersion .
El constructor de DefaultResource demuestra un punto importante: se crea un nuevo recurso sin saber nada . Puede verificar que es nuevo verificando que la transmisión pasada al constructor es nula. Luego debe crear un MemoryStream y completarlo con el contenido de datos mínimo válido para el recurso.
¡Eso es todo! No hay nada más que debas hacer. Por supuesto, aún no ha proporcionado a nadie una razón para usar su envoltorio ...
Nota
Después de un pensamiento, ImageResource y TextResource se consideran en desuso. Sin embargo, permanecerán en la biblioteca en el futuro previsible. A pesar de lo que se escribe a continuación, ya no considero que sea una buena idea tener un envoltorio para un recurso que sea solo una transmisión de bytes.
El enfoque adoptado para los recursos DDS se considera más correcto. A continuación se establece directamente un corolario: el diseño aquí fue influenciado por S3PE en lugar de implementar cualquier cosa con respecto a la estructura de los datos en sí, que es el propósito de un envoltorio. Esto debería haberse manejado de manera similar a los recursos DDS.
Otro corolario fue la adición y luego la eliminación del envoltorio de recursos _VID durante un ciclo de control de calidad cuando se descubrió que el contenido era puramente la salida de un códec audiovisual de Electronic Arts personalizado, en lugar de tener un contenido útilmente descifrable.
En conclusión: "Valor" debería ser solo una cadena. Normalmente, el formateador incorporado construye uno apropiado de sus propiedades públicas.
Un ejemplo ligeramente más complejo es ImageSource. Se adhiere al modelo de dos clases:
public class ImageResource : AResource { }
public class ImageResourceHandler : AResourceHandler { }Este contenedor maneja imágenes: muchos tipos de recursos diferentes simplemente se almacenan archivos PNG89.
El constructor estático para ImageResourceHandler lee una lista de todos los tipos de recursos de imagen conocidos (desde un archivo en la carpeta donde se encuentra el ensamblaje). Luego se usa para completar la lista de la lista IDictionary<Type, List<string>> en el constructor de instancias, que luego es utilizado por WrapperDealer . Esto significa que es fácil agregar nuevos tipos de recursos a la lista que es compatible con este envoltorio: simplemente edite el archivo de texto y agréguelos, no es necesario recompilarlos. (Es un patrón tan bueno, debería haber hecho que sea más fácil reutilizar ...)
La clase ImageResource sigue siendo bastante simple. Su constructor asegura que haya una imagen PNG89 válida si se pasa una transmisión nula. Y proporciona una propiedad única llamada "valor" que devuelve un System.Drawing.Image creado a partir de los datos PNG89. No es compatible con la búsqueda de imágenes a un recurso existente.
Vale la pena mencionar más la propiedad Value : el S3PI Demo Front End (ahora conocido como S3PE) verifica si un recurso tiene una propiedad Value y, de ser así, si tiene un tipo de imagen o datos de cadena. Sabe mostrar esos dos (y esos dos solo, actualmente). Devolver el apropiado puede ser útil en la depuración.
Notará que la posición de la secuencia se establece en cero antes de usar, siempre suponga que está en un estado desconocido.
El envoltorio TextResource es muy similar: los recursos de texto se definen en un archivo; Tiene una propiedad de "valor" que devuelve el recurso como un valor de cadena. Además, tiene algunas propiedades específicas de texto, incluido el acceso a los datos como XML. (Sería un mejor diseño tener el envoltorio XML como una extensión del envoltorio de texto y solo manejar archivos XML conocidos en él ...)
Este envoltorio maneja un solo tipo de recurso: el mapa del nombre del paquete. Proporciona una interfaz IDictionary<ulong, string> , que permite que el mapa se lea y actualice. Es un ejemplo muy simple de cómo manejar las actualizaciones.
Así es como funciona. Este es un ejemplo simple, pero el patrón se puede extender a necesidades más complejas.
El trabajo se realiza en varios lugares:
La propiedad Stream verifica si el recurso ha sido dirigido (es decir, cambiado). Si es así, descarta la transmisión actual y las llaman UnParse() .
El constructor de instancias verifica una transmisión nula y llama UnParse() para construir el recurso mínimo válido.
El método de Parse(Stream s) lee los datos en la estructura de datos utilizada para manipularlo, aquí un Dictionary<ulong, string> . Como esta es una estructura repetida de entradas de longitud variable que permite insertar datos, no es eficiente usar los datos en la secuencia.
El método UnParse() exporta la estructura de datos a una nueva secuencia, creando nuevos objetos cuando sea necesario.
Como se mencionó anteriormente, la propiedad Stream debe saber si el recurso ha sido sucio. La implementación de la interfaz IDictionary<ulong, string> se ocupa de esto llamando OnResourceChanged(this, EventArgs.Empty) para las operaciones de actualización. Esto se proporciona en AResource y establece el recurso en Dirty, además de llamar a los manejadores ResourceChanged de cualquier cosa que escuche el evento.
Catalogresource realmente solo lleva las ideas en Namempresource más. Tiene una clase abstracta para un conjunto relacionado de recursos. He tratado de mantener un patrón consistente de codificación para ayudar a comprender lo que está sucediendo. Dejo como un ejercicio para que el lector trabaje a través de la implementación para ver cómo están interactuando todas las clases. ¡Ojalá debería tener sentido! (Si no, ¡estaré perplejo cuando salga un error!)
Esto tiene el beneficio de ser reciente y, aunque relativamente simple, tiene algunos bits interesantes. También es uno de los envoltorios que más a menudo me considero cuando escribo uno nuevo.
Un recurso RCOL es un recurso normal, como se describió anteriormente, con la diferencia fundamental de que es un contenedor para otros "recursos", conocidos como bloques RCOL. Cada bloque tiene un formato identificado por un código de cuatro caracteres ("cuatrocc" o etiqueta); Los bloques también tienen tipos de recursos. El recurso RCOL (en el paquete) tiene el mismo tipo que el primer bloque RCOL en (en el recurso) y el recurso lleva el nombre de este primer bloque RCOL. Algunos recursos RCOL solo contienen un solo bloque RCOL; Otros contienen múltiples bloques RCOL.
El soporte básico es proporcionado por s3pi.GenericRCOLResource . Además de leer bloques de y escribir bloques al paquete, el envoltorio de recursos tiene métodos adicionales para respaldar el formato RCOL y hay un registro de los controladores de bloques RCOL.
(Tenga en cuenta que el término "fragmento" se usa libremente para referirse a un bloque RCOL a veces ...)
Hay una clase abstracta, ARCOLBlock , que define los fundamentos. Existe una implementación predeterminada, DefaultRCOL , para cuando no se define ningún otro controlador de bloque RCOL coincidente en el registro, que proporciona un soporte mínimo.
Además de extender ARCOLBlock en lugar de AResource , la tarea de escribir un controlador de bloques RCOL es muy similar a escribir un envoltorio de recursos.
Sin embargo, Electronic Arts / Maxis recientemente ha comenzado a hacer la vida un poco más difícil, ya que algunos contenedores de RCOL no se ajustan exactamente a la comprensión original de cómo debería funcionar el contenedor. Tenga en cuenta esto al leer el código o escribir el suyo.
Primero, debe tener experiencia y ya saber cómo editar los archivos del paquete SIMS, utilizando el software S3PE. S3PE básicamente funciona como una interfaz gráfica para S3PI, que los usuarios comunes pueden usar. Por lo tanto, es seguro decir que S3PI es capaz de hacer todo lo que S3PE puede hacer, y aún más.
Nota
El S3PE también está disponible para descargar en este repositorio. Tanto su archivo ejecutable como su código fuente C# y la solución Visual Studio.
Sabiendo esto, para implementar S3PI en su programa, debe codificar como si su programa estuviera usando S3PE para realizar la acción.
Supongamos que desea eliminar un cierto recurso de un archivo de paquete. Si estuviera usando S3PE, primero abriría ese archivo de paquete, buscaría el recurso para eliminar. Luego presionaría DEL Key para eliminar ese archivo y luego guardar. Una vez que se guarda el archivo del paquete, lo cerraría.
Si lo hace usando S3PE, su programa debe realizar los mismos pasos si usa S3PI para realizar esta misma acción. Consulte el código de muestra a continuación, realizando la acción de eliminar los recursos "0x00b2d882-0x00000000-0x0a12300000ff0000" de un archivo de paquete abierto, como ejemplo ...
using s3pi ;
using s3pi . Interfaces ;
using s3pi . Package ;
//Open the package
IPackage package = Package . OpenPackage ( 0 , "C:/Folder/someFile.package" , true ) ;
//Search the resource "0x00B2D882-0x00000000-0x0A12300000FF0000" inside the package
foreach ( IResourceIndexEntry item in package . GetResourceList )
{
//Get current entrie resource TGI
string typeHex = GetLongConvertedToHexStr ( item . ResourceType , 8 ) ;
string groupHex = GetLongConvertedToHexStr ( item . ResourceGroup , 8 ) ;
string instanceHex = GetLongConvertedToHexStr ( item . Instance , 16 ) ;
//If is the target resource, delete it
if ( typeHex == "0x00B2D882" && groupHex == "0x00000000" && instanceHex == "0x0A12300000FF0000" )
package . DeleteResource ( item ) ;
}
//Save the changes
package . SavePackage ( ) ;
//Close the package
Package . ClosePackage ( 0 , package ) ; Importante
Es muy importante que siempre cierre un archivo de paquete abierto después de que haya terminado de trabajar en él.
Nota
The Dream Launcher es un lanzador para los Sims 3 creados por "Marcos4503". El lanzador de sueños utiliza S3PI para implementar diversas características, como fusionar paquetes, limpieza de ahorros y otras funciones. Puede seguir este enlace para consultar el repositorio de Dream Launcher y echar un vistazo al código fuente para obtener más ejemplos de uso de S3PI. El lanzador de sueños se creó usando C# como lenguaje de programación.
using s3pi ;
using s3pi . Interfaces ;
using s3pi . Package ;
//Creates a new Package that will receive the resources from 2 other Packages
IPackage finalPackage = Package . NewPackage ( 0 ) ;
//Open the Package 1 and copy all resources to the final package
IPackage package1 = Package . OpenPackage ( 0 , "C:/Folder/package1.package" , false ) ;
foreach ( IResourceIndexEntry item in package1 . GetResourceList )
finalPackage . AddResource ( item , ( package1 as APackage ) . GetResource ( item ) , true ) ;
Package . ClosePackage ( 0 , package1 ) ;
//Open the Package 2 and copy all resources to the final package
IPackage package2 = Package . OpenPackage ( 0 , "C:/Folder/package2.package" , false ) ;
foreach ( IResourceIndexEntry item in package2 . GetResourceList )
finalPackage . AddResource ( item , ( package2 as APackage ) . GetResource ( item ) , true ) ;
Package . ClosePackage ( 0 , package2 ) ;
//Enable compression for all viable resources of final merged package (the same way S3PE does)
foreach ( IResourceIndexEntry item in finalPackage . GetResourceList )
item . Compressed = ( ushort ) ( ( item . Filesize != item . Memsize ) ? 0xFFFF : 0x0000 ) ;
//Saves the final Package, result of the merge
finalPackage . SaveAs ( "C:/Folder/finalFile.package" ) ;
Package . ClosePackage ( 0 , finalPackage ) ; using s3pi ;
using s3pi . Interfaces ;
using s3pi . Package ;
//Open a .nhd save file
IPackage nhdSaveFile = Package . OpenPackage ( 0 , "C:/Folder/saveFile.nhd" , false ) ;
//Search inside the package, by the first thumbnail of type "SNAP" (or hex type "0x6B6D837E")
foreach ( IResourceIndexEntry item in nhdSaveFile . GetResourceList )
if ( GetLongConvertedToHexStr ( item . ResourceType , 8 ) == "0x6B6D837E" )
{
//Get the base stream for this resource
Stream aPackageStream = ( nhdSaveFile as APackage ) . GetResource ( item ) ;
//Get the base resource using the "ImageResource" s3pi wrapper***
IResource baseResource = ( IResource ) ( new ImageResource . ImageResource ( 0 , aPackageStream ) ) ;
//Get the bitmap from base resource stream
BitmapImage bitmapImage = new BitmapImage ( ) ;
bitmapImage . BeginInit ( ) ;
bitmapImage . StreamSource = baseResource . Stream ;
bitmapImage . CacheOption = BitmapCacheOption . OnLoad ;
bitmapImage . EndInit ( ) ;
bitmapImage . Freeze ( ) ;
//... continue ...//
//Cancel the search
break ;
}
//Close the save file
Package . ClosePackage ( 0 , nhdSaveFile ) ; *** Tenga en cuenta que aquí, podríamos usar la clase WrapperDealer para que S3PI nos proporcione el contenedor correcto para el recurso con el que estamos trabajando automáticamente. Si usáramos WrapperDealer allí, S3PI nos traería automáticamente el envoltorio ImageResource , sin embargo, se sabe que WrapperDealer es incompatible con algunos marcos .NET, como WPF en sí, causando choques. Por esta razón, siempre se recomienda usar el envoltorio directamente, cuando se trabaja con un recurso dentro del archivo del paquete. Si elegimos usar la clase WrapperDealer para obtener la imagen, el fragmento de código se vería así ...
//...
//Get the resource using WrapperDealer
IResource resource = WrapperDealer . GetResource ( 0 , nhdSaveFile , item , true ) ;
//Get the bitmap from base resource stream
BitmapImage bitmapImage = new BitmapImage ( ) ;
bitmapImage . BeginInit ( ) ;
bitmapImage . StreamSource = resource . Stream ;
bitmapImage . CacheOption = BitmapCacheOption . OnLoad ;
bitmapImage . EndInit ( ) ;
bitmapImage . Freeze ( ) ;
//... using s3pi ;
using s3pi . Interfaces ;
using s3pi . Package ;
//Open a package that contains a CASP resource
IPackage openedPackage = Package . OpenPackage ( 0 , "C:/Folder/clothes.package" , true ) ;
//Search the first CASP (or hex type 0x034AEECB) resource inside the package
foreach ( IResourceIndexEntry item in openedPackage . GetResourceList )
if ( GetLongConvertedToHexStr ( item . ResourceType , 8 ) == "0x034AEECB" )
{
//Get the CASP stream
Stream caspStream = WrapperDealer . GetResource ( 1 , openedPackage , item , true ) . Stream ;
//Get the CASP resource
CASPartResource . CASPartResource sourceCASpart = new CASPartResource . CASPartResource ( 1 , caspStream ) ;
//Allow this CASP for Random Sims
sourceCaspart . ClothingCategory |= CASPartResource . ClothingCategoryFlags . ValidForRandom ;
//Disallow this CASP for Random Sims
sourceCaspart . ClothingCategory &= ~ CASPartResource . ClothingCategoryFlags . ValidForRandom ;
//Delete the old CASP resource
openedPackage . DeleteResource ( item ) ;
//Add the new modified resource
openedPackage . AddResource ( ( ( IResourceKey ) item ) , ( ( AResource ) sourceCaspart ) . Stream , true ) ;
//Release streams
caspStream . Dispose ( ) ;
caspStream . Close ( ) ;
( ( AResource ) sourceCaspart ) . Stream . Dispose ( ) ;
( ( AResource ) sourceCaspart ) . Stream . Close ( ) ;
}
//Save the package and close it
openedPackage . SavePackage ( ) ;
Package . ClosePackage ( 0 , openedPackage ) ; Nota
Aquí usamos WrapperDealer para acceder al recurso CASP, pero también podríamos usar Wrapper CASPartResource directamente para acceder al recurso CASP.
Como probablemente ya comprenda, los archivos del paquete SIMS son como un "archivo zip", que contiene varios otros archivos dentro de ellos. Cada archivo/recurso dentro de un archivo de paquete tiene un TGI asociado con él.
El TGI es básicamente el tipo, grupo e instancia. El tipo y el grupo son hexadecimales de 8 dígitos, mientras que la instancia es un hexadecimal de 16 dígitos. Para evitar conflictos entre los recursos cuando el juego lo carga, cada recurso presente en todos los paquetes cargados por el juego debe tener una combinación TGI única.
Cuando abre un archivo de paquete con S3PE, puede ver fácilmente el tipo, grupo e instancia de cada recurso presente en el paquete abierto. Ahora que sabe esto, tenga en cuenta que, al editar los archivos de paquete SIMS, siempre debe asegurarse de que los recursos que inserta en los archivos de paquete siempre deben tener un TGI único.
Si tiene más preguntas sobre esto, puede leer este artículo, que habla y explica muy bien qué son los conflictos de mod, cómo ocurren, cómo resolverlos, etc.
Si ha leído hasta aquí, debe tener una comprensión decente de lo que es S3PI y cómo usarlo. Si desea acceder al antiguo repositorio oficial S3PI, puede usar este enlace. Recordando que todo el crédito por crear la biblioteca S3PI va a Peter L Jones.
Repositorio creado con Marcos Tomaz