Quake .map support for Godot

Quake .map file support for Godot.

Documentation

Consult the Qodot User Guide.

Overview

Qodot extends the Godot editor to import Quake .map files, and provides a data-driven framework for converting the entities and brushes contained therein into a custom node hierarchy.

Features

  • Natively import .map files into Godot and convert them into a usable scene tree
  • Supports
    • Brush geometry
    • Textures and customized UVs
    • Convex and concave collision volumes
    • Gameplay entities
    • FGD (Forge Game Data) export for custom game definitions
  • Configurable scene population
    • Leverages the map format's classname and key/value property systems
    • Spawn and configure custom Godot scenes and scripts based on entities defined in the map editor
    • Define the visual and collision properties of brush entities on a per-classname basis
  • TrenchBroom Integration
    • Simple, intuitive map editor with a strong feature set
    • TrenchBroom game configurations can be exported for tighter workflow integration
    • Nested TrenchBroom groups can be used to build a tree hierarchy from the format's standard flat structure

Showcase

Assorted props by @SunkPer

Summer Island by @SunkPer

Thesis

Qodot was created to solve a long-standing problem with modern game engines: The lack of simple, accessible level editing functionality for users without 3D modeling expertise.

Unity, Unreal and Godot are all capable of CSG to some extent or other with varying degrees of usability, but lack fine-grained direct manipulation of geometry, as well as per-face texture and UV manipulation. It's positioned more as a prototyping tool to be used ahead of a proper art pass than a viable methodology.

Conversely, dedicated 3D modeling packages like Maya or Blender are very powerful and can iterate fast in experienced hands, but have an intimidating skill floor for users with a programming-focused background that just want to build levels for their game.

Enter the traditional level editor: Simple tools built for games like Doom, Quake and Duke Nukem 3D that operate in the design language of a video game and are created for use by designers, artists and programmers alike. Thanks to years of community support, classic Quake is still alive, kicking, and producing high-quality content and mapping software alike. This continued popularity combined with its simplicity means the Quake .map format presents a novel solution.

Example Content

Various example scenes with inline README nodes are available inside the plugin folder to demonstrate each aspect of Qodot's functionality.

Extra Content

The Qodot extra content repository contains a set of additional resources, such as map editor plugins, logo graphics, showcase content and screenshots.

Qodot Elsewhere

Discord - Qodot

Reddit - Qodot

Godot Forums - Qodot

Godot Asset Library - Qodot

Shifty's Twitter

Credits

Kristian Duske - For creating TrenchBroom and inspiring the creation of Qodot

Arkii - For example code and handy documentation of the Valve 220 format

TheRektafire - For a variety of useful tidbits on the .map format

Ember - For creating the user guide

Calinou - For making Qodot work on case-sensitive systems

SunkPer - For showcase screenshots

lordee, DistractedMOSFET and winadam - For laying the groundwork of the FGD export and entity scripting systems.

fossegutten - For a typed GDScript pass

Corruptinator - For the idea of using TrenchBroom groups as a scene tree.

grenappels - For implementing smoothed brush normal edge splitting

FreePBR.com - For royalty-free PBR example textures

