Hi there! You are currently browsing as a guest. Why not create an account? Then you get less ads, can thank creators, post feedback, keep a list of your favourites, and more!
Lab Assistant
Original Poster
#1 Old 26th Sep 2014 at 10:25 PM Last edited by justJones : 6th May 2018 at 11:05 PM.
Default For absolute beginners with no clue: Making a simple script that gets the town's population.
So, my last tutorial might have been a little complex. In lieu of this, I decided to write something a little more introductory to The Sims 4's scripting framework. Today, we're going to make a "Get Town Population" mod (for reference, you can see the full source code and mod here). Hopefully, when we're done with this tutorial, you can begin to understand how the framework.. uhm... works.

The main purpose of this tutorial is to accustom you to finding things within The Sims 4's own Python code. It's a giant web of objects, classes, and functions, so it's easy to get lost. This is the process I normally go through when finding different things I need.

What You'll Need
  • The Sims 4's core Python modules.
  • A slight idea of how Python works.

So, now, we're going to have take a peek at the Python modules provided in The Sims 4 (you should be looking at PY files, not PYO files). You can find helpful ways to get your hands on these core modules here and here. "base", "core", and "simulation" are each labels to module collections that are used in the game's intelligence engine. We're going to concern ourselves with "core" and "simulation". As I've noticed, "base" contains a very large amount of library modules useful for certain micro-operations within the game's code, but aren't necessarily things we will often have to look at. "core" and "simulation" are most important for modding the game.

To successfully complete our little mod here, we need a command that you can type. When it's typed, it will reveal the population of all the sims in your game. Now that we know our goal, we can proceed to hunt for the things we need.

Let's have a look at "core" first. Within the core collection, you'll find "google", "shared_commands", and "sims4". Within sims4, you'll find several other libraries related to the handling of modder-created Python modules, algorithms essential for the functioning of the game, and key aspects found within The Sims 4's user interface. This is probably the best place to look if we want to find out where there is a function in the game that allows us to register new cheat console (Ctrl+Shift+C) commands. And speak of the devil! There's a "commands.py" file in there! Let's have a look...

It seems there's a function there called Command:

Code:
def Command(*aliases, command_type=CommandType.DebugOnly, pack=None):


Great! That would give us the first line of code that we need! Let's start our script!

Code:
import sims4.commands


It is important that we import the module or else we will end up with errors because our own module will not recognize the things we declare.

Now, it's time to insert the call to sims4.commands.Command() as a decorator. Whatever function we define directly below the decorator will be its "subject" (the decorator will be applied to that function). But wait! Before we register the command, we need to be sure that we've nailed down the command type. In "commands.py", there's an enumerated list of command types:

Code:
class CommandType(enum.Int, export=False):
__qualname__ = 'CommandType'
DebugOnly = 1
Automation = 2
Cheat = 4
Live = 5


OK, so we're going to register our command type as a Live command. Remember the definition of the Command() function we saw earlier? It's already passing a command_type for us, and we need to override that in our own code:

Code:
@sims4.commands.Command('getpopulation', command_type=sims4.commands.CommandType.Live)


Good! Now, it's time to declare a function right below this beautiful decorator that gives some output back, giving the player that types "getpopulation" the town's population. First, we need to find out what we should call to output to the cheat console, then we need to find out how to grab the town's population. This is where things get a little more tricky.

So, let's get that output function.... I think we should look in "commands.py" a little more.

Ah, found it!

Code:
class CheatOutput(Output):
__qualname__ = 'CheatOutput'

def __call__(self, s):
cheat_output(s, self._context)


The "__call__" function tells us that we only need to write a string when calling the function. Now, let's focus on getting the town's population.

For the town population and all that other jazz, we need to get out of the core module collection and dive into "simulation". In the "sims" folder, there's a file called "sim_info_manager.py". That looks like a good place to start.

There's a class in that file called "SimInfoManager". It seems to hold the details of every sim. If we could count all of the sims in its list, then that will give us the population of all sims. While looking through the rest of the code in TS4's repository, I'm noticing a pattern: sim_info_manager is an object in services. Its attachment to services is found in __init__.py inside the services folder. More importantly, it has a function that's called sometimes inside of the code files called get_all(), which returns a list element. That seems to have solved our mystery!

OK, so let's recap a little. Here's our code so far:

