🎉 Initial source commit

This commit is contained in:
Tony Bark 2025-10-12 13:29:19 -04:00
commit c8b14bd8ae
17 changed files with 3220 additions and 0 deletions

339
.gitignore vendored Normal file
View file

@ -0,0 +1,339 @@
### PyCharm+iml template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# AWS User-specific
.idea/**/aws.xml
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# SonarLint plugin
.idea/sonarlint/
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
### VisualStudioCode template
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/*.code-snippets
# Local History for Visual Studio Code
.history/
# Built Visual Studio Code Extensions
*.vsix
### dotenv template
.env
### Python template
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
.pdm.toml
.pdm-python
.pdm-build/
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
### PyCharm+all template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# AWS User-specific
.idea/**/aws.xml
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# SonarLint plugin
.idea/sonarlint/
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser

3
.idea/.gitignore generated vendored Normal file
View file

@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

View file

@ -0,0 +1,7 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="useProjectProfile" value="false" />
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

7
.idea/misc.xml generated Normal file
View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Black">
<option name="sdkName" value="Python 3.13 (ts4-workspace)" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.13 (ts4-workspace)" project-jdk-type="Python SDK" />
</project>

8
.idea/modules.xml generated Normal file
View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/sims4pythonscripts.iml" filepath="$PROJECT_DIR$/.idea/sims4pythonscripts.iml" />
</modules>
</component>
</project>

17
.idea/sims4pythonscripts.iml generated Normal file
View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/EA/base" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/EA/core" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/EA/simulation" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/EA/generated" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/.venv" />
</content>
<orderEntry type="jdk" jdkName="Python 3.13 (ts4-workspace)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="TestRunnerService">
<option name="PROJECT_TEST_RUNNER" value="Unittests" />
</component>
</module>

6
.idea/vcs.xml generated Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

0
EA/.gitkeep Normal file
View file

22
LICENSE Normal file
View file

@ -0,0 +1,22 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute
this software, either in source code form or as a compiled binary, for any
purpose, commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and
to the detriment of our heirs and
successors. We intend this dedication to be an overt act of relinquishment
in perpetuity of all present and future rights to this software under copyright
law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. For more information,
please refer to <https://unlicense.org/>

View file

@ -0,0 +1,7 @@
import sims4.commands
@sims4.commands.Command('myfirstscript', command_type=sims4.commands.CommandType.Live)
def myfirstscript(_connection=None):
output = sims4.commands.CheatOutput(_connection)
output("This is my first script mod")

View file

@ -0,0 +1,5 @@
from Utilities import compile_module
from settings import *
root = os.path.dirname(os.path.realpath('__file__'))
compile_module(creator_name, root, mods_folder)

3
README.md Normal file
View file

