Atualmente, é muito difícil encontrar informações sólidas e ajuda real em relação ao S3PI, ainda mais se você estiver tentando criar um programa usando o S3PI como uma biblioteca para interagir com os arquivos do pacote do SIMS. Além disso, a biblioteca S3PI não está no GitHub e não possui um repositório aqui.
Por esses motivos, decidi criar esse repositório para armazenar a biblioteca S3PI na íntegra, com exemplos de código e dicas sobre como usá -la corretamente. Além disso, compilei aqui todas as informações úteis que encontrei na Internet relacionadas ao S3PI!
Se você deseja contribuir com mais informações, crie uma solicitação de tração ou relate -a na guia "Problemas". Farei o meu melhor para manter este repositório com o máximo de informações e exemplos que puder, mas se o autor do S3PI solicitar, levarei esse repositório offline.
Importante
Lembrando que todos os créditos para a criação da biblioteca S3PI vão para o incrível "Peter L Jones"!
A interface do pacote "Sims 3" fornece uma biblioteca principal de código portátil que "entende" pacotes de jogos Sims3. Observe que (com alguns pequenos ajustes), o código da biblioteca principal também entende outros formatos de pacote de jogos (por exemplo, simcity online, sims4).
Juntamente com a biblioteca principal estão vários "invólucros" que fornecem a parte principal do projeto. Eles lidam com a desserialização e a serialização dos dados dentro do pacote (ou em qualquer outra fonte).
Outras ferramentas podem usar esta biblioteca e invólucros para manipular o conteúdo de dados dos arquivos de pacotes dos jogos do SIMS.
Observe que o desenvolvimento desta biblioteca e dos invólucros fornecidos aqui já terminou.
O "S3PI" é um acrônimo para "interface do pacote Sims3 ™". Ele fornece suporte para acessar os dados dentro de arquivos individuais de "pacote" usados pelo jogo Electronic Arts SIMS3 ™. Um "pacote" é um arquivo de disco com uma extensão de arquivo geralmente de ".package" (mas outras extensões são usadas). No entanto, o principal recurso de identificação usado pelo S3PI é o cookie mágico de quatro bytes no início do arquivo, que deve ser "DBPF". Além disso, o número da versão do formato do arquivo deve ser 2 para o Sims 3 ™ (ou 3 para o Sim City 5 ™, que mal suportado).
Observe que os pacotes "protegidos" (com um cookie mágico de "DBPP") não são suportados. Observe que os pacotes "temporários" (com um cookie mágico de "DBBF") não são suportados no momento.
O S3PI é um conjunto de conjuntos .NET (documentados abaixo e disponível aqui) que implementam as descrições do Wiki Sims 3 (com essas páginas disponíveis alternativamente aqui como wiki-mirror). Observe que sempre vale a pena verificar se você não tiver certeza de algo, seja sobre como algo deve funcionar ou se você acha que encontrou um problema no S3PI, o que permanece bem possível. Nem o wiki nem a biblioteca estão sempre certos - de fato, pode ser que ambos estejam errados de maneiras diferentes.
A biblioteca S3PI vem com um arquivo de ajuda compilado (.chm) que descreve muito do que você precisa saber. Você também pode acessar uma versão disso, aqui. Esta página tenta dar uma visão geral rápida, pois a biblioteca é bastante extensa e pode ser complicado descobrir o que você precisa saber.
Esta página é dividida em três seções restantes.
Depois de entender como usar um invólucro para acessar dados em um pacote, consulte a lista Wiki do SIMS3 dos tipos de arquivos para ver quais são suportados e como obter o suporte (se não fizer parte da distribuição S3PI).
Dica
Se você tiver perguntas não respondidas, não hesite em postar aqui no fórum/discussões. Será um prazer ajudar!
A biblioteca é um conjunto de DLLs de montagem .NET. Se é provável que você trabalhe em mais de um projeto usando a biblioteca, aconselho fortemente colocá -los em uma pasta separada do seu projeto e espaços de trabalho de solução - mas perto na estrutura da sua pasta. Dessa forma, é fácil substituí -los todos sem precisar atualizar cada projeto.
Para usar a biblioteca de um novo projeto, primeiro você precisa saber qual partes da biblioteca você usará. Eu deliberadamente mantive as peças dependentes separadas, para que seu projeto só precise fazer referência às DLLs necessárias, mantendo seu projeto em tamanho baixo. A desvantagem é que há muitas DLLs!
A primeira coisa a notar é que muitos deles são "invólucros" - qualquer coisa com um nome como SomethingResource.DLL . Eles contêm o código para entender o conteúdo de um ou mais recursos em um arquivo de pacote do Sims 3.
Primeiro, vamos dar uma olhada em cada uma das assembléias restantes. Depois disso, fornecerei um esboço de como iniciar um novo projeto. Terminarei com algumas reflexões sobre como organizar suas práticas de trabalho.
Observação
Você deve concordar com a licença GPLV3 antes de distribuir seu código. Observe que, enquanto você está vinculando a uma biblioteca GPLV3, você está essencialmente reutilizando-a e deve distribuir seu código em termos equivalentes. Você pode encontrar mais detalhes no site da Free Software Foundation.
Quando incluí -lo: sempre - é necessário por várias outras partes da biblioteca.
Resumo: Contém várias classes que não se relacionam diretamente com "The Sims 3" e não têm referências a nenhum dos tipos de s3pi.Interfaces . Eles poderiam ser utilizados para projetos que não usam o restante da biblioteca S3PI (portanto, mantendo -a separada).
Leitura adicional: Ao fazer referência a esta assembléia, você recebe o seguinte ...
System.Collections.Generic.AHandlerList<T> - Extensão abstrata da List<T> Fornecendo feedback nas atualizações da lista por meio de um EventHandler fornecido.System.ArgumentLengthException - representa um erro no comprimento de um argumento para um método.System.Extensions - Métodos de extensão úteis não fornecidos pelo LINQ (e sem execução diferida). (O nome da classe é duvidoso e pode mudar ...)System.Security.Cryptography.FNV32 - FNV32 Rotina de hashSystem.Security.Cryptography.FNV64 - FNV64 Rotina de hashSystem.Text.SevenBitString -Leia e escreva uma sequência prefeitada de comprimento codificada de sete bits em uma determinada Encoding de ou para um Stream .System.Security.Cryptography.Sims3PackCRC - Calcule o CRC de um pedaço de dados armazenado em um arquivo SIMS3PACK. (OK, sem dúvida isso não tem razão estar aqui, mas em termos de dependências de código, faz sentido!) Quando incluí -lo: sempre.
Resumo: Originalmente, destinado a permitir que várias configurações internas à biblioteca sejam alteradas substituindo a DLL. Isso nunca aconteceu.
Leitura adicional: nada.
Quando incluí -lo: sempre. Não é apenas exigido pela própria biblioteca, mas define a API pública.
Resumo: Fornece várias interfaces, classes abstratas e classes auxiliares usadas em toda a biblioteca e invólucros, que definem os métodos públicos fornecidos pelas várias classes da biblioteca.
Leitura adicional:
s3pi.Interfaces Documentação de espaço para names. Observe que o espaço para nome é "poluído" pelas classes do s3pi.GenericRCOL . Os puristas também podem considerar algumas das classes auxiliares "poluição" ...
Quando incluí -lo: ao trabalhar com os arquivos do pacote Sims 3.
Resumo: fornece a implementação concreta das classes e interfaces abstratas definidas em s3pi.Interfaces .
Leitura adicional: nada.
Quando incluí -lo: ao trabalhar com invólucros de recursos.
Resumo: Se você estiver criando novos recursos ou recursos de leitura a partir de um pacote, este é o mecanismo recomendado. No entanto, existem alternativas.
Leitura adicional:
s3pi.WrapperDealer.WrapperDealer - Responsável por associar ResourceType no IResourceIndexEntry a uma classe específica (um "wrapper") que o entende ou o invólucro padrão. O s3pi.DefaultResource e s3pi.GenericRCOLResource fornecem o básico para entender como usar um recurso depois de ter uma referência a ele.
Quando incluí -lo: se você deseja nomes de arquivos padrão da comunidade.
Resumo: No início do Sims 3, a comunidade de modding concordou em um formato definido sobre como um recurso embalado deve ser nomeado quando fora de um arquivo de pacote. Este conjunto fornece a implementação para a biblioteca S3PI.
Leitura adicional: s3pi.Extensions namespace. Esta área da biblioteca ainda precisa documentar corretamente.
Quando incluí -lo: quando você deseja copyableMessageBox (ou edifícioException).
Resumo: Este conjunto fornece uma maneira de exibir mensagens que permitem ao usuário copiar o conteúdo facilmente. No futuro, outros controles gerais podem aparecer aqui.
Leitura adicional: Classe CopyableMessageBox , CopyableMessageBoxButtons Enumeração e Enumeração CopyableMessageBoxIcon .
Quando incluí -lo: quando você deseja um dos controles personalizados.
Resumo: Este conjunto fornece controles personalizados relacionados aos tipos de dados no S3PI.
Leitura adicional: Classe ResourceTypeCombo , classe TGIBlockCombo e classe TGIBlockListEditor . Esta área da biblioteca ainda precisa documentar corretamente.
Quando incluí -lo: quando você usa imagens DDS e deseja uma maneira de exibi -las em um aplicativo Winforms.
Resumo: Esta assembly fornece um suporte de controle personalizado e suporte de recursos DDS.
Leitura adicional: DDSPanel Class e DDSPanel.MaskChannel Enumeração.
Quando incluí -lo: pode ser útil ao escrever um ajudante para o S3PE.
Resumo: fornece suporte para mapear um recurso para um ou mais programas que possam estar interessados nesse tipo de recurso.
Leitura adicional: s3pi.Helpers Namespace. Esta área da biblioteca ainda precisa documentar corretamente.
Configure as referências necessárias com base no System.Custom de seção anterior.custom, s3pi.Settings , s3pi.Interfaces e quaisquer outros. Além disso, você precisará considerar se deseja fazer referência a assemblies específicos do wrapper. Na maioria dos casos, essa será a abordagem apropriada. Seus assemblies referenciados, por padrão, serão copiados para a pasta de saída do projeto, juntamente com o seu programa.
Observe que existem certos componentes adicionais utilizados, como arquivos de configuração, que você também precisará providenciar para a compilação do seu projeto para copiar (se mais recente) para a pasta de saída.
Você pode querer olhar para as soluções S3OC e S3PE Visual Studio para ver como eu fiz isso.
O S3PI fornece várias classes C# para ajudar os programas que desejam acessar os arquivos do pacote Sims 3 e os recursos armazenados dentro deles. A "Biblioteca Core" apenas entende o próprio contêiner de pacotes - não entende o conteúdo dos recursos. Isso é delegado a "invólucros". Os invólucros estão associados a recursos declarando a lista de ResourceTypes que suportam. A biblioteca principal retorna uma instância da classe de recursos apropriados para a biblioteca "cliente".
Portanto, os invólucros têm dois objetivos principais: fornecer um "entendimento" do conteúdo de um ou mais tipos de recursos e informar a biblioteca principal quais tipos de recursos eles entendem. Um invólucro pode fornecer um ou mais manipuladores de recursos, pois consideram o ajuste, mas os autores são incentivados a manter diferentes preocupações separadas em diferentes embalagens.
A Biblioteca Core identifica os embalagens pesquisando os conjuntos na pasta da biblioteca S3PI para aqueles com a interface apropriada.
O WrapperDealer possui uma interface que permite que os aplicativos do cliente possam ativar e desativar combinações específicas de ResourceType e wrapper.
Agora incluí DefaultResource na Documentação da Biblioteca S3PI.
O exemplo mais simples é o dado no DefaultResource na distribuição de origem. "Não faz nada" além do que é essencial para qualquer invólucro.
Ele define duas classes:
public class DefaultResource : AResource { }
public class DefaultResourceHandler : AResourceHandler { } Uma montagem que contém um invólucro deve conter uma classe implementando AResourceHandler . Esta classe fornece uma pesquisa IDictionary<Type, List<string>> entre uma classe que implementa AResource e uma lista de strings que contêm valores ResourceType . (As strings usadas são os valores do lançamento do TypedValue ResourceType em uma string, ou seja, uma string hexadecimal.)
DefaultResource usa "*" para informar WrapperDealer que está feliz em levar tudo. Não use isso em seus invólucros!
DefaultResource , então.
É fortemente recomendado que você tenha const Int32 recommendedApiVersion = 1; no topo da sua classe para compatibilidade futura. Isso permite que você "versão" da API do seu wrapper, se precisar. Provavelmente não é tão útil na prática, no entanto.
Você deve ter a propriedade AApiVersionedFields RecommendedApiVersion .
O construtor para DefaultResource demonstra um ponto importante - um novo recurso é criado sem saber nada . Pode verificar se é novo verificando que o fluxo passado para o construtor é nulo. Em seguida, ele deve criar um MemoryStream e preenchê -lo com o conteúdo mínimo de dados válidos para o recurso.
É isso! Não há mais nada que você deve fazer. Claro, você ainda não forneceu a ninguém um motivo para usar seu invólucro ...
Observação
Depois de um pouco de pensamento, ImageResource e TextResource são considerados depreciados. No entanto, eles permanecerão na biblioteca no futuro próximo. Apesar do que está escrito abaixo, não considero mais uma boa ideia ter um invólucro para um recurso que é apenas um fluxo de bytes.
A abordagem adotada para os recursos do DDS é considerada mais correta. Um corolory é declarado diretamente abaixo: o design aqui foi influenciado pelo S3PE, em vez de implementar qualquer coisa sobre a estrutura dos dados em si, que é o objetivo de um invólucro. Isso deveria ter sido tratado de maneira semelhante aos recursos do DDS.
Um outro corolory foi a adição e, em seguida, a remoção do invólucro de recursos _VID durante um ciclo de controle de qualidade, quando se descobriu que o conteúdo era puramente a saída de um codec audiovisual de artes eletrônicas personalizadas, em vez de ter qualquer conteúdo decifrável.
Em conclusão: "valor" deve ser apenas uma string. Normalmente, o formatador incorporado constrói um apropriado a partir de suas propriedades públicas.
Um exemplo um pouco mais complexo é o ImageResource. Ele permanece no modelo de duas classes:
public class ImageResource : AResource { }
public class ImageResourceHandler : AResourceHandler { }Este wrapper lida com imagens - muitos tipos de recursos diferentes são simplesmente arquivos PNG89 armazenados.
O construtor estático do ImageResourceHandler lê uma lista de todos os tipos de recursos de imagem conhecidos (de um arquivo na pasta onde a montagem está localizada). Isso é usado para preencher a lista da IDictionary<Type, List<string>> Lista no construtor da instância, que é então usado pelo WrapperDealer . Isso significa que é fácil adicionar novos tipos de recursos à lista que este wrapper suporta - basta editar o arquivo de texto e adicioná -los, sem necessidade de recompilar. (É um padrão tão bom, eu deveria ter facilitado a reutilização ...)
A classe ImageResource permanece bastante simples. Seu construtor garante que haja uma imagem PNG89 válida se passada um fluxo nulo. E fornece uma única propriedade chamada "Valor" que retorna um System.Drawing.Image criado a partir dos dados PNG89. Não suporta salvar imagens de volta a um recurso existente.
Vale a pena mencionar a propriedade Value - o front end de demonstração S3PI (agora conhecido como S3PE) verifica se um recurso tem uma propriedade Value e, se sim, se possui um tipo de imagem ou dados da string. Ele sabe como exibir esses dois (e os dois sozinhos, atualmente). Retornar o apropriado pode ser útil na depuração.
Você notará que a posição do fluxo é definida como zero antes do uso - sempre assuma que está em um estado desconhecido.
O wrapper TextResource é muito semelhante - os recursos de texto são definidos em um arquivo; Possui uma propriedade "Value" retornando o recurso como um valor de string. Além disso, possui algumas propriedades específicas de texto, incluindo o acesso aos dados como XML. (Seria melhor design ter o invólucro XML como uma extensão do invólucro de texto e lidar apenas com arquivos XML conhecidos nele ...)
Este invólucro lida com um único tipo de recurso - o mapa do nome do pacote. Ele fornece uma interface IDictionary<ulong, string> , permitindo que o mapa seja lido e atualizado. É um exemplo muito simples de como lidar com atualizações.
Aqui está como funciona. Este é um exemplo simples, mas o padrão pode ser estendido a necessidades mais complexas.
O trabalho é realizado em vários lugares:
A propriedade Stream verifica se o recurso foi sutil (ou seja, alterado). Nesse caso, ele descarta o fluxo atual e chama UnParse() .
O construtor da instância verifica um fluxo nulo e chama UnParse() para construir o recurso mínimo válido.
O método Parse(Stream s) lê os dados na estrutura de dados usada para manipulá -los - aqui um Dictionary<ulong, string> . Como essa é uma estrutura repetida de entradas de comprimento variadas que permitem que os dados sejam inseridos, não é eficiente usar os dados no fluxo.
O método UnParse() exporta a estrutura de dados para um novo fluxo, criando novos objetos quando necessário.
Como mencionado acima, a propriedade Stream precisa saber se o recurso foi sutil. A implementação do IDictionary<ulong, string> Interface cuida disso, chamando OnResourceChanged(this, EventArgs.Empty) para operações de atualização. Isso é fornecido no AResource e define o recurso para sujo, além de chamar os manipuladores ResourceChanged de qualquer coisa que ouça o evento.
O CatalogResource realmente leva as idéias no NameMapresource ainda mais. Possui uma classe abstrata para um conjunto de recursos relacionados. Tentei manter um padrão consistente de codificação para ajudar a entender o que está acontecendo. Deixo como um exercício ao leitor trabalhar através da implementação para ver como todas as classes estão interagindo. Espero que isso faça sentido! (Se não, eu serei perplexo quando um bug surgir !!)
Isso tem o benefício de ser recente e, embora relativamente simples, tem alguns bits interessantes. É também um dos invólucros que eu costuma me consultar ao escrever um novo.
Um recurso RCOL é um recurso normal, conforme descrito acima - com a diferença fundamental de que é um contêiner para outros "recursos", conhecidos como blocos RCOL. Cada bloco possui um formato identificado por um código de quatro caracteres ("quatrocc" ou tag); Os blocos também têm tipos de recursos. O recurso RCOL (no pacote) tem o mesmo tipo que o primeiro bloco RCOL em (no recurso) e o recurso recebeu o nome deste primeiro bloco RCOL. Alguns recursos RCOL contêm apenas um único bloco RCOL; Outros contêm vários blocos RCOL.
O suporte básico é fornecido pelo s3pi.GenericRCOLResource . Além de ler os blocos e os blocos de escrita para o pacote, o invólucro de recursos possui métodos adicionais para suportar o formato RCOL e há um registro de manipuladores de blocos RCOL.
(Observe que o termo "pedaço" é livremente usado para se referir a um bloco RCOL às vezes ...)
Há uma classe abstrata, ARCOLBlock , que define os fundamentos. Existe uma implementação padrão, DefaultRCOL , para quando nenhum outro manipulador de blocos RCOL correspondente é definido no registro, que fornece suporte mínimo.
Além de estender ARCOLBlock em vez de AResource , a tarefa de escrever um manipulador de blocos RCOL é muito semelhante a escrever um invólucro de recursos.
No entanto, as artes eletrônicas / maxis começaram recentemente a tornar a vida um pouco mais difícil, pois alguns contêineres de RCOL único não estão exatamente em conformidade com o entendimento original de como o contêiner deve funcionar. Esteja ciente disso ao ler o código ou escrever o seu próprio.
Primeiro, você precisa ter experiência e já sabe como editar os arquivos do pacote Sims, usando o software S3PE. O S3PE funciona basicamente como uma interface gráfica para S3PI, que os usuários comuns podem usar. Portanto, é seguro dizer que o S3PI é capaz de fazer tudo o que o S3PE pode fazer e ainda mais.
Observação
O S3PE também está disponível para download neste repositório. Seu arquivo executável e seu código -fonte C# e solução do Visual Studio.
Sabendo disso, para implementar o S3PI em seu programa, você precisa codificar como se o seu programa estivesse usando o S3PE para executar a ação.
Digamos que você queira excluir um determinado recurso de um arquivo de pacote. Se você estivesse usando o S3PE, primeiro abriria esse arquivo de pacote, pesquise o recurso para excluir. Em seguida, você pressionaria a tecla DEL para excluir esse arquivo e salvar. Depois que o arquivo de embalagem for salvo, você o fechará.
Se você fizer isso usando o S3PE, seu programa deve executar as mesmas etapas se você usar o S3PI para executar a mesma ação. Consulte o código de amostra abaixo, executando a ação de excluir o recurso "0x00B2D882-0X00000000-0X0A12300000FF0000" de um arquivo de pacote aberto, como exemplo ...
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
É muito importante que você sempre feche um arquivo de pacote aberto depois de terminar de trabalhar nele.
Observação
O Dream Launcher é um lançador do The Sims 3 criado por "Marcos4503". O lançador dos sonhos faz uso do S3PI para implementar vários recursos, como fusão de pacotes, limpeza de defesas e outras funções. Você pode seguir este link para conferir o repositório do Sonho Launcher e dar uma olhada no código -fonte para obter mais exemplos de uso do S3PI. O lançador dos sonhos foi criado usando C# como linguagem de programação.
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 ) ; *** Observe que aqui poderíamos usar a classe WrapperDealer para que o S3PI nos fornecesse o wrapper correto para o recurso com o qual estamos trabalhando automaticamente. Se usássemos WrapperDealer , o S3PI nos traria automaticamente o invólucro ImageResource e WrapperDealer é conhecido por ser incompatível com algumas estruturas .NET, como o próprio WPF, causando falhas. Por esse motivo, é sempre recomendável usar o invólucro diretamente, ao trabalhar com um recurso dentro do arquivo de pacote. Se optarmos por usar a classe WrapperDealer para obter a imagem, o snippet de código ficaria assim ...
//...
//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 ) ; Observação
Aqui usamos WrapperDealer para acessar o recurso CASP, mas também podemos usar o Wrapper CASPartResource diretamente para acessar o recurso CASP.
Como você provavelmente já entende, os arquivos do pacote Sims são como um "arquivo zip", contendo vários outros arquivos dentro deles. Cada arquivo/recurso dentro de um arquivo de pacote possui um TGI associado a ele.
O TGI é basicamente o tipo, grupo e instância. O tipo e o grupo são hexadecimais de 8 dígitos, enquanto a instância é um hexadecimal de 16 dígitos. Para evitar conflitos entre os recursos quando carregados pelo jogo, todos os recursos presentes em todos os pacotes carregados pelo jogo devem ter uma combinação exclusiva do TGI.
Ao abrir um arquivo de pacote com o S3PE, você pode ver facilmente o tipo, o grupo e a instância de cada recurso presente no pacote aberto. Agora que você sabe disso, lembre -se de que, ao editar os arquivos do pacote do Sims, você deve sempre garantir que os recursos que você insira nos arquivos de pacotes devem sempre ter um TGI exclusivo.
Se você tiver mais alguma dúvida sobre isso, pode ler este artigo, que fala e explica muito bem o que os conflitos de mod, como eles ocorrem, como resolvê -los etc.
Se você leu até aqui, deve ter um entendimento decente do que é o S3PI e como usá -lo. Se você deseja acessar o antigo repositório oficial S3PI, poderá usar este link. Lembrando que todo o crédito por criar a biblioteca S3PI vai para Peter L Jones.
Repositório criado por Marcos Tomaz