Code:
import sims4.commands

@sims4.commands.Command('getpopulation', command_type=sims4.commands.CommandType.Live)


All this searching and we've only written two lines of code! It's getting late and you're yawning, we've looked through all of TS4's code, and all we managed to finish is two lines! That's no problem, though, since we've found everything we need now to finish the mod!

We'll start by importing services (which will also import its __init__.py) at the top where we imported sims4.commands:

Code:
import services


Now, we need to go under the decorator and declare a function right there:

Code:
def getpop(_connection=None):


Don't worry about the _connection variable. I ripped that off of the maslow mod that EA wrote, and that's just become a habit now. You can call it fluffy_kittens if you'd like.

So, now that we know how to output to the cheat console (by calling CheatOutput), we should define a variable that calls it:

Code:
    output = sims4.commands.CheatOutput(_connection)


Now, all we have to do to output a string is to type output('blablabla'). But we don't want to output just 'blablabla'. We want to output the town's population. This is where our search for sim_info_manager in services pays off.

Code:
    output('Your town\'s population is {}'.format(len(services.sim_info_manager().get_all())))


You see, by measuring the length of the list we get when we call get_all() in services.sim_info_manager(), we get the count of all the sims in the universe! We've finished our mod!

This is what our final code looks like:

Code:
import services
import sims4.commands

@sims4.commands.Command('getpopulation', command_type=sims4.commands.CommandType.Live)
def getpop(_connection=None):
	output = sims4.commands.CheatOutput(_connection)
	output('Your town\'s population is {}'.format(len(services.sim_info_manager().get_all())))


Short, useful, succinct, elegant, and tastier than the cordon bleu I stole from my wife yesterday. This is the result of that code.



HINT: If you don't have Notepad++, GET IT. It's very useful for finding things within files. For example, I can use the "Find in Files" feature to search the entire Sims 4 repository for instances in which a particular function (like get_all() in this example) is called.
8 users say thanks for this. (Who?)
Advertisement
Instructor
#2 Old 26th Sep 2014 at 10:30 PM
This is awesome! I'm definitely going to go through all of this later! I've been wanting to learn how to do some of these things so that I could do my own tuning and things to customize the game for me but I had no idea of where to even start. Thank you! I'll be back later if I have questions!
Lab Assistant
Original Poster
#3 Old 26th Sep 2014 at 11:00 PM
Quote: Originally posted by melbrewer367
This is awesome! I'm definitely going to go through all of this later! I've been wanting to learn how to do some of these things so that I could do my own tuning and things to customize the game for me but I had no idea of where to even start. Thank you! I'll be back later if I have questions!


For tuning, I'd imagine you would have to deal with the game's ".package" files. Scripting strictly adds more functions into the game using by latching modules onto the game's code. One good way to think of it is that tuning modifies values in the game and adds tangible things to it (like objects, food, etc.) and scripting is more useful to modify how the game itself runs (i.e. my relationship decay mod)
Instructor
#4 Old 26th Sep 2014 at 11:39 PM
Quote: Originally posted by mgomez
For tuning, I'd imagine you would have to deal with the game's ".package" files. Scripting strictly adds more functions into the game using by latching modules onto the game's code. One good way to think of it is that tuning modifies values in the game and adds tangible things to it (like objects, food, etc.) and scripting is more useful to modify how the game itself runs (i.e. my relationship decay mod)


Right. Thank you for clarifying the difference. The scripting is what I meant like your relationship decay mod you mentioned (which I downloaded the same day you posted it!).
Lab Assistant
Original Poster
#5 Old 27th Sep 2014 at 12:32 AM
Quote: Originally posted by melbrewer367
Right. Thank you for clarifying the difference. The scripting is what I meant like your relationship decay mod you mentioned (which I downloaded the same day you posted it!).


I certainly hope you have the latest version. Earlier version had a glaring bug because of some of the game mechanisms (some of which I might explain in another tutorial, when I find the time to stop banging my head against my desk).

I'm happy to help if you ever need some guidance in making mods. The process becomes a bit intuitive once you get the hang of how the game's nuts and bolts clunk together.
Test Subject
#6 Old 3rd Oct 2014 at 4:31 PM
I did everything you said but it doesn't work
Maybe I saved it wrong or something?
I must admit I've never used python, more used to Java.
I really want to start making mods so if you could be kind enough to help me out a bit I would be thankful for ever :D
Test Subject
#7 Old 15th Oct 2014 at 5:33 AM
Default Compilation
Hi mgomez!