Owner
Qodot
Quake ,map support for Godot
Qodot
Comments
  • libqodot fails to find libmap on Unix systems

    libqodot fails to find libmap on Unix systems

    Can't open dynamic library: /home/kj/Nextcloud/Gamedev/godot/the-complex-project/addons/qodot/bin/x11/libqodot.so. Error: libmap.so: cannot open shared object file: No such file or directory

    To reproduce:

    • create new project
    • put addons/
    • run Godot

    I did this on old projects, new one. I downloaded release zip, compiled myself (using LLVM). Still the same error.

  • Implement mesh splitting for better frustum culling effectiveness and displaying more lights simultaneously

    Implement mesh splitting for better frustum culling effectiveness and displaying more lights simultaneously

    After a discussion with someone on the #godotengine IRC, it seems Qodot doesn't support mesh splitting (or we haven't found it, at least). Mesh splitting allows for greater frustum culling effectiveness, on top of being able to render more than 8 Omni/SpotLghts for the whole level.

    Is there such an option in Qodot?

  • Occlusion Culling

    Occlusion Culling

    Should Qodot have its own system for this, since Godot doesn't have anything built-in as of 3.1?

    My initial reaction is that building a solution to operate in more general Godot terms would be a better time investment, since each brush gets converted into a standard MeshInstance using an ArrayMesh to hold vertex data.

    However, under the current model culling would have to be AABB / Box-Sphere based based, since you can't toggle visibility per face.

    A better solution, and one that would take advantage of the .map format in a similar way Quake does, would be to instead create one mesh per brush face. That way each face could update its visibility separately based on simple point-in-frustum + normal-dot-camera checks.

    It would be better if ArrayMesh offered the ability to selectively show/hide its component surfaces, but that doesn't appear to be a thing. Could store the vertices in an array somewhere and filter them into the ArrayMesh based on visibility, but that seems like it would be a lot of data-thrashing vs the multiple mesh solution.

  • First pass at entity definition system.

    First pass at entity definition system.

    I whipped this up for my own uses but might as well offer it back to the project. There's still enhancements that can be done but it is usable. There's probably some last things I'll tweak/investigate but I thought I'd open the PR now to get feedback sooner rather than later.

    This PR adds two new qodot nodes: QodotEntityDefinition and QodotEntityDefinitionSet. These two are used to build a scene that describes a set of entity defs you want to export to a FGD for use in TrenchBroom. The idea is straight forward enough: make a new scene, make the parent node a QodotEntityDefinitionSet. Add QodotEntityDefinition children. Set the exported variables on each definition appropriately, the most important detail is to set the path to a corresponding subscene file that you want to use as an entity. After adding your children, set the export file path on the QEDS to the FGD you want to write over, and use the pseudo-button to export it.

    The exported entities are currently pretty simple. Notably there is no exported mesh or icon.

    To use an entity definition set in a QodotMap, there is a new exported variable on Qodotmap to select a QEDS file. When you reload the map the entities that are recognized within your selected QEDS will be replaced with instanced child scenes.

    A particular thing I'd like feedback on is my use of the InstancedScene class in build_entity_spawns_step.gd. Fundamentally the problem I was encountering there was trying to communicate to qodot_map that this node was an instanced subscene. This is relevant because qodot_map resets the ownership of added nodes recursively. This causes all the subscenes children to be injected in the scene too, which is confusing compared to standard Godot behaviour. I am not sure if there is a more ideal way to communicate that information back up the call tree, so I thought I'd just ask.

    Another small detail is that I've opted simply to use UNIX-style '\n' newlines in the exporting FGD. But that might be in-ideal for Windows users. GDScript doesn't seem to offer a straight forward way of getting the current platform's newline value. I'm open to suggestions on what/if to do anything about it.

  • I should launch Godot as root to see Qodot nodes, strange no ?

    I should launch Godot as root to see Qodot nodes, strange no ?

    Hi Qodot community :)

    I have a strange behavior on my Fedora... I have installed all requirement to launch Qodot and Trenchbroom on my system but after launch the scripts :

    • qodot_trenchbroom_config_file.tres
    • qodot_trenchbroom_config_folder.tres I correctly generate my Trenchbroom configurations but if I am not root I can't see the Qodot nodes :/

    as user : image

    as root : image

    Have you an idea with this problem, it's only a permission problem ? Thanks for your help :)

  • libmap crash under Arch and Manjaro

    libmap crash under Arch and Manjaro

    From @varkatope:

    Starting program: /home/varkatope/Desktop/qodot_debug_test/qodot.x86_64 qodot.x86_64
    [Thread debugging using libthread_db enabled]
    Using host libthread_db library "/usr/lib/libthread_db.so.1".
    [New Thread 0x7ffff7fcd700 (LWP 9956)]
    Godot Engine v3.2.stable.official - https://godotengine.org
    [Detaching after fork from child process 9957]
    [Detaching after fork from child process 9974]
    [New Thread 0x7fffe9709700 (LWP 9991)]
    [New Thread 0x7fffe8f08700 (LWP 9992)]
    [New Thread 0x7fffe3fff700 (LWP 9993)]
    [New Thread 0x7fffe37fe700 (LWP 9994)]
    [New Thread 0x7fffe2ffd700 (LWP 9995)]
    [New Thread 0x7fffe27fc700 (LWP 9996)]
    [New Thread 0x7fffe1ffb700 (LWP 9997)]
    [New Thread 0x7fffe17fa700 (LWP 9998)]
    [New Thread 0x7fffe0ff9700 (LWP 9999)]
    [New Thread 0x7fffbffff700 (LWP 10000)]
    [New Thread 0x7fffbf7fe700 (LWP 10001)]
    [New Thread 0x7fffbeffd700 (LWP 10002)]
    [New Thread 0x7fffbe7fc700 (LWP 10003)]
    [New Thread 0x7fffbdffb700 (LWP 10004)]
    [New Thread 0x7fffbd7fa700 (LWP 10005)]
    [New Thread 0x7fffbcff9700 (LWP 10006)]
    [New Thread 0x7ffff6623700 (LWP 10007)]
    OpenGL ES 3.0 Renderer: AMD RAVEN (DRM 3.36.0, 5.5.2-1-MANJARO, LLVM 9.0.1)
    [New Thread 0x7fffe8066700 (LWP 10008)]
    [New Thread 0x7fffe0577700 (LWP 10009)]
     
    Building /home/varkatope/GameDevelopment/qodot-example/maps/metal-arch.map
    
    build_map
    remove_children
    Done in 0.000311 sec
    
    load_map
    
    Thread 1 "qodot.x86_64" received signal SIGSEGV, Segmentation fault.
    0x00007ffff4023951 in map_parser_load (map_file=0x411cb30 "/home/varkatope/GameDevelopment/qodot-example/maps/metal-arch.map") at libqodot/libmap/src/c/map_parser.c:115
    115	    comment = false;
    

    libmap appears to be segfaulting a couple of lines after map_data_reset, reset_current_face, reset_current_brush and reset_current_entity are called by map_parser_load after a load is invoked by libqodot.

    Given that we have another user (@MissLav) who's tested the new native core under Manjaro, I'm not sure what's going on here. I've stepped through the aforementioned functions with a debugger, and all of the dynamic memory logic that could cause a segfault is being skipped as expected of a first-run scenario.

  • Float-format support for light color

    Float-format support for light color

    In build_entity_spawns.gd color is treated with ints but the default floats is what is needed.

    It is like this : var red = int(comps[0]) / 255.0

    and must become like this: var red = float(comps[0])

  • Use a license more suited to code

    Use a license more suited to code

  • TrenchBroom game definition export from Godot

    TrenchBroom game definition export from Godot

    Ideally the user should be able to export a ready-to-go TrenchBroom config for their game, complete with a custom set of entity and face definitions defined within the editor.

    This would require a custom resource for the game definition containing an icon (to be resized to 32x32), the data for GameConfig.cfg, and the data for a game-specific .fgd file.

    FGD stands for 'Forge Game Data' and is an extension for Hammer's game definition files. Spec is available here: https://developer.valvesoftware.com/wiki/FGD

  • Fix base classes and default values

    Fix base classes and default values

    During the 'fetch_entity_definitions' build step, the qodot-plugin is only considering 1 level of base class hierarchy when merging properties into the entity. I believe FGD supports a multi-level hierarchy, so shouldn't all base classes be traversed while merging in properties?

    In addition, when the 'apply_properties' build step is executed, only existing properties are evaluated - and properties defined in the entity definition are ignored. Unassigned properties - at least in TrenchBroom - are assumed to be 'default' value. Therefore, shouldn't missing/unassigned properties be set to the defaults defined in the entity definition?

  • How To Setup Qodot On Linux?

    How To Setup Qodot On Linux?

    Good day,

    I am very new to Godot development and came across Qodot as being a very good alternative to Blender.

    I read the Wiki but I still don't understand what the Qodot_Trenchbroom_Config_Folder.tres or how to open it from within Godot or even where to move it.

    My goal here is to be able to create a Qodot project in Trench Broom, to export it and to import it into Godot.

    Could someone help me out?

    Thank you!

  • the length of string of all enabled textures folders paths together must be smaller than 255 characters

    the length of string of all enabled textures folders paths together must be smaller than 255 characters

    from mrezai on discord — 20/06/2022 04:37

    The issue in textures isn't about count of textures but it's related to how many texture folders added to trenchbroom. texture folder paths will be saved in "_tb_textures" property in the map file and if the length of its value become greater than 255 characters then stack overflow and crash will be happened in the map file parsing.

  • Allow option to build and keep all brushes as separate static bodies and meshes

    Allow option to build and keep all brushes as separate static bodies and meshes

    Currently, the entire map is a single combined body but some games would benefit from having each brush as a separate static body and mesh so occlusion culling can be used and different colliders can be differentiated. This will also allow users to specifically change textures and materials in engine so they can use TrenchBroom purely for level design.

  • WAD textures with name containing upper case characters are not applied to mesh materials

    WAD textures with name containing upper case characters are not applied to mesh materials

    Given

    • A MAP file which has attribute "wad".
    • A QodotMap scene instance which references this MAP and its corresponding WAD file referenced by that attribute.
    • This WAD file contains a texture which has a name which contains at least one uppercase character.

    When

    • Building this QodotMap in Godot.

    Then

    • Meshes which are expected to get a material which references such a texture name are not given such.

    It seems to be a convention that WAD texture names are lowercase but I suspect it is not a rule. Both Trenchbroom & TexMex support such. I encountered this problem when trying to use Valve's cs_dust.wad, which contains texture names like "SandRoad".

    I have a fix for this problem by modifying qodot_texture_loader.gd::load_texture to not apply "to_lower" to the texture_name parameter before searching for this name as a key in texture_wad_resources' textures. I think this fix is sound because observing the dictionaries of loaded WADs in Godot show that the texture names are still in their original form (not forced into their lowercase form).

    I don't know if there is some other use case which requires this string manipulation. Perhaps an earlier developer was catering to a case where a MAP file contained a texture name with mixed case whereas the WAD file did not and it was expected that they should match up. At any rate, that's not a valid normalization of naming because as I mentioned before, Qodot in the least is allowing texture names to be mixed case when loading a WAD. It's also worth mentioning that TexMex allows another texture in the same WAD to have the same name in a different case. However, I didn't text if Quake had a problem with such a thing--I don't know what client, editor, or compiler that may have created this precedent. Skimming the WAD2 specification, I didn't see anything that indicated such.

    But if this behavior is to be retained, first a check for texture_name in texture_wad.textures can be performed prior to texture_name_lower.

  • 'Filter' texture flag defaults to 'on' when using new textures and rebuilding

    'Filter' texture flag defaults to 'on' when using new textures and rebuilding

    I'm currently using pixellated graphics in my project and I've noticed that rebuilding a map in Godot causes the newly added textures' filters to default their 'Filter' flag to 'On' even though it was deliberately turned 'Off' when imported into Godot(I know because I set them manually). This behavior does not occur on subsequent rebuilds after re-setting the flag back to 'Off'(it only happens to textures newly added to the texture collection in TrenchBroom), but it's a little annoying.

    Steps to reproduce:

    1. Import a texture into Godot(in my case I use .PNG files), placing it into TrenchBroom's designated textures folder.
    2. Set the texture's 'Filter' flag to 'Off'.
    3. Refresh the texture collections in Trenchbroom and use the new texture in the current map. Save the file.
    4. In Godot, press 'Quick Build' or 'Full Build' to rebuild the map.
    5. Check the texture's flags(you may need to click on a different one and then back again to refresh the Import tab's display).
    6. the flag will be defaulted to 'On'. You can turn it off and re-import it and it will behave normally.

    Godot v3.4.4.stable.official [419e713a2] Qodot 1.7.1 TrenchBroom v2021.1 (release Linux)

  • Worldspawn layers cant share textures with brush entities

    Worldspawn layers cant share textures with brush entities

    I'm using Worldspawn layers to associate footstep sounds to different surfaces (textures).

    I wanted to create a brush entity that acts like a secret door (same texture as the surrounding wall/floor) but I discovered that Qodot either:

    • fails to create the brush entity (missing CollisionShape) if the worldspawn layer contains at least 1 brush.

    • crashes while building the map if the only brush using the texture is the BrushEntity with this error

    res://addons/qodot/src/nodes/qodot_map.gd:851 - Invalid type in function 'add_surface_from_arrays' in base 'ArrayMesh'. Cannot convert argument 2 from Nil to Array.
    
    qodot.gather_worldspawn_layer_surfaces(texture, brush_clip_texture, face_skip_texture)
    

    I suspect the problem lies in this libqodot line

    I think it should only consider the worldspawn classname while ignoring other brush entities.

    But I'm not familiar enough with C and libqodot to investigate it more.

