Add project files.

This commit is contained in:
alejo committed 2026-10-25 03:29:04 -03:00
commit a9ae435321
52 files changed
+65378

No files matched your search

+188
View File
@@ -0,0 +1,188 @@
#include "hmap/hmap.h"
#include <cstdio>
#include <cstdlib>
#include <sstream>
namespace hmap {
namespace {
const char* kBuiltin = R"DEF(
# Hammer++ built-in entity definitions (same syntax as assets/entities.def)
# @point|@brush <class> "<label>" [color(r,g,b)] [size(h)|size(hx,hy,hz)] [dir] [model] [contents(solid|clip|trigger|water|sky)]
# <key> <type> "<label>" "<default>" ["a=Label A,b=Label B"] (types: string int float bool color255 vec3 choice model material target)
@point info_player_start "Player start" color(70,230,90) size(16,36,16) dir
@point info_target "Target / marker" color(190,190,190) size(6)
@point light "Point light" color(255,225,110) size(6)
color color255 "Color" "255 240 215"
intensity float "Intensity" "1.0"
radius float "Radius" "512"
@point light_spot "Spot light" color(255,190,90) size(6) dir
color color255 "Color" "255 240 215"
intensity float "Intensity" "1.2"
radius float "Radius" "768"
cone_inner float "Inner cone (deg)" "25"
cone_outer float "Outer cone (deg)" "40"
@point light_environment "Sun / environment" color(255,205,70) size(10) dir
color color255 "Sun color" "255 244 222"
intensity float "Intensity" "0.9"
ambient color255 "Ambient" "42 46 58"
@point prop_static "Static prop" color(120,170,255) size(16) model
model model "Model" ""
solid bool "Collide" "1"
tint color255 "Tint" "255 255 255"
@point prop_dynamic "Dynamic prop" color(110,210,255) size(16) model
model model "Model" ""
solid bool "Collide" "1"
animation string "Animation" ""
@point sound_ambient "Ambient sound" color(200,130,255) size(8)
sound string "Sound file" ""
volume float "Volume" "1.0"
radius float "Radius" "512"
@point item_spawn "Item spawn" color(255,150,200) size(10)
item string "Item" ""
respawn float "Respawn time" "30"
@brush func_detail "Detail brush" color(120,160,255)
@brush func_wall "Wall (own model)" color(170,170,190)
@brush func_door "Door" color(210,165,90)
speed float "Speed" "100"
movedir vec3 "Move direction" "0 1 0"
distance float "Distance" "64"
wait float "Wait before closing" "3"
@brush func_button "Button" color(230,120,120)
target target "Target" ""
delay float "Delay" "0"
@brush trigger_multiple "Trigger (repeatable)" color(255,120,40) contents(trigger)
target target "Target" ""
wait float "Re-arm delay" "1"
@brush trigger_once "Trigger (once)" color(255,170,60) contents(trigger)
target target "Target" ""
@brush func_clip "Player clip" color(120,120,255) contents(clip)
@brush water "Water volume" color(70,120,255) contents(water)
density float "Density" "1.0"
)DEF";
std::vector<std::string> tokenize(const std::string& line) {
std::vector<std::string> t;
size_t i = 0, n = line.size();
while (i < n) {
while (i < n && (line[i] == ' ' || line[i] == '\t' || line[i] == '\r')) ++i;
if (i >= n) break;
if (line[i] == '"') {
size_t j = line.find('"', i + 1);
if (j == std::string::npos) j = n;
t.push_back(line.substr(i + 1, j - i - 1));
i = j + 1;
} else {
size_t j = i;
while (j < n && line[j] != ' ' && line[j] != '\t' && line[j] != '\r') ++j;
t.push_back(line.substr(i, j - i));
i = j;
}
}
return t;
}
std::vector<float> numbersIn(const std::string& tok) {
std::vector<float> v;
size_t a = tok.find('('), b = tok.find(')');
if (a == std::string::npos || b == std::string::npos || b < a) return v;
std::string inner = tok.substr(a + 1, b - a - 1);
for (char& c : inner) if (c == ',') c = ' ';
std::istringstream ss(inner);
float f;
while (ss >> f) v.push_back(f);
return v;
}
bool startsWith(const std::string& s, const char* p) { return s.rfind(p, 0) == 0; }
} // namespace
const EntityClass* EntityRegistry::find(const std::string& name) const {
for (const EntityClass& c : classes)
if (c.name == name) return &c;
return nullptr;
}
Status EntityRegistry::parse(const std::string& text) {
std::istringstream in(text);
std::string line;
int lineNo = 0;
EntityClass* cur = nullptr;
while (std::getline(in, line)) {
++lineNo;
size_t first = line.find_first_not_of(" \t\r");
if (first == std::string::npos || line[first] == '#') continue;
std::vector<std::string> t = tokenize(line);
if (t.empty()) continue;
if (t[0][0] == '@') {
if (t.size() < 2 || (t[0] != "@point" && t[0] != "@brush"))
return Status::Fail("entity defs line " + std::to_string(lineNo) + ": expected @point or @brush <class>");
EntityClass c;
c.name = t[1];
c.label = t.size() > 2 ? t[2] : t[1];
c.brush = t[0] == "@brush";
if (c.brush) c.brushContents = CONTENTS_SOLID;
for (size_t i = 3; i < t.size(); ++i) {
if (startsWith(t[i], "color(")) {
auto v = numbersIn(t[i]);
if (v.size() >= 3) c.color = {v[0] / 255.0f, v[1] / 255.0f, v[2] / 255.0f};
} else if (startsWith(t[i], "size(")) {
auto v = numbersIn(t[i]);
if (v.size() == 1) c.half = {v[0], v[0], v[0]};
else if (v.size() >= 3) c.half = {v[0], v[1], v[2]};
} else if (t[i] == "dir") c.directional = true;
else if (t[i] == "model") c.hasModel = true;
else if (startsWith(t[i], "contents(")) {
std::string v = t[i].substr(9);
if (v.find("trigger") == 0) c.brushContents = CONTENTS_TRIGGER;
else if (v.find("clip") == 0) c.brushContents = CONTENTS_CLIP;
else if (v.find("water") == 0) c.brushContents = CONTENTS_WATER;
else if (v.find("sky") == 0) c.brushContents = CONTENTS_SKY;
else c.brushContents = CONTENTS_SOLID;
}
}
bool replaced = false;
for (EntityClass& ex : classes)
if (ex.name == c.name) { ex = c; cur = &ex; replaced = true; break; }
if (!replaced) { classes.push_back(c); cur = &classes.back(); }
} else {
if (!cur) return Status::Fail("entity defs line " + std::to_string(lineNo) + ": property before any class");
if (t.size() < 3) return Status::Fail("entity defs line " + std::to_string(lineNo) + ": expected <key> <type> \"<label>\"");
PropDef p;
p.key = t[0];
p.type = t[1];
p.label = t[2];
if (t.size() > 3) p.def = t[3];
if (t.size() > 4) p.choices = t[4];
cur->props.push_back(p);
}
}
return Status::Ok();
}
void EntityRegistry::applyDefaults(Entity& e) const {
const EntityClass* c = find(e.classname);
if (!c) return;
for (const PropDef& p : c->props)
if (!p.def.empty() && !e.find(p.key)) e.set(p.key, p.def);
}
EntityRegistry EntityRegistry::builtin() {
EntityRegistry r;
r.parse(kBuiltin);
return r;
}
} // namespace hmap