Thank you for the tutorial. It is very helpful, short and to the point. Great to get somebody started!

But I am trying to compile my own script and it doesn't seem to work. I think I am not creating the .py file in the correct directory. It complains about modules not existing.

What directory (core, base, or simulation) should the script be created in in order for compilation to finish successfully?

Thanks!

Zar
Test Subject
#8 Old 21st Oct 2014 at 5:31 PM
Could this process be used to mod NPC behaviors as a whole town? say like getting sims to go to work,and have and raise their own offspring?
Test Subject
#9 Old 26th Oct 2014 at 9:11 PM
So I've followed the other tutorials to decompile the pyo files and I'm running into an issue that has been asked before, but I haven't found any answers. When I call TheHologramMan’s unpyc3.py with a .pco file I ALWAYS get back the "USAGE: C:\Python33\unpyc3.py <filename.pyc>" message, as if I left off the file parameter...but I didn't. This happens even when I don't use the batch script - to test, I copied abc.pyo from base.zip to my Python dir (Python33) so that it's in the same folder as unpyc3.py, cd'd to that folder (even though it's in my PATH so I shouldn't have to), and called exactly this: unpyc3.py abc.pyo

It didn't work. Suggestions?
Test Subject
#10 Old 7th Apr 2015 at 9:36 PM
In this tutorial, you've said that we should be looking at .py files, and not .pyo files. However, the decompiler bat script only generates .pyo files.
Test Subject
#11 Old 9th Sep 2015 at 10:20 AM Last edited by Lynire : 17th Dec 2015 at 4:00 PM.
After you get your .py file, in order to get it to work you need to make a .pyo file and put that along with your .py file into a zip file. The zip file is what goes into your Sims 4 Mods folder. To make a .pyo file, you can create a batch file named something like PythonOptimizeCompile.bat and put this in it:

Code:
@echo off
if %1x==x goto usage
%~d1
cd "%~p1"
echo on
python -O -c "import py_compile;py_compile.compile('%~n1%~x1','%~n1.pyo')"
@echo off
goto end
:usage
echo drag+drop the .py file onto this to compile to a .pyo file.
:end
pause


If you have more than one Python version installed and the version found by your path is not the version used by Sims 4 (3.3.5) then you will need to put the full path in for the python command rather than just "python" or change your path variable.

Then when you drag+drop your .py file onto that batch file it will create a .pyo file with the same base name as the .py file in the same folder, provided python is in your path. This applies to Windows.
One horse disagreer of the Apocalypse
#12 Old 31st Jan 2016 at 11:14 AM
Testing this in game, I got "Unable to execute command". Obviously there is no clue where it went wrong. It appeared to compile ok.

"You can do refraction by raymarching through the depth buffer" (c. Reddeyfish 2017)
Pettifogging Legalist!
retired moderator
#13 Old 31st Jan 2016 at 11:24 AM
Do you see anything in lastException.txt? "Unable to Execute" is a good sign, it means that your script is basically working and the game only does not understand what you're trying to tell it.

Maybe this thread helps: http://forums.thesims.com/en_US/dis...-the-game-files -- this is when I made my first script attempt, and SGEugi basically walked me through it step by step. I believe about 50% of all things one could possibly do wrong are covered in that thread

Stuff for TS2 · TS3 · TS4 | Please do not PM me with technical questions – we have Create forums for that.

In the kingdom of the blind, do as the Romans do.
One horse disagreer of the Apocalypse
#14 Old 31st Jan 2016 at 12:21 PM
I think my compiling is wrong as the .py works ok as a loose file, just the .pyo not working now.

"You can do refraction by raymarching through the depth buffer" (c. Reddeyfish 2017)
Lab Assistant
#15 Old 14th Nov 2016 at 11:52 PM
Awesome. But what is the _connection=None argument for?(I know you said i don't have to worry about it... But it's intriguing) And where is the get_all() command declared?
Test Subject
#16 Old 15th Nov 2016 at 9:17 PM
So this is a fairly old thread and may not even be the right place to ask but ... I cannot even get past downloading python :/ I go through the installation wizard and it says it can't be completed because there is no software to install. I was hoping someone here had heard of this problem before, or is it strictly something I need to contact the python website about. Thanks
Lab Assistant
#17 Old 30th Jan 2017 at 2:32 PM
Can this method override an existing pyo in the game, or can it only supplement?
Test Subject
#18 Old 18th Mar 2017 at 6:45 PM
Hey I tried this tutorial out for myself and it worked after a bit of troubleshooting and diffing.

