i love the source engine. even more, i love its level editor, hammer. i think it's the last level editor that exists. i want an experience similar to it, because making game levels in something like blender frankly sucks. so a while back, i started writing down a kind of spec for a game-agnostic level editor. i don't think i'm going to work on it any time soon, but it's a neat idea i think and worth exploring at some point.
- hammer but modern
- generic, not tied to any engine
- main save format is bespoke, but can export to gltf and obj (only geo)
- two types of primitives, brush and point entity
- entities can be brush or point
- brush editing tools (that part sucks :( )
- entities can have simple keyvalues and attributes, which are also keyvalues with an expression language
an example of attributes is I/O. attributes follow a schema with an expression language that allows them to be constrained. in i/o this is useful for defining an entity's inputs and outputs and then being able to make sure the attribute's value (eg input to fire) is an input of the target entity. therefore, attribute values can be any type, including full objects. eg:
code block{
//... rest of entity def
"attributes": [
{
"name": "outputs",
"kind": "fields", // how to edit this attribute ("fields" will show an editable window similar to the entity kv inspector and store them as an array)
"value": [
{
"output": "OnStartOpen",
"targetname": "$TARGETNAME$",
"input": "$ONE(ent(targetname).attributes.inputs)$",
"data": "",
"delay": 0.0,
}
]
},
{
"name": "inputs",
"kind": "data", // "data" kind is not saved in the map file, it's just for reference
"value": [
"Open", "Close"
]
}
]
}entity def:
code block{
"classname": "info_player_start",
"kind": "point", //"point"|"solid"|"any" - "any" is most useful for base classes
"base": [], // Array<EntityDef> - will inherit kv's and attributes from base classes
"position": "", // vec3
"rotation": "", // vec3
"scale": "", // vec3
"kv": {
"team": {
"type": "enum_string",
"value": "Red,Blue,None",
"default": "None",
},
"start_enabled": {
"type": "bool", // simple types don't need the value key
"default": true,
}
},
"attributes": [ // see above
{
"name": "outputs",
"kind": "fields",
"value": [
{
"output": "OnSpawn",
"targetname": "$TARGETNAME$",
"input": "$ONE(ent(targetname).attributes.inputs)$",
"data": "",
"delay": 0.0,
}
]
}
]
}example of a saved entity:
code block{
"classname": "info_player_start",
"kv": {
"team": "Red",
"start_enabled": true // kv's with default fields are still saved to be able to open maps without a gamedef
},
"attributes": {
"outputs": [
{
"output": "OnSpawn",
"targetname": "some_door",
"input": "Open",
"data": "",
"delay": 0.5,
}
]
}
}gizmos are attributes:
code block{
"name": "radius",
"kind": "sphere_gizmo",
"value": [
{
"default": 1.0,
"controlling_kv": "radius", // editing the radius kv will edit the gizmo, and editing the gizmo will edit the radius kv
}
]
} i'm not settled at all on most of this. one thing i really like about Trenchbroom is the expression language, so i want to have something like it in the entity definition files. i think instead of interpolating it in something like "$FUNC$" i'd rather go with {{expr}}.
i know also that i strongly want to have an engine-agnostic input/output system, as provided in the first few examples. it should be possible to express level logic without leaving the level editor.
it could be argued that this should be part of the engine for whatever game you're working on, but a game engine allows less assumptions to be made than a separate app i think.
im Normal and you'r NOT.
bear that in mind.