Skip to main content

A scalable, modular ECS-based world simulation framework โ€” people, cities, relationships, and more

Project description

๐ŸŒ pykworldsim

A scalable, modular Entity-Component-System (ECS) world simulation framework.
Simulate people, relationships, cities, jobs, goals, and events โ€” or anything you design.

Python 3.10+ License: MIT Tests Version


โœจ Features

Feature Description
โšก Pure ECS Entities, components, and systems cleanly separated
๐Ÿ‘ค Domain model Built-in Person, Location, Job, Goal, Relationship, Event components
๐Ÿ” Deterministic Seed-based reproducibility across runs
โฏ๏ธ Pausable loop Pause / resume the simulation mid-run
๐Ÿ’พ Save / Load Full JSON world state serialisation
๐Ÿ”Œ Plugin system Register custom systems dynamically by class or import path
โš™๏ธ YAML/JSON config Define entire worlds declaratively
๐Ÿ“‹ Rich CLI pykworldsim run config.yaml with coloured output
๐Ÿงช Fully tested 60+ pytest test cases covering all layers
๐Ÿ“ฆ pip-installable Standard pyproject.toml, PEP 561 typed

๐Ÿ“ฆ Installation

# From PyPI
pip install pykworldsim

# From source (with dev extras)
git clone https://github.com/ka1rav6/pykworldsim
cd pykworldsim
pip install -e ".[dev]"

๐Ÿš€ Quick Start

Physics simulation

from pykworldsim import World, Simulation, Position, Velocity, MovementSystem
from pykworldsim.core.systems.physics import PhysicsSystem

world = World(name="demo")
world.register_system(PhysicsSystem(gravity=9.81, bounds=(0, 0, 100, 100)))
world.register_system(MovementSystem())

e = world.create_entity()
world.add_component(e, Position(x=10.0, y=0.0))
world.add_component(e, Velocity(dx=2.0, dy=0.0))

sim = Simulation(world, seed=42)
sim.run(steps=100, dt=0.1)

pos = world.get_component(e, Position)
print(f"Final: ({pos.x:.2f}, {pos.y:.2f})")

Social simulation

from pykworldsim import (
    World, Simulation,
    Person, Job, Goal, Relationship,
    SocialSystem, EventSystem,
)
from pykworldsim.core.components.event import Event

world = World(name="society")
world.register_system(SocialSystem())
world.register_system(EventSystem())

alice = world.create_entity()
world.add_component(alice, Person(name="Alice", age=28.0, happiness=65.0))
world.add_component(alice, Job(title="Engineer", salary=8000.0, satisfaction=75.0))
world.add_component(alice, Goal(description="Get promoted", priority=9.0))

# Schedule a birthday event at tick 5
ev = world.create_entity()
world.add_component(ev, Person(name="_holder"))
world.add_component(ev, Event(name="Birthday", event_type="social", tick_scheduled=5))

sim = Simulation(world, seed=2024)
sim.run(steps=20, dt=1.0)

person = world.get_component(alice, Person)
print(f"Alice: age={person.age:.1f}, happiness={person.happiness:.1f}")

Original repo API (backward compatible)

from pykworldsim import World
from pykworldsim import Person

# Original-style usage still works
world = World()
alice = world.create_entity()
world.add_component(alice, Person(name="Alice"))
world.Simulate()               # alias for world.update()
report = world.generate_report()
print(report)

๐Ÿ–ฅ๏ธ CLI Usage

# Run a simulation from a YAML config
pykworldsim run examples/config.yaml

# Enable debug logging and save final state
pykworldsim run examples/config.yaml --verbose --save output.json

# Inspect a saved world
pykworldsim inspect output.json

# Print full JSON report
pykworldsim run examples/config.yaml --report

# Load a custom plugin system
pykworldsim run config.yaml --plugin mypackage.systems.MySystem

# List registered plugins
pykworldsim plugins

โš™๏ธ YAML / JSON Config Format

name: my-world
log_level: INFO

simulation:
  steps: 100
  dt: 0.1
  seed: 42

systems:
  - type: MovementSystem
  - type: SocialSystem
    params:
      age_rate: 0.05
      energy_decay: 0.3

entities:
  - position: {x: 0.0, y: 0.0}
    velocity:  {dx: 5.0, dy: 2.0}

  - person: {name: Alice, age: 28.0, happiness: 65.0}
    job:    {title: Engineer, salary: 8000.0, satisfaction: 75.0}
    goal:   {description: "Get promoted", priority: 9.0}

๐Ÿ”Œ Plugin System

Register a custom system at runtime โ€” no subclassing of a framework class needed, just subclass BaseSystem:

from pykworldsim.core.systems.base_system import BaseSystem
from pykworldsim.core.components.position import Position
from pykworldsim.plugins import PluginRegistry

class BoundaryWrapSystem(BaseSystem):
    def __init__(self, width=100.0, height=100.0):
        super().__init__()
        self.width = width
        self.height = height

    def update(self, dt: float) -> None:
        for entity, (pos,) in self.world.get_components(Position):
            pos.x %= self.width
            pos.y %= self.height