@ -0,0 +1,3 @@
# Sims 4 Python Workspace
[Created by TS4 Studio](https://sims4studio.com/thread/15145/started-python-scripting-updated), this workspace makes it possible for you to develop basic scripting mods for the game. The API is from 2018. So you'll need to decompile your version in order to be compitable with the newest patch.

62
Utilities/__init__.py Normal file
View file

@ -0,0 +1,62 @@
from zipfile import PyZipFile, ZIP_STORED
import shutil
import io
from Utilities.unpyc3 import decompile
import fnmatch
import os
def decompile_dir(rootPath):
pattern = '*.pyc'
for root, dirs, files in os.walk(rootPath):
for filename in fnmatch.filter(files, pattern):
p = str(os.path.join(root, filename))
try:
py = decompile(p)
with io.open(p.replace('.pyc', '.py'), 'w') as output_py:
for statement in py.statements:
output_py.write(str(statement) + '\r')
print(p)
except Exception as ex:
print("FAILED to decompile %s" % p)
script_package_types = ['*.zip', '*.ts4script']
def extract_subfolder(root, filename, ea_folder):
src = os.path.join(root, filename)
dst = os.path.join(ea_folder, filename)
if src != dst:
shutil.copyfile(src, dst)
zip = PyZipFile(dst)
out_folder = os.path.join(ea_folder, os.path.splitext(filename)[0])
zip.extractall(out_folder)
decompile_dir(out_folder)
pass
def extract_folder(ea_folder, gameplay_folder):
for root, dirs, files in os.walk(gameplay_folder):
for ext_filter in script_package_types:
for filename in fnmatch.filter(files, ext_filter):
extract_subfolder(root, filename, ea_folder)
def compile_module(creator_name, root, mods_folder,mod_name=None):
src = os.path.join(root, 'Scripts')
if not mod_name:
mod_name=os.path.basename(os.path.normpath(os.path.dirname(os.path.realpath('__file__'))))
mod_name = creator_name + '_' + mod_name
ts4script = os.path.join(root, mod_name + '.ts4script')
ts4script_mods = os.path.join(os.path.join(mods_folder), mod_name + '.ts4script')
zf = PyZipFile(ts4script, mode='w', compression=ZIP_STORED, allowZip64=True, optimize=2)
for folder, subs, files in os.walk(src):
zf.writepy(folder)
zf.close()
shutil.copyfile(ts4script, ts4script_mods)

64
Utilities/compiler.py Normal file
View file

@ -0,0 +1,64 @@
import fnmatch
import os
from zipfile import PyZipFile, ZIP_STORED
import shutil
import io
from Utilities.unpyc3 import decompile
import fnmatch
import os
def decompile_dir(rootPath):
pattern = '*.pyc'
for root, dirs, files in os.walk(rootPath):
for filename in fnmatch.filter(files, pattern):
p = str(os.path.join(root, filename))
try:
py = decompile(p)
with io.open(p.replace('.pyc', '.py'), 'w', encoding='utf-8') as output_py:
for statement in py.statements:
output_py.write(str(statement) + '\r')
print(p)
except Exception as ex:
print("FAILED to decompile %s" % p)
script_package_types = ['*.zip', '*.ts4script']
def extract_subfolder(root, filename, ea_folder):
src = os.path.join(root, filename)
dst = os.path.join(ea_folder, filename)
if src != dst:
shutil.copyfile(src, dst)
zip = PyZipFile(dst)
out_folder = os.path.join(ea_folder, os.path.splitext(filename)[0])
zip.extractall(out_folder)
decompile_dir(out_folder)
pass
def extract_folder(ea_folder, gameplay_folder):
for root, dirs, files in os.walk(gameplay_folder):
for ext_filter in script_package_types:
for filename in fnmatch.filter(files, ext_filter):
extract_subfolder(root, filename, ea_folder)
def compile_module(creator_name, root, mods_folder,mod_name=None):
src = os.path.join(root, 'Scripts')
if not mod_name:
mod_name=os.path.basename(os.path.normpath(os.path.dirname(os.path.realpath('__file__'))))
mod_name = creator_name + '_' + mod_name
ts4script = os.path.join(root, mod_name + '.ts4script')
ts4script_mods = os.path.join(os.path.join(mods_folder), mod_name + '.ts4script')
zf = PyZipFile(ts4script, mode='w', compression=ZIP_STORED, allowZip64=True, optimize=2)
for folder, subs, files in os.walk(src):
zf.writepy(folder)
zf.close()
shutil.copyfile(ts4script, ts4script_mods)

2649
Utilities/unpyc3.py Normal file

File diff suppressed because it is too large Load diff

13
decompile_all.py Normal file
View file

@ -0,0 +1,13 @@
from Utilities import extract_folder
from settings import *
ea_folder = 'EA'
if not os.path.exists(ea_folder):
os.mkdir(ea_folder)
gameplay_folder_data = os.path.join(game_folder, 'Data', 'Simulation', 'Gameplay')
gameplay_folder_game = os.path.join(game_folder, 'Game', 'Bin', 'Python')
extract_folder(ea_folder,gameplay_folder_data)
extract_folder(ea_folder,gameplay_folder_game)

8
settings.py Normal file
View file

@ -0,0 +1,8 @@
import os
creator_name = 'My Creator Name'
mods_folder = os.path.expanduser(
os.path.join('~', 'Documents', 'Electronic Arts', 'The Sims 4', 'Mods')
)
game_folder = os.path.join('C:', os.sep, 'Program Files (x86)', 'Origin Games', 'The Sims 4')