{"slug": "returning-to-the-sims-128-errors-in-a-fresh-lot", "title": "Returning to The Sims: 128 errors in a fresh lot", "summary": "In a blog post, developer Omer Ben-Amram reports that adding LLM-play capability to The Sims 1 via the open-source Simitone engine initially produced 128 errors on a fresh lot, which he reduced to 14 by fixing missing values array slots and carry slot mismatches. He treats the game like enterprise software, logging and auto-acknowledging exceptions so an unattended AI agent can play without GUI dialogs.", "body_md": "This is part of TSaaS (The Sims as a Service), my series about adding LLM-plays capability to The Sims 1.\n\n## Motivation\n\nMy overall goal is to have an unattended setup of an LLM playing the Sims 1.\n\nPart of the work is LLM-related, but a bigger part is setting up a Windows-targeting video game to:\n\n- Run inside a Linux container\n- Install the wiring for API control rather than GUI\n\nAs part of #2, I want to boot the game directly into a lot with a Sim family (for starters, the built-in family “the Goths”) and start playing. That’s where the trouble started.\n\n## Errors: I’m a sysadmin now\n\nThe main reason this project is possible at all is [Simitone](https://github.com/riperiperi/Simitone) — an open-source .NET from-scratch implementation of The Sims 1’s engine, running against the original game’s content files.\n\nAbout a year ago, when I tested it as a human, I noticed that entering a new lot caused a bunch of “unhandled sims engine” errors, which was annoying but click-through-able. Some of them had no visible impact on the game world. Some affected a specific object (e.g. a sofa you can’t sit on), which I could then sell and buy again, solving the problem.\n\n(Note the dialog half-visible behind this one. When it rains, it pours.)\n\nWhen a human was playing the game, they could review each one of the errors popping up and react, like the sofa case. I wanted an unattended process running in a container, so clickable dialogs had to go, and I had to decide what to do with the exceptions they describe. I had two user behaviors I could choose from:\n\n- The diligent user, carefully reading each exception and reacting to it. This would reflect in pausing the game, reflecting the exception to the agent and asking it what it’d like to do with it\n- The optimistic user, clicking “ok” for each dialog and hoping they won’t affect the gameplay too badly.\n\nI chose option #2, and figured that I can monitor the resulting gameplay and invest my energy in preventing the errors rather than reacting to them. Since I’m used to sysadmin-ing enterprise software, I treated the game like one:\n\n- If an exception happens, do not display it on GUI.\n\nInstead, log it, auto-acknowledge it, let the game continue.\n\nThe agent never sees the exception (as if it auto-clicked ok). - When I, the sysadmin, am reviewing the gameplay, I also read the log and look for exceptions.\n\nI do the same thing I’d do when reviewing a service log - group by callsite, target the most frequent ones first, do the research to figure out which are harmful and which are benign, and then either fix or suppress.\n\n## The big boys\n\nLoading the lot reported 128 exceptions, which was weird because the lot was fresh out of the box. It’s one of the lots that come premade with a house and a family so you can start playing immediately, not a random untested combination. So why did it blow up?\n\nMost of them belonged to these types:\n\n- A sim having an 80-slot “values” (motives, skills, flags) array, where the engine wanted 101.\n\nI added the missing entries with sane values. One might ask “what is the sane value for a new attribute?”, but looking at the code, the new attributes were obvious things like “is a superstar” or “is a ghost”, which I can confidently set to`false`\n\nfor newly-loaded sims. - Carry slot mismatch. Simitone knows that a sim should have 3 (head, hands, pelvis), but deferred to the savefile’s slot size (1).\n\nFixed by setting the slot size to 3, initializing missing ones as empty.\n\nEliminating both, I managed to get startup errors from 128 to 14, which is a nice start.\n\nHere’s an example of #1, a Makin’ Magic script checking whether Mortimer is a ghost, but Mortimer comes from a pre-Makin’ Magic save and is missing the relevant flag’s slot:\n\n## Kitchen counter breakdown\n\nAfter accepting 14 startup errors, I moved on and tried making the actual gameplay work. On occasion, the sims would fail when trying to cook themselves a meal. The food would just disappear, an exception would pop up, and the sim would forget about the matter completely. My only hint was that the meal process involved:\n\n- Taking food out of the fridge\n- Chopping stuff on the countertop\n- Cooking (this is where fires happen)\n- Taking the meal to eat (if “have a meal”) or on a flat surface (for “serve meal”) for others to utilize later\n\nSince the sim was able to use the fridge and then errored out, I figured it’s related to countertops. The popping exception was obviously involved too, so it was time to do some heavy debugging.\n\n## Need to go deeper\n\nSince I was able to modify the engine, I could add more debug printing into the exception handler and the Sims VM in general to get more context on what broke. The stack traces themselves are uninteresting. What IS interesting was the annotation I added:\n\n```\n(Tiled Counter:Tiled Counter)\n > main:3/2 #4096 (IP OUT OF RANGE) [restored]\n```\n\n`[restored]`\n\nmarks a frame that came out of a savefile rather than from live execution, which was the smoking gun.\n\nAll of the remaining startup errors were “**IP** (Instruction Pointer) **OUT OF RANGE**”, coming straight from restored saves.\n\nIt turns out each object has a small script it runs, looking a bit like assembly. The counter’s state looks like this:\n\n```\n...\n\"routine\": { \"name\": \"main\", \"id\": 4096,\n           \"instructionCount\": 2, \"opcodes\": [8224, 280] },\n\"ip\": 3,\n...\n```\n\nThe interesting part here is that despite the routine having two instructions, we’re supposed to resume at instruction #3, which is… what?\n\nFor the less assembly-language minded, this is the equivalent of you being instructed to refer to chapter 3 in a book with 2 chapters - an obvious indication that the instruction is referring to a different version of the book than the one you’re holding.\n\nThe VM’s reaction was acceptable, but I had two problems with it:\n\n- The error manifested only when someone wanted to use the object, which was just the time where the object was interesting to the player.\n- The current handling caused the affected sim to drop its action completely, possibly losing items or disrupting whatever grand plan it was following.\n\nWe should prevent this error outright, at load time.\n\n## Quick but incomplete\n\nThanks to the e2e framework I set up (worth its own post), I was able to create a regression test.\nI loaded the savefile, and ensured no object has an `ip`\n\nthat is outside the bounds of its instruction array.\n\nGetting this test green means eliminating the exceptions, which I did by reviewing every object when loading, and resetting ones where the ip was out of bounds of the routine. This made the exceptions go away and the meal prep complete successfully, so I could leave it there, but I wasn’t quite happy.\n\n## Nagging feeling\n\nThe index being out of bounds happened because the object’s routine (coming from the content directory, in a specific Sims version) was no longer matching the one that was referred by the `ip`\n\n(which came from the save file). The out-of-bounds is an obvious indicator of such a mismatch, but is not “required” for the mismatch to happen.\n\nFor instance, let’s assume there exists a fishtank, and its script looks something like this (the `>`\n\nmarks where the saved `ip`\n\npoints):\n\n```\n 1: flip graphic (fish swimming left are now right, etc)\n 2: sleep 10s\n 3: if fed_since > 1 sim-day:\n 4:   goto L7\n>5: else:\n 6:   goto L1\n 7: show dead fish graphic\n 8: (stuck here, fish are dead)\n```\n\nAnd the `ip`\n\nhappened to be set on L5, because the fish were alive and well.\nNow, we load this save into another version of content, where the script looks like this:\n\n```\n 1: flip graphic (fish swimming left are now right, etc)\n 2: sleep 10s\n 3: if fed_since < 1 sim-day:\n 4:   goto L1\n>5: show dead fish graphic\n 6: (stuck here, fish are dead)\n```\n\nSimpler script, victory for all. **But** if we load the save that has `ip`\n\nset to L5, we’ll get a dead fishtank.\nWhile this is not an exception (a mechanical corruption), it’s definitely wrong (a logical corruption).\n\nMy conclusion was that without the original engine available to extract the original scripts from, we have no way of accurately translating `ips`\n\nto the right instruction.\n\n## Discarding everything\n\nWhen faced with dirty data, I see 3 options:\n\n- Leave it as is\n- Clean it\n- Discard it\n\n#1 was unacceptable here, because these corruptions could affect the game in a way that’s going to be hard to detect.\n\n#2, as discussed previously, was only partially doable. Resetting index-bounds-violating objects was easy and solved the mechanical corruption, but silently-remapped lines would stay, causing an unknown amount of logical corruptions.\n\n#3, the way I see it, is not so bad. I prefer losing object states, since:\n\n- The first time I load into a lot, I have not initiated any actions that affect object state, so I’m not afraid of losing a state I care about.\n- I get a guarantee that any actions I do initiate only interact with clean objects, so they won’t be ruined by objects with invalid state.\n\nGood deal for me.\n\n## Postmortem\n\nThis whole problem is a result of serialized class of v1 meeting a runtime of v2. You’re probably wondering “why is this not covered by the engine?”.\n\nDigging through the code, I saw that the sims savefile has a version identifier, and it is being read by Simitone for some things, but not for object state management.\n\nHaving no good understanding on “which version change justifies an object reset”, I used a trick relying on the fact that Simitone’s savefile is different than the original Sims one:\n\n``` python\ndef is_old_savefile(blob):\n  return blob.simitone_specific_data is None\n\ndef deserialize_savefile(blob, ...):\n  if is_old_savefile(blob):\n    reset_all_objects(blob)\n  ...\n```\n\nThis works because:\n\n- All of my never-touched-before saves are in the original Sims format\n- Every save I produce is in the new Simitone format\n- I will never ever get a new “content” pack that modifies objects’ behavior. I only need to differentiate between “before me” and “after me”, and the file format already does that for free\n\nThis solution is:\n\n- Free of both mechanical and logical corruptions\n- Very easy to explain and implement - “when encountering a savefile that didn’t come from our engine, reset all objects”. No heuristics on the ip of every object, no guesswork on whether this specific state is ok.\n- Losing nothing of value gameplay-wise\n\n## Happy ending\n\nWe now run with 0 exceptions on load, and even better - we eliminated a class of invisible potential bugs.\n\nI don’t think there’s a big learning takeaway here. Enterprise software is full of “take care when parsing old state” and “solve the problem and not the symptom”. Spotting it in “The Sims” surprised me.\n\nStay tuned to see what the Goths are doing with their countertops. Heads up: utilization less than perfect.", "url": "https://wpnews.pro/news/returning-to-the-sims-128-errors-in-a-fresh-lot", "canonical_source": "https://blog.backslasher.net/tsaas-saves.html", "published_at": "2026-08-02 11:07:56+00:00", "updated_at": "2026-08-02 11:23:15.637413+00:00", "lang": "en", "topics": ["artificial-intelligence", "large-language-models", "ai-agents", "developer-tools"], "entities": ["Omer Ben-Amram", "Simitone", "The Sims 1", "The Goths", "Makin' Magic"], "alternates": {"html": "https://wpnews.pro/news/returning-to-the-sims-128-errors-in-a-fresh-lot", "markdown": "https://wpnews.pro/news/returning-to-the-sims-128-errors-in-a-fresh-lot.md", "text": "https://wpnews.pro/news/returning-to-the-sims-128-errors-in-a-fresh-lot.txt", "jsonld": "https://wpnews.pro/news/returning-to-the-sims-128-errors-in-a-fresh-lot.jsonld"}}