skipmap is a high-performance concurrent sorted map based on skip list. Up to 3x ~ 10x faster than sync.Map in the typical pattern.
skipmap is a high-performance concurrent sorted map based on skip list. Up to 3x ~ 10x faster than sync.Map in the typical pattern.

Introduction skipmap is a high-performance concurrent map based on skip list. In typical pattern(one million operations, 90%LOAD 9%STORE 1%DELETE), th

Jan 8, 2023
Recursively searches a map[string]interface{} structure for another map[string]interface{} structure

msirecurse Recursively searches a map[string]interface{} structure for existence of a map[string]interface{} structure Motivation I wrote this package

Mar 3, 2022
Grpc-gateway-map-null - gRPC Gateway test using nullable values in map

Demonstrate gRPC gateway behavior with nullable values in maps Using grpc-gatewa

Jan 6, 2022
Kakoune syntax highlighting for the Godot Engine / Godot Scripting Language gdscript
Kakoune syntax highlighting for the Godot Engine / Godot Scripting Language gdscript

gdscript-kak Kakoune syntax highlighting for the Godot Engine / Godot Scripting Language gdscript. Adds basic syntax highlighting to your .gd files fo

Mar 2, 2021
:steam_locomotive: Decodes url.Values into Go value(s) and Encodes Go value(s) into url.Values. Dual Array and Full map support.

