|Search this Thread|
|28th Feb 2012, 05:36 PM||Using JAZZ and C# to make a non-default accessory for an object #1|
How to make a non-default prop replacement for ingame objects
You have followed/read these tutorials:
Tutorial:Sims 3 Object Moddingwiki
Background: I was working with the Merrye Makers and their medieval uploads and one of those uploads was a medieval floortorch. It looked ok, until the sim came to light the torch. Then my medieval sim used a butane gas lighter....
Of course, it is easiest to make a default replacement for the gas lighter and drop that in your downloads folder, but that will affect all fireplaces. What I wanted was an object mod that would use my replacement in the object and not in the EA fireplaces. After an enormous amount of help from lots of people I finally succeeded. This tutorial is how I made the object and what I did. I am not a coder or a script modder, so I will not be able to explain the code aspects that well.
First, I broke down my project into steps or stages.
The below image might help to show how the objects and the steps relate to each other.
Step 1 Cloning an object
I am not going to cover how to clone an object in this tutorial as there are already many tutorials that do this.
Step 2 The Script
As already said, I am not a coder, and this script took a bit of time but it has been looked over by some better coders and there is nothing really silly in here The key bit is to get the state machine to run so you can edit the JAZZ and replace it. This was the first script I ever made in C# and I learned a fair bit while I was going along.
** A state machine is a certain thingy that eggheads use to model stuff. Such a whatchamacallit is defined by states, transitions and actions. Now the important thing about a state machine is that it can only have one state at a given time and that transitions to a different state are only possible along the pre-defined paths. State machines defined by JAZZ scripts for TS3 have public states (usually at least Enter and Exit) that can be "requested" from the script side (the part written in C#) and transition states. The point is that the state machine must make its way to the requested state using transition states and in these transition states animations get played. JAZZ scripts allow a certain degree of flow control, like looping animations or playing different animations based on variables (like if-else in C#). It's also where props for animations, like the pencil for the homework animation, come into play. These props don't exist on the script side (again the part written in C#).
For example: C# uses the idea of inheritance; so if a class is the child of another class then it will have all the characteristics of that class, but it can specialize in some aspects. To try and explain I will use the fireplace as the example. There's one base class Fireplace and it has four direct children: FireplaceCheap, FireplaceDecent, FireplaceUltra and FirePit. Classes have relationships to other classes. You can formulate these in first person sentences that begin with "I am a", "I have a" and "I am associated with". FireplaceCheap for example could say "I am a Fireplace. I have a Chimney. I have a Footprint. I am associated with Interaction." (Interaction is the class that lets Sims interact with objects.) The Fireplace itself could say "I am a LightGameObject." and LightGameObject could say "I am a GameObject." (GameObject is the base class for all visible objects in the game.)
The idea of inheritance or "I am a" (usually called IS_A) relationship is difficult to understand at first. The basic idea is to build taxonomies. Put the stuff that is common to a set of classes into one base class and then let other classes inherit from it and only put into these classes what is special. Like the Fireplace class with its four children. The Fireplace class is just an abstract concept, but no actual Fireplace object will ever exist. Just like fish for example. But fish totally exist you say? Really? Look at fish. You'll see sharks, catfish, sardines, leefishes... There's no fish which (or who) is really just a fish. Every fish you can actually meet is a special fish. Very special in some cases.
What EA did, for each group of fireplaces they created "mimics" that are children to one of the specialised Fireplace classes. A mimic doesn't have any special behavior. It just exists so it can have it's own XML tuning and appropriate footprint. Each EA fireplace uses one of these mimics and you will find the very same approach for many if not most EA objects. The EA namespace I use in this mod is the Sims3.Gameplay.Objects.Fireplaces.Mimics.
The opening lines of my script shows this approach: we can see that I have attached .LeeFishMod to the end of the EA Namespace - inside the EA namespace there is a class FireplaceCheap. The line public class MedievalFireplace : Fireplace Cheap can be read as "copy all the characteristics of the FireplaceCheap and apply those to my fireplace".
Set the namespace and the class for your object
For example, all fireplaces have a chimney and a modelname, so I don't have to define those, but they have unique footprints and tunings, so that is this method:
This will mean that the footprint used by the object will be the 2x1 and the tuning will be the default tuning. A death trap. I fix that later.
Then we write the code for the class that will call the existing fireplace interaction and give me the entry point to change the JAZZ. Look at what it is saying; that the private(only this script) sealed (no, really, only this script) class LightMyFire will be using a Sim, and a Medieval Fireplace and it will be using most of the interactions defined in FireplaceCheap.:
Private sealed class LightMyFire
Inside the class we tell the game what interaction to use - who(sim), with(medieval fireplace), does what (Fireplace.Interaction) and the methods used are in the list below: I took a picture of the layout in notepad to try and illustrate how it works. If you start with a curly bracket then you have to close it.
So, looking at the picture, we see that the WHOLE script is contained inside the bracket that begins at
and that there are "subsections" inside leefishmod - contained within their own pairs of curly brackets - like this - each indented list is a child (or children) of the line above it, so "protected override bool Run" is the grandchild of "public class MedievalFireplace : FireplaceCheap"
Here we are telling the game that we have a new Definition, we don't specify what is inside it, just that there is one. The next line is a good example of using something called the get;set method in C#. It accepts two "arguments" - the get and the set. It is telling the code that when it encounters the public game object IKTarget to go and get my private object, mIKTarget, and call that the target from now on. So now whenever the code in this script sees Target, it sees my private target, in this class. It will only affect this object. The interaction is the key part of the code - without the interaction there is nothing to run.
The Event that will be called as a result of our interaction
This bit is telling the game that when the StartFireCallBack is triggered then it will look in the code and find the target referred to in the class directly owning this - in this case that is public class MedievalFireplace : FireplaceCheap. This is actually very key to understanding how this is all working - whenever we see base.Something then it is a direction to the code to look in the class above. Think of classes as containers and the curly brackets as defining the limits of each container.
The things that will happen when the Run command starts
A bool is a true or false statement. In the code we see the ! symbol. This is shorthand for NOT - so our code reads "if the sim cannot reach the fireplace return false" and if that is true BUT "if the fire is on - return false" - if those are not false then go ahead and run this code. In the last block of code we see the use of the word base - this means that our class LightMyFire is referring to the class Medieval Fireplace and will cause the sim to go to the slot in front of the fireplace (standard entry as used for fireplace cheap - otherwise the sim would just start doing the fireplace lighting anims as soon as you clicked Lighteth Fire) and do some updates and line up the sim in the slot ready to run the anims - and this is the MAGIC MOMENT - we have accessed the JAZZ (the statemachine). The next line to get the JAZZ file - statemachinemedieval - is now calling the new JAZZ file which we make in the next step in this tutorial. We can see that the statemachine will use the cheap animations and will run on (this.StartFireCallback), it will use the LightFire and exit as defined in the statemachine and then once it has used our JAZZ for the statemachine it will revert to base for updates and exit.
What our interaction will be called in the pie menu and what is defined to stop it running
If you look in the screenshot of the code (or even in your .cs project if you are following along in visual studio) then you will see that the LightMyFire class has been closed by it's curly bracket - and that this is another class inside MedievalFireplace. We can see that the definition is now using Sim, Medieval Fireplace and our class - MedievalFireplace.LightMyFire
The definition makes it so that "Lighteth Fire" is shown in the piemenu - unless it fails our test. Our test is as follows - is this a sim, is this the medieval fireplace - and - most importantly - is the fire lit, as it would be silly to light a fire that is already lit.
Using the state machine (the JAZZ)
Remember we already called the state machine medieval in LightMyFire, but that was how to start it. This block of code will ensure that our actors (the sim and the fireplace) will perform the interaction as a pair and as defined in our JAZZ code
Making it actually happen
Finally, we remove the original LightFire and add the Lighteth Fire string from the menu. OnStartup( ) is the moment that the object is created in the world. In that method the interaction are called. The interaction is the bit where our object anims etc are "stored" - without an interaction an object is just a piece of pretty deco - without even a "look at".
So now we finally have the code. The bit above is really hard to do if you are not a coder, and I recommend that coders and object makers get together in modding teams to make cool modded objects .
Step 3 Editing the JAZZ
There is an extensive wiki article on the Smooth JAZZ editor - you can find it here or by clicking the help in the application. The JAZZ code is not like the C# sharp code - so it can be easy to get confused. The JAZZ defines what animations are called, there is no target and there is a CLIP for every object (Sim, Fireplace...) that gets animated, so said object is the actor of that animation.
I made a copy of the game JazzData and stored it in a folder. You can also load straight from the game folder. In my set up the folder is at C:\Program Files (x86)\Electronic Arts\The Sims 3\Game\Bin\Jazz
The steps to open the state machine are:
1) Open the Smooth JAZZ application
2) Click on file..Open and browse to the JazzData folder.
3) Click on the JazzData package file
4) You will see a popup of the available JAZZ files. You can sort the list and scroll. I opened fireplace.
Click on Open and you will see the JazzData for the fireplace. In the code block below we see that the name of the machine is "fireplace" and that there are several "actors". Actor x is the sim and there are other actors - the names are quite self explanatory.
Now we need to see where the lightfire anims are being called - if you look in the script, we are using the LightFire interaction. In Smooth JAZZ you can "jump" to an interaction by clicking on the dropdown.
The key lines here are :
Create Prop 1080 as "fireplacelighter" and Select on Parameter "CheapVersion" and Play 0x3C920346D301B884 for "fireplacelighter"
In the script I set the parameter as CheapVersion so the JAZZ will run the cheap animations, the 1080 is an identification for the game to find the specific prop and the play 0x3C920346D301B884 is the identification for a specific animation.
Defining the Prop to use
The PROP is the object that the sim will use in an animation; not the object it is interacting with (in this case a fireplace) but the object it holds during an animation. Examples of props are the sponge when cleaning a stove, the mop when mopping up a puddle and, of course - the fireplacelighter.
1080 is the decimal conversion of a hex number - that hex number is the OBJD IID. If you open the original lighter you will see that the instance id is 0x0000000000000438
I used this online converter - as you can see I removed the 0x from the IID to do the conversion. You can now clone the fireplacelighter and renumber it and using a HEX>DEC converter (available on the same website) find out the decimal value and plug it into the JAZZ.
I also needed to change the JAZZ script finding where fireplacelighter is called and replace that with fireplacetaper.
The first step is to see which animation is being called by the JAZZ:
So that it is the CLIP with the IID of 0x3C920346D301B884. Using to find the resource I opened the CLIP
Then I opened the clip in by right clicking on the resource in and selecting open in editor
Once I had the clip open in I exported and renamed the clip and created a new instance
I then closed that and opened the fireplace package and imported the new clip..
Then I copied the new IID and pasted that into my JAZZ. (IID = 0x2F8D36C98ADBD921)
so we have the following code:
and up at the top of the JAZZ we need to change the start anim actor name to match ours:
Save as a reasonable name (I called mine medieval.JAZZ) and then package all into the fireplace object:
Step 4 Editing the CLIP
You may not have to do this on some PROPs, but on this one there was an effect on the PROP - the flame at the end of the lighter. This meant I had to edit the fireplace lighter CLIP to refer to the correct actor. In the original JAZZ the actor in this clip is as defined the fireplace lighter. In my new CLIP (which was just a copy with a new IID) the actor name and hash were still referring to the original fireplace lighter. This meant that when the object was tested in game the sim (x) lit the fireplace with a firelighttaper (no such thing - so the sim's hand was empty). Easy to fix.
1) Open package containing the exported clip using S3PE.
2) Click on the Fireplace Taper clip
3) Click on grid.
4) Change the actor name to match what it is called in JAZZ (fireplacetaper)
5) Use the Hash tool to get the hashed value.
6) Looking at the picture below, change the values. Click on the + sign next to each event to check you have covered all of them.
7) I cloned the fireplacelighter to make my candle - and a good job too or I would have had to add bones and hashes and all sorts of awful things.
Step5 Creating the PROP
I will not cover how to create an object here - there are already lots of tutorials for object creation. But, here are a few tips:
1) Plan ahead - think about what you want from your anim and prop.
2) If you are replacing a PROP as I am here then clone the original prop. You can find it by looking in the JAZZ - getting the prop id and so on, or just by looking through the accessories objects in S3OC.
3) Unless you want to get really into editing the anims try and keep the new object similarly proportioned to the original.
Step 6 Adding XML and ITUN resources
At the very beginning of this
As there is already a good tutorial that explains how to make an XML file I have not covered that here. Please see the Tutorial:Sims_3_XML_Tuning_Moddingwiki
Making an ITUN resource
ITUN resources are stored in the Sims3\Game\Bin\GameplayData.Package (you can take a copy of it, or you can open it with in read only mode). You can find the location of many resources in this handy table Sims_3:PackedFileTypeswiki. Open the package in and filter for fireplace.
Find one that does almost what you want and alter it. Extract that resource and then open it up in Notepad. (Notepad ++ is a handy tool - and free). This is from the fireplace for example:
Enter the full class name for both interaction definition and object. Note how nested classes are separated by + characters. The ITUN's instance ID is the FNV64 hash of the short class names of interaction and object, separated by a _ character. In this case it's the hash of LightMyFire_MedievalFireplace for example. I don't know if that is exactly necessary, but it is how Buzzler does it . Then save the resource and add to your package.
Attached to this tutorial is the object I modded - a medieval fireplace and a candle. Feel free to rip it apart and see how it works - please do NOT upload elsewhere.
Finally.............. This object (and tutorial) would not exist without the following people who helped with nearly every aspect:
Buzzler, Inge Jones, Peter Jones, cmomoney, orangemittens, atavera, misukisu. Thank You all of you.
3 users say thanks for this.
[ Click here to view a longer list ]
|22nd Feb 2012, 11:56 AM||#2|
|1st Mar 2012, 11:37 AM||#3|
Join Date: Oct 2011
This is a very helpful and detailed tutorial! Thanks