# Register by class
PluginRegistry.register("BoundaryWrapSystem", BoundaryWrapSystem)

# Or register by import path (useful for CLI --plugin flag)
PluginRegistry.register_from_path("mypackage.systems.BoundaryWrapSystem")

๐Ÿ’พ Save & Load

# Save world state
world.save("checkpoint.json")

# Restore world state
from pykworldsim import World
world = World.load("checkpoint.json")

๐Ÿ—๏ธ Architecture

pykworldsim/
โ”œโ”€โ”€ core/
โ”‚   โ”œโ”€โ”€ entity.py          Thread-safe entity ID allocation
โ”‚   โ”œโ”€โ”€ world.py           ECS container: entities + components + systems
โ”‚   โ”œโ”€โ”€ simulation.py      Deterministic, pausable simulation loop
โ”‚   โ”œโ”€โ”€ components/
โ”‚   โ”‚   โ”œโ”€โ”€ position.py    2-D spatial coordinate
โ”‚   โ”‚   โ”œโ”€โ”€ velocity.py    2-D velocity vector
โ”‚   โ”‚   โ”œโ”€โ”€ person.py      Individual agent (age, health, happiness, energy)
โ”‚   โ”‚   โ”œโ”€โ”€ location.py    Named place / city
โ”‚   โ”‚   โ”œโ”€โ”€ relationship.py Directed bond between entities
โ”‚   โ”‚   โ”œโ”€โ”€ job.py         Occupation / role
โ”‚   โ”‚   โ”œโ”€โ”€ goal.py        Motivation / objective
โ”‚   โ”‚   โ””โ”€โ”€ event.py       Scheduled time-based occurrence
โ”‚   โ”œโ”€โ”€ systems/
โ”‚   โ”‚   โ”œโ”€โ”€ base_system.py Abstract base class
โ”‚   โ”‚   โ”œโ”€โ”€ movement.py    pos += vel ร— dt
โ”‚   โ”‚   โ”œโ”€โ”€ physics.py     Gravity + boundary bouncing
โ”‚   โ”‚   โ”œโ”€โ”€ social.py      Ageing, energy, happiness, goal progress
โ”‚   โ”‚   โ””โ”€โ”€ event.py       Event scheduling and dispatch
โ”‚   โ””โ”€โ”€ config/
โ”‚       โ””โ”€โ”€ loader.py      YAML / JSON โ†’ World + Simulation
โ”œโ”€โ”€ plugins/
โ”‚   โ””โ”€โ”€ registry.py        Dynamic system registration
โ”œโ”€โ”€ utils/
โ”‚   โ””โ”€โ”€ logging.py         Logging configuration helper
โ””โ”€โ”€ cli.py                 Typer CLI with Rich output

ECS pattern:

Concept Role
Entity Opaque integer ID โ€” carries no data
Component Plain dataclass โ€” data only, no logic
System Logic only โ€” queries entities by component, mutates them

๐Ÿงช Running Tests

pip install -e ".[dev]"

pytest                                  # all tests
pytest --cov=pykworldsim               # with coverage report
pytest tests/test_simulation.py -v     # single module
pytest -k "test_physics"               # filter by name

Example usage

from pykworldsim.core.world import World
from pykworldsim.core.simulation import Simulation
from pykworldsim.systems.physics import MovementSystem
from pykworldsim.core.entity import Entity

# Create world
world = World(size=100)

# Create entity
player = Entity()
player.add_component("position", {"x": 0, "y": 0})
player.add_component("velocity", {"dx": 1, "dy": 1})

world.add_entity(player)

# Add system
world.add_system(MovementSystem())

# Run simulation
sim = Simulation(world)

for step in range(10):
    sim.step(dt=1.0)

# Output
for entity in world.entities:
    pos = entity.get_component("position")
    print(pos)

๐Ÿ“„ License

MIT ยฉ Kairav Dutta

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pykworldsim-2.0.0.tar.gz (32.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pykworldsim-2.0.0-py3-none-any.whl (32.0 kB view details)

Uploaded Python 3

File details

Details for the file pykworldsim-2.0.0.tar.gz.

File metadata

  • Download URL: pykworldsim-2.0.0.tar.gz
  • Upload date:
  • Size: 32.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for pykworldsim-2.0.0.tar.gz
Algorithm Hash digest
SHA256 465faa33564e2e695ea5b3316dc4694653cd4bf8f9a8a712e899dece3e0de522
MD5 8e7ceafeadbcfa4a54a2ff77b79b9012
BLAKE2b-256 53d0674798448506bf6b8ea3619b29052220bb00f2c476c290540b2240cdb554

See more details on using hashes here.

File details

Details for the file pykworldsim-2.0.0-py3-none-any.whl.

File metadata

  • Download URL: pykworldsim-2.0.0-py3-none-any.whl
  • Upload date:
  • Size: 32.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for pykworldsim-2.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9c4beae96a6e9cb95cc2d590c2806d9fba4d474137560f689d46c549bbaacf2f
MD5 065eed81cd3e390edd78f0970dc5dfff
BLAKE2b-256 001dd8093e1b06f3d131934355c7f6618a3f19e84674d1d583938bca64593fe0

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page