Package form Package form Decodes url.Values into Go value(s) and Encodes Go value(s) into url.Values. It has the following features: Supports map of

Dec 26, 2022
Dec 28, 2022
Database Abstraction Layer (dbal) for Go. Support SQL builder and get result easily (now only support mysql)

godbal Database Abstraction Layer (dbal) for go (now only support mysql) Motivation I wanted a DBAL that No ORM、No Reflect、Concurrency Save, support S

Nov 17, 2022
Replacement of ApacheBench(ab), support for transactional requests, support for command line and package references to HTTP stress testing tool.

stress stress is an HTTP stress testing tool. Through this tool, you can do a stress test on the HTTP service and get detailed test results. It is ins

Aug 23, 2022
🎨 Terminal color rendering library, support 8/16 colors, 256 colors, RGB color rendering output, support Print/Sprintf methods, compatible with Windows.
🎨 Terminal color rendering library, support 8/16 colors, 256 colors, RGB color rendering output, support Print/Sprintf methods, compatible with Windows.

?? Terminal color rendering library, support 8/16 colors, 256 colors, RGB color rendering output, support Print/Sprintf methods, compatible with Windows. GO CLI 控制台颜色渲染工具库,支持16色,256色,RGB色彩渲染输出,使用类似于 Print/Sprintf,兼容并支持 Windows 环境的色彩渲染