What I noticed is that in your final code piece listed at the bottom of your original post you have:

Code:
def getpop(_connection=None)


but in your source code for your actual mod you just have:

Code:
def getpop(_connection)


I compiled and tested both versions of this with the =None and without, and found that just having def getpop(_connection), the command would work in game.

Was setting it equal to None a typo?

(p.s. I'm a total noob at python, hopefully this might help someone else that's running thru this tutorial and having problems at the end)
Test Subject
#19 Old 25th Oct 2017 at 7:18 PM
I've done all I have to do to create the core folder, but inside I've found only .pyo files, none .py files. Where I go wrong?
Test Subject
#20 Old 16th Apr 2020 at 10:27 AM
Default Same problem - cannot see any Python code files
Quote: Originally posted by elimegreeneyed
I've done all I have to do to create the core folder, but inside I've found only .pyo files, none .py files. Where I go wrong?


I got the same problem too. Hopefully somebody will reply soon. I guess it has something to do with changes in the patches/game code since 2014. Most of the tutorials were written in 2014 or 2015, it's been few years and maybe things no longer work correctly...
Test Subject
#21 Old 21st Sep 2020 at 3:20 PM
Quote: Originally posted by huong.le
I got the same problem too. Hopefully somebody will reply soon. I guess it has something to do with changes in the patches/game code since 2014. Most of the tutorials were written in 2014 or 2015, it's been few years and maybe things no longer work correctly...


I tried to follow this tutorial as well but I agree with you, most of thetutorials are badly out of date and some of the other ones aren't written well. I decided to write a modern tutorial that you may be interested in and it may help you figure this one out. Tutorial Here In general though I hope to see people writing more tutorials on this. There's barely anything out there and this thread is one of the top Google results for me still and it's from ages ago.
Field Researcher
#22 Old 21st Sep 2020 at 7:20 PM
@junebug12851 The most up-to-date tutorial for extracting Python files that we have is here: https://sims4studio.com/thread/1514...ython-scripting
Google seems to hate Andrew's tutorial, unfortunately. But thank you for the detailed tutorials and continuing to write more, the community will love these!

Creator Musings is a Sims 4 modder, poser/animator, and CC creator hangout server (though everyone is allowed) with a tutorial/resource directory, help channels, and mod/cc/sims 4 news channels!
My Discord | Twitter | Tumblr | Patreon
Test Subject
#23 Old 21st Sep 2020 at 8:40 PM
@MizoreYukii Google's not completely unkind to Andrew's tutorial lol, I did find it on Google after going through several different search results. The issue I had was it didn't work that well for me as there were errors and the comments are full of people having similar errors but more importantly the tutorial takes a hands-off approach. It focuses on teaching python modding but abstracting away all the difficulties and enforcing a certain setup. Everything is already done for you, you just follow the tutorials and structure things how the tutorial says to.

This doesn't leverage recommended modern tools which succeed the older ones over time so it's not future proof and it doesn't explain to people the rest of the stuff that goes into python modding. Since you're depending on pre-made scripts to do the other stuff for you, when it breaks, you don't know what to do and have to enter the comments to ask for help. Andrew's tutorial and this tutorial inspired me to write a tutorial that was modern and explained everything hands-on and without abstracting things away because I want people to stand on their own and not have to rely on scripts other people made long ago or outdated tools or a certain project structure and when things change in the future have the knowledge to adapt to the changes and confidence to help others out.

I really love your compliment! I hope the community does love it and I really want to see more people confident with python modding and leveraging it in mods or talking about it.
Test Subject
#24 Old 1st Oct 2020 at 10:33 PM
Thank you for the guide! I've been thinking for a while that I wanted to get into modding the Sims 4, and I do have basic knowledge in python but all the instructions were in XML or creating CC in SimsStudio.
You mentioned another guide you wrote, do you have any more tips for writing mods?
Back to top