A browser tool for writing Sauerbraten .ogz files (maps) using JSON.
https://salatielsauer.github.io/OGZ-Editor/
To apply mapvars you must pay special attention to their types, strings must be enclosed in double quotes and RGB colors must be defined as arrays.
"mapvars": {
"maptitle": "a beautiful map",
"atmo": 1,
"cloudlayer": "skyboxes/clouds01",
"cloudfade": 0.9,
"cloudscrollx": 0.01,
"sunlight": [255, 100, 255]
}
Entities have two array properties: position
and attributes
, the position receives the XYZ values and the attributes vary depending on the entity, but the first index is always its type.
"entities": [
{
"position": [512, 512, 512],
"attributes": ["mapmodel", 0, 0, 0, 0, 0]
}
]
For entity colors you can use the short hex string or an RGB array.
"entities": [
{
"position": [512, 512, 512],
"attributes": ["particles", 0, 0, 0, "0xFFFF", 0]
},
{
"position": [512, 512, 528],
"attributes": ["particles", 0, 0, 0, [255, 100, 255], 0]
}
]
On a size 10 map (1024x1024) the standard subdivision consists of 8 smaller cubes of size 512x512, and each of them can be subdivided into 8 more cubes.
The octree of a newmap has the following structure:
"geometry": [
"solid",
"solid",
"solid",
"solid",
"empty",
"empty",
"empty",
"empty"
]
All children are divided into a lower and an upper layer, these layers consist of 4 cubes each.
To create a subdivision in a child, add a new list within the previous list:
"geometry": [
"solid",
"solid",
"solid",
"solid",
"empty",
[
"empty",
"empty",
"solid",
"empty",
"empty",
"empty",
"solid",
"empty"
],
"empty",
"empty"
]
Each list reduces the size of the cube in half, that is, a subdivision of a 512x512 cube will create 8 new 256x256 cubes within it.
The gif below shows a size 10 map with its first "chunk" subdivided once.
The non-optimized structure (before remip or calclight) would look like:
"geometry": [
[
"solid",
"solid",
"solid",
"solid",
"solid",
"solid",
"solid",
"solid",
],
"solid",
"solid",
"solid",
"empty",
"empty",
"empty",
"empty"
]
There are some tricks to reduce the number of children, so when executing /remip
unnecessary subdivisions are removed or converted to pushed faces.
Although Sauer requires the entire Octree filled, even with empty cubes, you don't have to worry about specifying them manually as shown above, JSOCTA will fill all the missing space.
To add textures you can create an object within the list and define its textures
property:
"geometry": [
{"solid": {
"textures": [1, 2, 3, 4, 5, 6]
}}
]
Each number is an index of a registered texture (the textures of the F2 menu in game). Their positions determine which face of the cube it will be applied to: left right back front bottom top. Undefined faces will inherit the last texture, to have an "allfaces" effect you only have to set the first texture.
"geometry": [
{"solid": {
"textures": [9]
}}
]
Cubes added without a texture property will inherit the last texture from the last cube.
Detailed cube manipulation is not yet supported.
JSOCTA is what powers OGZ Editor, it consists of functions that read, format and convert the contents of a JavaScript object to a valid OGZ.
You can easily install jsocta.js on your own page with the script tag:
<script src="jsocta.js"></script>
or in NodeJS:
const jsocta = require("./scripts/jsocta.js")
If you don't have NodeJS installed and want to do more than what OGZ-Editor provides, you can access all classes and methods using your browser's developer tools console (F12 while on the OGZ-Editor page).
JSOCTA has the following classes:
-
new OctaMap(object)
The main class, it formats the converted result of all other classes respecting the OCTA structure. -
new OctaMapvars(object)
Handles the formatting and conversion of the map variables object. -
new OctaEntities(array)
Handles the formatting and conversion of the map entities array. -
new OctaGeometry(array)
Handles the formatting and conversion of the map octree array.
All the above classes have the following methods:
.format(object)
Converts a single item and returns it as a string array..getStringArray()
Converts and returns all (string) items as an array..getString()
Converts and returns all items as a concatenated string..getByteArray()
Converts, concatenates and returns all items as a byte array.
module.exports
has the classes in the following properties:
Map: OctaMap,
MapVars: OctaMapvars,
Entities: OctaEntities,
Geometry: OctaGeometry
to access them just require
the jsocta.js file:
const jsocta = require(".scripts/jsocta.js")
console.log(new jsocta.Mapvars({}).getString())
To get a valid ogz you need to compress the value of .getByteArray()
using gzip.
Browser pako.gzip
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pako/2.0.3/pako.min.js"></script>
<script src="scripts/jsocta.js"></script>
</head>
<body>
<script>
console.log(
pako.gzip(
new OctaMap({
"mapvars": {"maptitle": "map generated with the browser"},
"geometry": ["solid", {"solid": {"textures": [3]}}]
}).getByteArray()
)
)
</script>
</body>
NodeJS zlib.gzip
const zlib = require("zlib")
const jsocta = require("./scripts/jsocta.js")
zlib.gzip(
new jsocta.Map({
"mapvars": {"maptitle": "map generated with nodejs"},
"geometry": ["solid", {"solid": {"textures": [3]}}]
}).getByteArray(), (error, result) => {
console.log(result)
}
)
- Support latest mapversion (version 29 is the only one documented)
- Read and convert octa to .json
- Process and convert .json to octa
- Integer, Float and String mapvars
- Convert RGB array to decimal
- Support all entities
- Support multiple entities of the same type
- Support negative values of entity attributes
- Orderly Octree editing & Textures
- Support cube insertion at a specific coordinate and size (the
OctaGeometry.insert()
method) - Fill undefined space with empty cubes
- Inherit last texture from previous added cube
- Complex shapes (edges/corners editing)
- Materials (alpha, clip, death, gameclip, lava, noclip, water)
- Lightmaps
- Blendmaps
- JSON syntax highlighting
- JSON error feedback
- Tab & Shift+Tab indentation
- Option to save the file directly to disk without downloading (and CTRL+S shortcut)
OGZ Editor & JSOCTA by Salatiel S.
Special thanks to James Stanley for his very helpful documentation regarding version 29 of the Sauerbraten map format.