Dec 30, 2022
A thread safe map which has expiring key-value pairs

~ timedmap ~ A map which has expiring key-value pairs. go get github.com/zekroTJA/timedmap Intro This package allows to set values to a map which will

Dec 29, 2022
An in-memory string-interface{} map with various expiration options for golang

TTLCache - an in-memory cache with expiration TTLCache is a simple key/value cache in golang with the following functions: Expiration of items based o

Jan 8, 2023
A prefix-enhanced map in Go

PrefixMap PrefixMap is a prefix-enhanced map that eases the retrieval of values based on key prefixes. Quick Start Creating a PrefixMap // creates the

Jun 13, 2022
Decode / encode XML to/from map[string]interface{} (or JSON); extract values with dot-notation paths and wildcards. Replaces x2j and j2x packages.

mxj - to/from maps, XML and JSON Decode/encode XML to/from map[string]interface{} (or JSON) values, and extract/modify values from maps by key or key-

Dec 22, 2022
Fast, efficient, and scalable distributed map/reduce system, DAG execution, in memory or on disk, written in pure Go, runs standalone or distributedly.

Gleam Gleam is a high performance and efficient distributed execution system, and also simple, generic, flexible and easy to customize. Gleam is built

Jan 1, 2023
Fast, efficient, and scalable distributed map/reduce system, DAG execution, in memory or on disk, written in pure Go, runs standalone or distributedly.

Gleam Gleam is a high performance and efficient distributed execution system, and also simple, generic, flexible and easy to customize. Gleam is built

Jan 5, 2023
Map, Reduce, Filter, De/Multiplex, etc. for the Go language.

proto proto gives Go operations like Map, Reduce, Filter, De/Multiplex, etc. without sacrificing idiomatic harmony or speed. It also introduces a conv

Nov 17, 2022
Convert struct, slice, array, map or others for Golang

XConv zh-CN XConv is a golang type convertor. It convert any value between types (base type, struct, array, slice, map, etc.) Features Convert between

Dec 8, 2022