Skip to content

SalatielSauer/OGZ-Editor

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

34 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

OGZ-Editor

A browser tool for writing Sauerbraten .ogz files (maps) using JSON.
https://salatielsauer.github.io/OGZ-Editor/

Updates (07/10/2023)

  • A more simplified and faster version of the JSOCTA syntax is now available, to use it simply set the version property to 2.

Updates (12/08/2023)

  • Cube corners can be manipulated with the edges property. (Corner Editing >)
  • Cubes can be placed in specific positions if defined inside the prefab array and have the position property set. (Cube Positioning >)
  • Blocks in the editor are highlighted when their endpoints are selected.
  • The map is now read correctly having mapversion set to 33.

Map Variables

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

Version 1:

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]
  }
]

Version 2:

With the version property set to 2, you can use the alternative syntax below for entities:

"entities": [
  {"x": 512, "y": 512, "z": 512, "t": 2, "at1": 23}
]

This will add a single entity of type 2 ("mapmodel") with attribute 1 set to 2 (carrot) at position 512 512 512.

The list of available entity properties are: x y z t at0 at1 at2 at3 at4, the list of available types can be found here.

Octree Editing

Version 1:


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.

Subdivisions

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.

Cube Positioning

To add a cube at a specific position you can create an object containing the prefab array followed by the list of cubes and their position and gridpower properties.

"geometry": [
  {"prefab": [
    {"solid": {
      "position": [256, 256, 256],
      "gridpower": 4
    }}
  ]}
]

You can merge both the manually defined octree structure and the prefab array:

"geometry": [
  "solid", "solid", "solid", "solid",
  {"prefab": [
    {"solid": {
      "position": [256, 256, 256],
      "gridpower": 4
    }}
  ]}
]

The object containing the prefab is not treated as part of the 8 items in the geometry array, so it can be added as a ninth item.

Textures

To add textures you can create an object 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.

Corner Editing

Similar to textures, to manipulate corners you can set the edges property of the object:

"geometry": [
  {"solid": {
    "edges": {
      "top": [1, 2, 3, 4]
    }
  }}
]

Each number is a corner of the face, the order of the corners are: upper-left upper-right lower-left lower-right. Each corner can be pushed a total of 8 times, 0 means no push. As a reference, you can find the front face when the origin box is in the lower left corner of the selection.

Version 2:

With the version property set to 2, you can use the alternative syntax below for octree manipulation:

"geometry": [
  {"g": 5, "x": 512, "y": 512, "z": 512, "ft1": 5, "af": 2}
]

This will add a grass cube of gridpower 5 (g) with the top-right corner of the front face (ft1) pushed 5 times.
Some of the available properties for cubes are: g t af tp bk lf rt dn ....
g defines the cube gridpower/size (0 = 1x1, 1 = 2x2, 2 = 4x4...);
t defines the cube type (1 "solid" by default);
af determine the texture index for all faces;
tp and all subsequent properties determine the texture index for that face;
faces can be followed by a corner index from 0 to 3, which determine its push level.


JSOCTA

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).

Classes

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.

Common Methods

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.

NodeJS Module

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())

Getting the OGZ file

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)
  }
)

JSOCTA

  • Support mapversion 33
  • Read and convert octa to .json
  • Process and convert .json to octa
    Mapvars
    • Integer, Float and String mapvars
    • Convert RGB array to decimal
    Entities
    • Support all entities
    • Support multiple entities of the same type
    • Support negative values of entity attributes
    Octree
    • Orderly Octree editing & Textures
    • Support cube insertion at a specific coordinate and size (the OctaGeometry.insert() method)
    • Support for copying and pasting geometry chunks
    • 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)
    • Virtual Slots
    • Lightmaps
    • Blendmaps

OGZ Editor

  • 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 (@jes) for his very helpful documentation regarding version 29 of the Sauerbraten map format.