openworldformat 0.4.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- openworldformat/__init__.py +1765 -0
- openworldformat/agent.py +142 -0
- openworldformat/cinematography.py +404 -0
- openworldformat/dataset.py +83 -0
- openworldformat/entity_refs.py +25 -0
- openworldformat/eval.py +226 -0
- openworldformat/physics.py +424 -0
- openworldformat/soundtrack.py +94 -0
- openworldformat-0.4.4.dist-info/METADATA +278 -0
- openworldformat-0.4.4.dist-info/RECORD +12 -0
- openworldformat-0.4.4.dist-info/WHEEL +5 -0
- openworldformat-0.4.4.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"""The soundtrack curves — the pure math half of the soundtrack block.
|
|
2
|
+
|
|
3
|
+
Spec: spec/world.md (the soundtrack section). A world's soundtrack is
|
|
4
|
+
curves over time: energy per second, beats at a bpm, sections as
|
|
5
|
+
fractions of the duration, modulations over a signal. Renderers and
|
|
6
|
+
audio engines consume them; here they are plain functions over plain
|
|
7
|
+
numbers — the notebook's half, no audio required.
|
|
8
|
+
|
|
9
|
+
Ported from the JS reference's pure-curve functions (``js/src/render.js``),
|
|
10
|
+
which is where the renderer keeps them because it is the only JS
|
|
11
|
+
consumer. Python's consumers are analysis, not playback.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import math
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"curve_at",
|
|
20
|
+
"beat_at",
|
|
21
|
+
"section_at",
|
|
22
|
+
"modulation_factor",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _clamp01(v: float) -> float:
|
|
27
|
+
return min(1.0, max(0.0, v))
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _mod(a: float, n: float) -> float:
|
|
31
|
+
return (a % n + n) % n
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _num(v) -> float | None:
|
|
35
|
+
"""A JSON number, or None — JavaScript's ``x > 0`` on undefined."""
|
|
36
|
+
if isinstance(v, (int, float)) and not isinstance(v, bool):
|
|
37
|
+
return v
|
|
38
|
+
return None
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def curve_at(curve: list | None, t: float) -> float:
|
|
42
|
+
"""``SoundtrackDef::energy_at`` / ``curve_at``: per-second curve, linear
|
|
43
|
+
interpolation, clamped to [0, 1]. Time outside the curve holds its
|
|
44
|
+
endpoints."""
|
|
45
|
+
if not curve:
|
|
46
|
+
return 0.0
|
|
47
|
+
n = len(curve)
|
|
48
|
+
if n == 1:
|
|
49
|
+
return _clamp01(curve[0])
|
|
50
|
+
tt = min(max(t, 0.0), n - 1)
|
|
51
|
+
i = math.floor(tt)
|
|
52
|
+
f = tt - i
|
|
53
|
+
if i + 1 >= n:
|
|
54
|
+
return _clamp01(curve[-1])
|
|
55
|
+
return _clamp01(curve[i] + (curve[i + 1] - curve[i]) * f)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def beat_at(soundtrack: dict | None, t: float) -> float:
|
|
59
|
+
"""``SoundtrackDef::beat_at``: 1 on a beat, decaying linearly to 0 at
|
|
60
|
+
the next. 0 when there is no bpm."""
|
|
61
|
+
st = soundtrack if isinstance(soundtrack, dict) else {}
|
|
62
|
+
bpm = _num(st.get("bpm"))
|
|
63
|
+
if bpm is None or not bpm > 0:
|
|
64
|
+
return 0.0
|
|
65
|
+
period = 60 / bpm
|
|
66
|
+
offset = _num(st.get("beat_offset"))
|
|
67
|
+
since = _mod(t - (offset or 0.0), period)
|
|
68
|
+
return 1 - since / period
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def section_at(soundtrack: dict | None, t: float) -> int:
|
|
72
|
+
"""``SoundtrackDef::section_at``: the index of the section holding ``t``
|
|
73
|
+
(sections are start fractions of the duration). 0 when there is no
|
|
74
|
+
duration or no sections."""
|
|
75
|
+
st = soundtrack if isinstance(soundtrack, dict) else {}
|
|
76
|
+
sections = st.get("sections")
|
|
77
|
+
sections = sections if isinstance(sections, list) else []
|
|
78
|
+
duration = _num(st.get("duration"))
|
|
79
|
+
if duration is None or not duration > 0 or not sections:
|
|
80
|
+
return 0
|
|
81
|
+
frac = _clamp01(t / duration)
|
|
82
|
+
idx = 0
|
|
83
|
+
for i in range(len(sections)):
|
|
84
|
+
if sections[i] <= frac:
|
|
85
|
+
idx = i
|
|
86
|
+
return idx
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def modulation_factor(definition: dict | None, signal: float) -> float:
|
|
90
|
+
"""``ModulationDef::factor``: map a [0, 1] signal onto ``range``."""
|
|
91
|
+
d = definition if isinstance(definition, dict) else {}
|
|
92
|
+
rng = d.get("range") or [1.0, 1.0]
|
|
93
|
+
a, b = rng[0], rng[1]
|
|
94
|
+
return a + (b - a) * _clamp01(signal)
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: openworldformat
|
|
3
|
+
Version: 0.4.4
|
|
4
|
+
Summary: The Open World Format research package: parse and fold a .world in pure Python, no engine required.
|
|
5
|
+
Author: The Open World Format contributors
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Repository, https://github.com/openworldformat/openworldformat
|
|
8
|
+
Project-URL: Documentation, https://openworldformat.org
|
|
9
|
+
Project-URL: Homepage, https://openworldformat.org
|
|
10
|
+
Keywords: 3d,world,gltf,scene,format,session,crdt,replay,benchmark,dataset
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
20
|
+
Classifier: Topic :: File Formats
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# openworldformat (PyPI)
|
|
26
|
+
|
|
27
|
+
The Open World Format research package. The core — parse a `.world`
|
|
28
|
+
manifest, fold its session log — is pure standard library, no
|
|
29
|
+
dependencies, and deliberately **no renderer**: this is the format's
|
|
30
|
+
research surface, not a viewer. Embodied-agent benchmarks (tasks as
|
|
31
|
+
predicates over the state document, trajectories in the format's own
|
|
32
|
+
op vocabulary), dataset tooling over session logs (fold a thousand
|
|
33
|
+
recordings, compute one number), and notebooks — none of that wants
|
|
34
|
+
three.js or Bevy; all of it wants `pip install openworldformat` and
|
|
35
|
+
a fold.
|
|
36
|
+
|
|
37
|
+
It is also the fold contract's third independently-built
|
|
38
|
+
implementation, sharing no code or toolchain with the JS reference or
|
|
39
|
+
the Rust one — every conformance world and outcome assertion the `js`
|
|
40
|
+
CI job runs, this package runs too, and the two folds agree
|
|
41
|
+
byte-for-byte on the example packages.
|
|
42
|
+
|
|
43
|
+
## Install
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install openworldformat
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Use
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
from pathlib import Path
|
|
53
|
+
from openworldformat import read_package, fold_log, to_manifest
|
|
54
|
+
|
|
55
|
+
# A head-first package: manifest.json is the world now (`head`); the log
|
|
56
|
+
# folds over snapshots/base.json back to it.
|
|
57
|
+
base, entries, head, package = read_package(Path("world"))
|
|
58
|
+
|
|
59
|
+
state = fold_log(base, entries)
|
|
60
|
+
state["entities"] # the world at head revision
|
|
61
|
+
state["applied_edits"] # how many edits the log held
|
|
62
|
+
to_manifest(state) # the whole manifest again — the fold is total
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
The fold applies the spec's rules: only `edit` ops change the document;
|
|
66
|
+
`tool`, `input`, `state` and `clock` fold to nothing; a `Batch` applies
|
|
67
|
+
all-or-nothing; ids and names stay unique; deleting an entity deletes
|
|
68
|
+
its descendants; it stops at the first entry that no longer applies.
|
|
69
|
+
|
|
70
|
+
Branches are tips: `build_history` gives a log its shape, `fold_path`
|
|
71
|
+
folds any branch of it. Session `state` ops fold separately, over
|
|
72
|
+
`state.json` (`fold_state`). `openworldformat.physics` carries the
|
|
73
|
+
`ext-physics` extension's executable half — the deterministic reference
|
|
74
|
+
solver, trajectory write/fold, and the outcome runner:
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
from openworldformat.physics import simulate_physics, fold_trajectories, run_outcomes
|
|
78
|
+
|
|
79
|
+
sim = simulate_physics(manifest, {"until_s": 6}) # deterministic
|
|
80
|
+
sim["contacts"] # impacts: {t_s, body, other, position, normal_speed}
|
|
81
|
+
sim["resting"] # where each dynamic body ended up
|
|
82
|
+
track = fold_trajectories(entries) # scrub recorded motion, no solver
|
|
83
|
+
run_outcomes(manifest, outcomes_doc) # the conformance assertions
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
The solver is deliberately minimal — spheres against floors and
|
|
87
|
+
axis-aligned statics, fixed 1/120 s semi-implicit Euler, sleep on rest —
|
|
88
|
+
so the conformance outcome assertions run anywhere and in CI.
|
|
89
|
+
Reference-grade, not production physics; deterministic within an
|
|
90
|
+
engine, semantic-only across engines, exactly as the core spec refuses
|
|
91
|
+
bit-exactness.
|
|
92
|
+
|
|
93
|
+
## Live authoring: agents outside, ops in
|
|
94
|
+
|
|
95
|
+
What a host does with an agent that wants to change the world:
|
|
96
|
+
`ingest` a batch against the fold — names bind to ids (a string where
|
|
97
|
+
an entity id goes is a name), a spawn without an id gets the next one,
|
|
98
|
+
partial transforms and materials merge with what's there, keys the
|
|
99
|
+
format would drop are refused with a path to each, and any failure
|
|
100
|
+
refuses the whole batch. The state you pass in is never touched:
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
from openworldformat import fold_log, ingest
|
|
104
|
+
|
|
105
|
+
done = ingest(state, [{"SpawnEntity": {"entity": {"name": "lamp", "parent": "crate"}}}])
|
|
106
|
+
done["ok"] # True
|
|
107
|
+
done["spawned"] # {"lamp": 3} — the ids the batch's names got
|
|
108
|
+
done["ops"] # the committed ops, bound: serialize into an entry and append
|
|
109
|
+
done["state"] # the new world; the old one is unchanged
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
`merge_patch` is the RFC 7396 helper the merges use; `manifest_text`
|
|
113
|
+
is the canonical pretty form an authority writes to `manifest.json` —
|
|
114
|
+
members sorted, nulls left out, entities by id, plain arrays inline —
|
|
115
|
+
so the same world is always the same bytes.
|
|
116
|
+
|
|
117
|
+
## Tasks: the benchmark harness
|
|
118
|
+
|
|
119
|
+
A task is a world, a trajectory, and a goal — a list of predicates over
|
|
120
|
+
what the fold produces. Scoring is therefore deterministic and needs no
|
|
121
|
+
engine: fold the log, evaluate the predicates. `examples/tasks/` turns
|
|
122
|
+
the repository's four example packages into a benchmark dataset, each
|
|
123
|
+
package's own log its solution:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
python -m openworldformat.eval examples/tasks/
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
ok the-drop-test: the switch scores (1 edits, 6 ops, 1 authors, revision 1)
|
|
131
|
+
ok forked-exploration: the moat variant wins this branch (3 edits, 4 ops, 3 authors, revision 4)
|
|
132
|
+
ok hello-world: hang the lantern (1 edits, 5 ops, 3 authors, revision 1)
|
|
133
|
+
ok speedrun-fork: noor's run, on its own branch (2 edits, 9 ops, 2 authors, revision 2)
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
A task file names the world and states the goal; a `tip` folds a branch
|
|
137
|
+
(a run, a variant) instead of the head; a budget caps the cost:
|
|
138
|
+
|
|
139
|
+
```json
|
|
140
|
+
{
|
|
141
|
+
"task": "hello-world: hang the lantern",
|
|
142
|
+
"world": "../../../examples/hello-world",
|
|
143
|
+
"budget": { "max_edits": 1, "max_entries": 5 },
|
|
144
|
+
"goal": [
|
|
145
|
+
{ "exists": { "entity": "lantern" } },
|
|
146
|
+
{ "near": { "entity": "lantern", "position": [-12.0, 0.0, 3.0], "tolerance": 0.5 } },
|
|
147
|
+
{ "field": { "name": "score.tour", "equals": 1 } }
|
|
148
|
+
]
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
| Predicate | Holds when |
|
|
153
|
+
|---|---|
|
|
154
|
+
| `{"exists": {"entity": name}}` | the fold holds an entity by that name |
|
|
155
|
+
| `{"gone": {"entity": name}}` | it doesn't |
|
|
156
|
+
| `{"near": {"entity", "position", "tolerance"=0.15}}` | the entity's folded position is within tolerance |
|
|
157
|
+
| `{"field": {"name", "equals"?, "at_least"?, "at_most"?}}` | the state document's value compares |
|
|
158
|
+
|
|
159
|
+
Budgets (`max_edits`, `max_ops`, `max_entries`, inclusive) are the cost
|
|
160
|
+
side of a task: solve it, but not by a million edits. Metrics report
|
|
161
|
+
the trajectory's shape — edits, ops, entries, authors (the audit
|
|
162
|
+
trail's model-vs-visitor filter is one field), span, revision.
|
|
163
|
+
|
|
164
|
+
To score an agent, don't write files at all — pass its ops to
|
|
165
|
+
`run_task` the moment it emits them:
|
|
166
|
+
|
|
167
|
+
```python
|
|
168
|
+
from openworldformat.eval import run_task
|
|
169
|
+
|
|
170
|
+
result = run_task(manifest, agent_entries, task, state_doc)
|
|
171
|
+
result["ok"], result["failures"], result["metrics"]
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
This task language is deliberately library-level, not a spec
|
|
175
|
+
extension; it graduates to `spec/extensions/` when a second implementer
|
|
176
|
+
wants it.
|
|
177
|
+
|
|
178
|
+
## Agents: the benchmark's other half
|
|
179
|
+
|
|
180
|
+
Scoring a recorded trajectory is one loop; scoring a live agent is the
|
|
181
|
+
same loop with the recording still wet. `run_agent` keeps the entries,
|
|
182
|
+
folds between steps so the agent observes its own edits, and scores
|
|
183
|
+
with `run_task`:
|
|
184
|
+
|
|
185
|
+
```python
|
|
186
|
+
from openworldformat.agent import run_agent
|
|
187
|
+
|
|
188
|
+
result = run_agent(manifest, task, state_doc) # template_agent inside
|
|
189
|
+
result["ok"], result["metrics"], result["entries"]
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
An agent is `f(document, values, task, entries) -> entry | None`: the
|
|
193
|
+
folded world and state values as observation, one entry of ops as
|
|
194
|
+
action, `None` to stop. The built-in `template_agent` is the baseline —
|
|
195
|
+
a compiler from goal predicates to ops, not a brain; it exists so
|
|
196
|
+
benchmark authors have a floor to beat and a skeleton to copy. Its
|
|
197
|
+
entries serialize to `ops.jsonl` like any recording: an agent run is a
|
|
198
|
+
log, ready to join a dataset.
|
|
199
|
+
|
|
200
|
+
## Dataset tooling: fold a corpus, compute one number
|
|
201
|
+
|
|
202
|
+
A folder of `.world` packages is a dataset — each `ops.jsonl` a
|
|
203
|
+
recording, each fold a row:
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
python -m openworldformat.dataset examples/
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
```
|
|
210
|
+
world entities edits ops entries authors tips span_s
|
|
211
|
+
forked-exploration 5 4 5 5 host, llm, maya 2 0.4
|
|
212
|
+
hello-world 14 1 5 5 llm, maya, visitor-7 1 1.877
|
|
213
|
+
speedrun-fork 9 2 15 4 kai, maya, noor 2 20.0
|
|
214
|
+
the-drop-test 7 1 6 2 host 1 0.2
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
The authors column is the audit trail's dimension — model, host and
|
|
218
|
+
visitor in one recording, separable by one field. The tips column
|
|
219
|
+
counts branches; fold each with `fold_path` and the counterfactuals
|
|
220
|
+
come with the corpus. `summarize(dir)` gives the row as a dict for
|
|
221
|
+
notebooks.
|
|
222
|
+
|
|
223
|
+
## API
|
|
224
|
+
|
|
225
|
+
| Export | What it does |
|
|
226
|
+
|---|---|
|
|
227
|
+
| `parse_manifest(text, strict=False)` | parse and version-check a world document (strict also enforces the schema's key sets) |
|
|
228
|
+
| `parse_log_line(line, strict=False)` | parse one `ops.jsonl` line, ops classified |
|
|
229
|
+
| `classify_op(op)` | recognize an op by shape — edits first |
|
|
230
|
+
| `op_kind_shape_ok(kind)` | the shape collision rule: edits PascalCase, history lowercase |
|
|
231
|
+
| `edit_ops(entry)` | an entry's edits, in order |
|
|
232
|
+
| `canonical_json(value)` | the canonical form for hashing — sorted, whitespace-free |
|
|
233
|
+
| `compute_entry_id(entry)` | an entry's content id, `sha256:<hex>` |
|
|
234
|
+
| `manifest_text(manifest)` | the canonical pretty text an authority writes to `manifest.json` |
|
|
235
|
+
| `fold_log(manifest, entries)` | the document at the last entry (the linear fold; by-name references bind to ids here, at ingestion) |
|
|
236
|
+
| `build_history(entries)` | a log's ids, parents, children and tips |
|
|
237
|
+
| `fold_path(manifest, entries, tip=None)` | the document at any tip (a branch) |
|
|
238
|
+
| `fold_state(state_doc, entries)` | the state document's values at the last entry |
|
|
239
|
+
| `compute_inverse(op, state)` | the inverse of one edit against the state it's about to change — undo is appending it |
|
|
240
|
+
| `merge_branch(state, entries)` | a branch's entries rewritten onto a main fold, colliding ids reallocated |
|
|
241
|
+
| `snapshot_filename(entry_id, revision)` | where a snapshot goes: by entry id, else by revision |
|
|
242
|
+
| `compact_package(package_json, head_revision)` | the package.json of a compaction |
|
|
243
|
+
| `read_package(world_dir)` | a head-first package: `(base, entries, head, package_json)` |
|
|
244
|
+
| `to_manifest(state)` | the fold's state as a whole manifest — `to_manifest(fold_log(m, []))` is `m` again |
|
|
245
|
+
| `ingest(state, batch)` | live authoring: bind, validate and apply a batch whole-or-refused; the state passed in is never touched; `warnings` for what validation warns about in the new world (a behavior whose target the batch deleted) |
|
|
246
|
+
| `merge_patch(current, change)` | JSON merge patch, RFC 7396 — the rule partial transforms merge by |
|
|
247
|
+
| `compact(world_dir, head_revision=None)` | move the base up to the head (or a revision): `snapshots/base.json` rewritten, the entries it holds archived |
|
|
248
|
+
| `ext_provenance(manifest)` | the provenance extension's five lineage fields, or None |
|
|
249
|
+
|
|
250
|
+
`openworldformat.physics` mirrors the npm package's
|
|
251
|
+
`openworldformat/physics`: `collect_physics`, `simulate_physics`,
|
|
252
|
+
`fold_trajectories`, `trajectory_op`, `run_outcomes`.
|
|
253
|
+
`openworldformat.cinematography` mirrors
|
|
254
|
+
`openworldformat/cinematography`: `camera_of`, `frame_of`, `view_of`,
|
|
255
|
+
`project`, `world_origin`, `aim_point_of`, `focus_distance_of`,
|
|
256
|
+
`shot_list`, `run_outcomes`.
|
|
257
|
+
`openworldformat.soundtrack` holds the soundtrack curves — `curve_at`,
|
|
258
|
+
`beat_at`, `section_at`, `modulation_factor` — as plain functions over
|
|
259
|
+
plain numbers, for analysis rather than playback.
|
|
260
|
+
`openworldformat.eval` scores tasks (see above): `run_task`,
|
|
261
|
+
`load_task_file`, and the `python -m openworldformat.eval` CLI.
|
|
262
|
+
`openworldformat.agent` runs agents against them: `run_agent` and the
|
|
263
|
+
`template_agent` baseline. `openworldformat.dataset` summarizes
|
|
264
|
+
recordings — `summarize` and the `python -m openworldformat.dataset`
|
|
265
|
+
report.
|
|
266
|
+
|
|
267
|
+
## Test
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
python -m unittest discover -s tests -t .
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
The suite mirrors the JS tests — it folds the repository's own example
|
|
274
|
+
packages, replays the drop-test recording through the solver, and runs
|
|
275
|
+
the conformance outcome assertions — so both references assert the same
|
|
276
|
+
facts.
|
|
277
|
+
|
|
278
|
+
Apache-2.0.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
openworldformat/__init__.py,sha256=15XrTQ5UeK_flXralR6FWSDeuC-EM11xljM378nA1G4,74489
|
|
2
|
+
openworldformat/agent.py,sha256=Gfi9SmLygZrzx1Ub-jxXCi3QTTHEAWLiwtSkHWXBDFk,6008
|
|
3
|
+
openworldformat/cinematography.py,sha256=RuvJocTn8itRzVZU4MgQ8ixz9Xw3tM1yOlTOzPLibCU,17123
|
|
4
|
+
openworldformat/dataset.py,sha256=wHAZR-GcgO0MpuJw8HquGJdLoDV_kKj2SvparMnw7FU,3075
|
|
5
|
+
openworldformat/entity_refs.py,sha256=Y7yLQVkdCRpiJJJtuATER-gvCN4N51PM3UWf_W0GLkk,1386
|
|
6
|
+
openworldformat/eval.py,sha256=giDCaezYl-uegD3ou8ZM5EW3qCnSz6LpFBWp_l5hm-Q,8887
|
|
7
|
+
openworldformat/physics.py,sha256=9kXSWUw2eyjvxnCINoOoNxdGi6PdoL5i-1NGInthdto,17264
|
|
8
|
+
openworldformat/soundtrack.py,sha256=0QeZ0EfC_yEDgPLjY2rZxbpeya7XcxsGxEY9hgeGyN4,3022
|
|
9
|
+
openworldformat-0.4.4.dist-info/METADATA,sha256=aks4v2SS3F-gUI2Dj3zRyPtGXBsFeNDv0F5I1M_YM8M,12704
|
|
10
|
+
openworldformat-0.4.4.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
11
|
+
openworldformat-0.4.4.dist-info/top_level.txt,sha256=80p_w3Q5qjS-v3VfN0PwnqKg4cP2WJhMQAZsCiUtZEc,16
|
|
12
|
+
openworldformat-0.4.4.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
openworldformat
|