ericw-tools/maputil/maputil.cc

210 lines
5.4 KiB
C++

/* Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
See file, 'COPYING', for details.
*/
#include <cstdint>
#include <common\entdata.h>
#include <common\parser.hh>
#include <common\log.hh>
#include <common\mapfile.hh>
#ifdef USE_LUA
extern "C"
{
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}
#endif
map_file_t LoadMapOrEntFile(const fs::path &source)
{
logging::funcheader();
auto file = fs::load(source);
map_file_t map;
if (!file) {
FError("Couldn't load map/entity file \"{}\".", source);
return map;
}
parser_t parser(file, {source.string()});
map.parse(parser);
return map;
}
constexpr const char *usage = "\
usage: maputil [operations...]\
\
valid operations:\
--query \"<Lua expression>\"\
perform a query on entities and print out matching results.\
see docs for more details on globals.\
--script \"<path to Lua script file\"\
execute the given Lua script.\
--strip_extended_info\
removes extended Quake II/III information on faces.\
--convert <quake | valve | etp | bp>\
convert the current map to the given format.\
--save \"<output path>\"\
save the current map to the given output path.\
";
static void maputil_query(map_file_t &map_file, const char *query)
{
#ifdef USE_LUA
logging::print("query: {}\n", query);
lua_State *state = luaL_newstate();
luaL_openlibs(state);
int err = luaL_loadstring(state, query);
if (err != LUA_OK) {
logging::print("can't load query: {}\n", lua_tostring(state, -1));
lua_pop(state, 1);
} else {
lua_pushvalue(state, 1);
int ref = luaL_ref(state, LUA_REGISTRYINDEX);
lua_pop(state, 1);
for (auto &entity : map_file.entities) {
lua_createtable(state, 0, entity.epairs.size());
for (auto &kvp : entity.epairs) {
lua_pushstring(state, kvp.second.c_str());
lua_setfield(state, -2, kvp.first.c_str());
}
lua_setglobal(state, "entity");
lua_rawgeti(state, LUA_REGISTRYINDEX, ref);
err = lua_pcall(state, 0, 1, 0);
if (err != LUA_OK) {
logging::print("can't execute query: {}\n", lua_tostring(state, -1));
lua_pop(state, 1);
} else {
int b = lua_toboolean(state, -1);
lua_pop(state, 1);
if (b) {
logging::print("MATCHED: {} @ {}\n", entity.epairs.get("classname"), entity.location);
}
}
lua_gc(state, LUA_GCCOLLECT);
}
luaL_unref(state, LUA_REGISTRYINDEX, ref);
lua_close(state);
}
#else
logging::print("maputil not compiled with Lua support\n");
#endif
}
int maputil_main(int argc, char **argv)
{
logging::preinitialize();
fmt::print("---- maputil / ericw-tools {} ----\n", ERICWTOOLS_VERSION);
if (argc == 1) {
fmt::print("{}", usage);
exit(1);
}
fs::path source = argv[1];
if (!fs::exists(source)) {
source = DefaultExtension(argv[1], "map");
}
printf("---------------------\n");
fmt::print("{}\n", source);
map_file_t map_file;
map_file = LoadMapOrEntFile(source);
for (int32_t i = 2; i < argc - 1; i++) {
const char *cmd = argv[i];
if (!strcmp(cmd, "--query")) {
i++;
const char *query = argv[i];
maputil_query(map_file, query);
} else if (!strcmp(cmd, "--save")) {
i++;
const char *output = argv[i];
fs::path dest = DefaultExtension(output, "map");
fmt::print("saving to {}...\n", dest);
std::ofstream stream(dest);
map_file.write(stream);
} else if (!strcmp(cmd, "--strip_extended_info")) {
for (auto &entity : map_file.entities) {
for (auto &brush : entity.brushes) {
for (auto &face : brush.faces) {
face.extended_info = std::nullopt;
}
}
}
} else if (!strcmp(cmd, "--convert")) {
i++;
const char *type = argv[i];
texcoord_style_t dest_style;
if (!strcmp(type, "quake")) {
dest_style = texcoord_style_t::quaked;
} else if (!strcmp(type, "valve")) {
dest_style = texcoord_style_t::valve_220;
} else if (!strcmp(type, "etp")) {
dest_style = texcoord_style_t::etp;
} else if (!strcmp(type, "bp")) {
dest_style = texcoord_style_t::brush_primitives;
} else {
FError("unknown map style {}", type);
}
map_file.convert_to(dest_style);
}
}
printf("---------------------\n");
return 0;
}