Skip to content

Commit 5cf6318

Browse files
Hugues Rosssfan5rubenwardy
authoredApr 14, 2020
Refactor texture overrides and add new features (#9600)
* Refactor texture overrides, and add new features: - Texture overrides can support multiple targets in one line - Texture override files can have comment lines - Item images/wield images can be overridden * Formatting changes * Address soime feedback - Pass vectors by const reference - Log syntax errors as warnings - Remove 'C' prefix from TextureOverrideSource * Simplify override target checks with an inline helper function * make linter happy * Apply feedback suggestions Co-Authored-By: rubenwardy <rw@rubenwardy.com> * Remove remaining != 0 checks * Update copyright notice Co-authored-by: sfan5 <sfan5@live.de> Co-authored-by: rubenwardy <rw@rubenwardy.com>
1 parent 7e21b3c commit 5cf6318

11 files changed

+285
-71
lines changed
 

Diff for: ‎doc/texture_packs.txt

+31-14
Original file line numberDiff line numberDiff line change
@@ -145,34 +145,51 @@ are placeholders intended to be overwritten by the game.
145145
Texture Overrides
146146
-----------------
147147

148-
You can override the textures of a node from a texture pack using
149-
texture overrides. To do this, create a file in a texture pack
150-
called override.txt
148+
You can override the textures of nodes and items from a
149+
texture pack using texture overrides. To do this, create one or
150+
more files in a texture pack called override.txt
151151

152152
Each line in an override.txt file is a rule. It consists of
153153

154-
nodename face-selector texture
154+
itemname target texture
155155

156156
For example,
157157

158158
default:dirt_with_grass sides default_stone.png
159159

160-
You can use ^ operators as usual:
160+
or
161+
162+
default:sword_steel inventory my_steel_sword.png
163+
164+
You can list multiple targets on one line as a comma-separated list:
165+
166+
default:tree top,bottom my_special_tree.png
167+
168+
You can use texture modifiers, as usual:
161169

162170
default:dirt_with_grass sides default_stone.png^[brighten
163171

164-
Here are face selectors you can choose from:
172+
Finally, if a line is empty or starts with '#' it will be considered
173+
a comment and not read as a rule. You can use this to better organize
174+
your override.txt files.
175+
176+
Here are targets you can choose from:
165177

166-
| face-selector | behavior |
178+
| target | behavior |
167179
|---------------|---------------------------------------------------|
168-
| left | x- |
169-
| right | x+ |
170-
| front | z- |
171-
| back | z+ |
172-
| top | y+ |
173-
| bottom | y- |
174-
| sides | x-, x+, z-, z+ |
180+
| left | x- face |
181+
| right | x+ face |
182+
| front | z- face |
183+
| back | z+ face |
184+
| top | y+ face |
185+
| bottom | y- face |
186+
| sides | x-, x+, z-, z+ faces |
175187
| all | All faces. You can also use '*' instead of 'all'. |
188+
| inventory | The inventory texture |
189+
| wield | The texture used when held by the player |
190+
191+
Nodes support all targets, but other items only support 'inventory'
192+
and 'wield'
176193

177194
Designing leaves textures for the leaves rendering options
178195
----------------------------------------------------------

Diff for: ‎src/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,7 @@ set(common_SRCS
423423
settings.cpp
424424
staticobject.cpp
425425
terminal_chat_console.cpp
426+
texture_override.cpp
426427
tileanimation.cpp
427428
tool.cpp
428429
translation.cpp

Diff for: ‎src/client/client.cpp

+5-2
Original file line numberDiff line numberDiff line change
@@ -1742,8 +1742,11 @@ void Client::afterContentReceived()
17421742
text = wgettext("Initializing nodes...");
17431743
RenderingEngine::draw_load_screen(text, guienv, m_tsrc, 0, 72);
17441744
m_nodedef->updateAliases(m_itemdef);
1745-
for (const auto &path : getTextureDirs())
1746-
m_nodedef->applyTextureOverrides(path + DIR_DELIM + "override.txt");
1745+
for (const auto &path : getTextureDirs()) {
1746+
TextureOverrideSource override_source(path + DIR_DELIM + "override.txt");
1747+
m_nodedef->applyTextureOverrides(override_source.getNodeTileOverrides());
1748+
m_itemdef->applyTextureOverrides(override_source.getItemTextureOverrides());
1749+
}
17471750
m_nodedef->setNodeRegistrationStatus(true);
17481751
m_nodedef->runNodeResolveCallbacks();
17491752
delete[] text;

Diff for: ‎src/itemdef.cpp

+19
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,25 @@ class CItemDefManager: public IWritableItemDefManager
422422
return get(stack.name).color;
423423
}
424424
#endif
425+
void applyTextureOverrides(const std::vector<TextureOverride> &overrides)
426+
{
427+
infostream << "ItemDefManager::applyTextureOverrides(): Applying "
428+
"overrides to textures" << std::endl;
429+
430+
for (const TextureOverride& texture_override : overrides) {
431+
if (m_item_definitions.find(texture_override.id) == m_item_definitions.end()) {
432+
continue; // Ignore unknown item
433+
}
434+
435+
ItemDefinition* itemdef = m_item_definitions[texture_override.id];
436+
437+
if (texture_override.hasTarget(OverrideTarget::INVENTORY))
438+
itemdef->inventory_image = texture_override.texture;
439+
440+
if (texture_override.hasTarget(OverrideTarget::WIELD))
441+
itemdef->wield_image = texture_override.texture;
442+
}
443+
}
425444
void clear()
426445
{
427446
for(std::map<std::string, ItemDefinition*>::const_iterator

Diff for: ‎src/itemdef.h

+5
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
2626
#include <set>
2727
#include "itemgroup.h"
2828
#include "sound.h"
29+
#include "texture_override.h" // TextureOverride
2930
class IGameDef;
3031
class Client;
3132
struct ToolCapabilities;
@@ -157,6 +158,10 @@ class IWritableItemDefManager : public IItemDefManager
157158
Client *client) const=0;
158159
#endif
159160

161+
// Replace the textures of registered nodes with the ones specified in
162+
// the texture pack's override.txt files
163+
virtual void applyTextureOverrides(const std::vector<TextureOverride> &overrides)=0;
164+
160165
// Remove all registered item and node definitions and aliases
161166
// Then re-add the builtin item definitions
162167
virtual void clear()=0;

Diff for: ‎src/nodedef.cpp

+21-46
Original file line numberDiff line numberDiff line change
@@ -1304,60 +1304,35 @@ void NodeDefManager::updateAliases(IItemDefManager *idef)
13041304
}
13051305
}
13061306

1307-
void NodeDefManager::applyTextureOverrides(const std::string &override_filepath)
1307+
void NodeDefManager::applyTextureOverrides(const std::vector<TextureOverride> &overrides)
13081308
{
13091309
infostream << "NodeDefManager::applyTextureOverrides(): Applying "
1310-
"overrides to textures from " << override_filepath << std::endl;
1311-
1312-
std::ifstream infile(override_filepath.c_str());
1313-
std::string line;
1314-
int line_c = 0;
1315-
while (std::getline(infile, line)) {
1316-
line_c++;
1317-
// Also trim '\r' on DOS-style files
1318-
line = trim(line);
1319-
if (line.empty())
1320-
continue;
1321-
1322-
std::vector<std::string> splitted = str_split(line, ' ');
1323-
if (splitted.size() != 3) {
1324-
errorstream << override_filepath
1325-
<< ":" << line_c << " Could not apply texture override \""
1326-
<< line << "\": Syntax error" << std::endl;
1327-
continue;
1328-
}
1310+
"overrides to textures" << std::endl;
13291311

1312+
for (const TextureOverride& texture_override : overrides) {
13301313
content_t id;
1331-
if (!getId(splitted[0], id))
1314+
if (!getId(texture_override.id, id))
13321315
continue; // Ignore unknown node
13331316

13341317
ContentFeatures &nodedef = m_content_features[id];
13351318

1336-
if (splitted[1] == "top")
1337-
nodedef.tiledef[0].name = splitted[2];
1338-
else if (splitted[1] == "bottom")
1339-
nodedef.tiledef[1].name = splitted[2];
1340-
else if (splitted[1] == "right")
1341-
nodedef.tiledef[2].name = splitted[2];
1342-
else if (splitted[1] == "left")
1343-
nodedef.tiledef[3].name = splitted[2];
1344-
else if (splitted[1] == "back")
1345-
nodedef.tiledef[4].name = splitted[2];
1346-
else if (splitted[1] == "front")
1347-
nodedef.tiledef[5].name = splitted[2];
1348-
else if (splitted[1] == "all" || splitted[1] == "*")
1349-
for (TileDef &i : nodedef.tiledef)
1350-
i.name = splitted[2];
1351-
else if (splitted[1] == "sides")
1352-
for (int i = 2; i < 6; i++)
1353-
nodedef.tiledef[i].name = splitted[2];
1354-
else {
1355-
errorstream << override_filepath
1356-
<< ":" << line_c << " Could not apply texture override \""
1357-
<< line << "\": Unknown node side \""
1358-
<< splitted[1] << "\"" << std::endl;
1359-
continue;
1360-
}
1319+
if (texture_override.hasTarget(OverrideTarget::TOP))
1320+
nodedef.tiledef[0].name = texture_override.texture;
1321+
1322+
if (texture_override.hasTarget(OverrideTarget::BOTTOM))
1323+
nodedef.tiledef[1].name = texture_override.texture;
1324+
1325+
if (texture_override.hasTarget(OverrideTarget::RIGHT))
1326+
nodedef.tiledef[2].name = texture_override.texture;
1327+
1328+
if (texture_override.hasTarget(OverrideTarget::LEFT))
1329+
nodedef.tiledef[3].name = texture_override.texture;
1330+
1331+
if (texture_override.hasTarget(OverrideTarget::BACK))
1332+
nodedef.tiledef[4].name = texture_override.texture;
1333+
1334+
if (texture_override.hasTarget(OverrideTarget::FRONT))
1335+
nodedef.tiledef[5].name = texture_override.texture;
13611336
}
13621337
}
13631338

Diff for: ‎src/nodedef.h

+5-7
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class Client;
3333
#include "itemgroup.h"
3434
#include "sound.h" // SimpleSoundSpec
3535
#include "constants.h" // BS
36+
#include "texture_override.h" // TextureOverride
3637
#include "tileanimation.h"
3738

3839
// PROTOCOL_VERSION >= 37
@@ -583,15 +584,12 @@ class NodeDefManager {
583584
void updateAliases(IItemDefManager *idef);
584585

585586
/*!
586-
* Reads the used texture pack's override.txt, and replaces the textures
587-
* of registered nodes with the ones specified there.
587+
* Replaces the textures of registered nodes with the ones specified in
588+
* the texturepack's override.txt file
588589
*
589-
* Format of the input file: in each line
590-
* `node_name top|bottom|right|left|front|back|all|*|sides texture_name.png`
591-
*
592-
* @param override_filepath path to 'texturepack/override.txt'
590+
* @param overrides the texture overrides
593591
*/
594-
void applyTextureOverrides(const std::string &override_filepath);
592+
void applyTextureOverrides(const std::vector<TextureOverride> &overrides);
595593

596594
/*!
597595
* Only the client uses this. Loads textures and shaders required for

Diff for: ‎src/server.cpp

+5-2
Original file line numberDiff line numberDiff line change
@@ -373,8 +373,11 @@ void Server::init()
373373
std::vector<std::string> paths;
374374
fs::GetRecursiveDirs(paths, g_settings->get("texture_path"));
375375
fs::GetRecursiveDirs(paths, m_gamespec.path + DIR_DELIM + "textures");
376-
for (const std::string &path : paths)
377-
m_nodedef->applyTextureOverrides(path + DIR_DELIM + "override.txt");
376+
for (const std::string &path : paths) {
377+
TextureOverrideSource override_source(path + DIR_DELIM + "override.txt");
378+
m_nodedef->applyTextureOverrides(override_source.getNodeTileOverrides());
379+
m_itemdef->applyTextureOverrides(override_source.getItemTextureOverrides());
380+
}
378381

379382
m_nodedef->setNodeRegistrationStatus(true);
380383

Diff for: ‎src/texture_override.cpp

+120
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*
2+
Minetest
3+
Copyright (C) 2020 Hugues Ross <hugues.ross@gmail.com>
4+
5+
This program is free software; you can redistribute it and/or modify
6+
it under the terms of the GNU Lesser General Public License as published by
7+
the Free Software Foundation; either version 2.1 of the License, or
8+
(at your option) any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU Lesser General Public License for more details.
14+
15+
You should have received a copy of the GNU Lesser General Public License along
16+
with this program; if not, write to the Free Software Foundation, Inc.,
17+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*/
19+
20+
#include "texture_override.h"
21+
22+
#include "log.h"
23+
#include "util/string.h"
24+
#include <algorithm>
25+
#include <fstream>
26+
27+
TextureOverrideSource::TextureOverrideSource(std::string filepath)
28+
{
29+
std::ifstream infile(filepath.c_str());
30+
std::string line;
31+
int line_index = 0;
32+
while (std::getline(infile, line)) {
33+
line_index++;
34+
35+
// Also trim '\r' on DOS-style files
36+
line = trim(line);
37+
38+
// Ignore empty lines and comments
39+
if (line.empty() || line[0] == '#')
40+
continue;
41+
42+
std::vector<std::string> splitted = str_split(line, ' ');
43+
if (splitted.size() != 3) {
44+
warningstream << filepath << ":" << line_index
45+
<< " Syntax error in texture override \"" << line
46+
<< "\": Expected 3 arguments, got " << splitted.size()
47+
<< std::endl;
48+
continue;
49+
}
50+
51+
TextureOverride texture_override = {};
52+
texture_override.id = splitted[0];
53+
texture_override.texture = splitted[2];
54+
55+
// Parse the target mask
56+
std::vector<std::string> targets = str_split(splitted[1], ',');
57+
for (const std::string &target : targets) {
58+
if (target == "top")
59+
texture_override.target |= static_cast<u8>(OverrideTarget::TOP);
60+
else if (target == "bottom")
61+
texture_override.target |= static_cast<u8>(OverrideTarget::BOTTOM);
62+
else if (target == "left")
63+
texture_override.target |= static_cast<u8>(OverrideTarget::LEFT);
64+
else if (target == "right")
65+
texture_override.target |= static_cast<u8>(OverrideTarget::RIGHT);
66+
else if (target == "front")
67+
texture_override.target |= static_cast<u8>(OverrideTarget::FRONT);
68+
else if (target == "back")
69+
texture_override.target |= static_cast<u8>(OverrideTarget::BACK);
70+
else if (target == "inventory")
71+
texture_override.target |= static_cast<u8>(OverrideTarget::INVENTORY);
72+
else if (target == "wield")
73+
texture_override.target |= static_cast<u8>(OverrideTarget::WIELD);
74+
else if (target == "sides")
75+
texture_override.target |= static_cast<u8>(OverrideTarget::SIDES);
76+
else if (target == "all" || target == "*")
77+
texture_override.target |= static_cast<u8>(OverrideTarget::ALL_FACES);
78+
else {
79+
// Report invalid target
80+
warningstream << filepath << ":" << line_index
81+
<< " Syntax error in texture override \"" << line
82+
<< "\": Unknown target \"" << target << "\""
83+
<< std::endl;
84+
}
85+
}
86+
87+
// If there are no valid targets, skip adding this override
88+
if (texture_override.target == static_cast<u8>(OverrideTarget::INVALID)) {
89+
continue;
90+
}
91+
92+
m_overrides.push_back(texture_override);
93+
}
94+
}
95+
96+
//! Get all overrides that apply to item definitions
97+
std::vector<TextureOverride> TextureOverrideSource::getItemTextureOverrides()
98+
{
99+
std::vector<TextureOverride> found_overrides;
100+
101+
for (const TextureOverride &texture_override : m_overrides) {
102+
if (texture_override.hasTarget(OverrideTarget::ITEM_TARGETS))
103+
found_overrides.push_back(texture_override);
104+
}
105+
106+
return found_overrides;
107+
}
108+
109+
//! Get all overrides that apply to node definitions
110+
std::vector<TextureOverride> TextureOverrideSource::getNodeTileOverrides()
111+
{
112+
std::vector<TextureOverride> found_overrides;
113+
114+
for (const TextureOverride &texture_override : m_overrides) {
115+
if (texture_override.hasTarget(OverrideTarget::ALL_FACES))
116+
found_overrides.push_back(texture_override);
117+
}
118+
119+
return found_overrides;
120+
}

Diff for: ‎src/texture_override.h

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
Minetest
3+
Copyright (C) 2020 Hugues Ross <hugues.ross@gmail.com>
4+
5+
This program is free software; you can redistribute it and/or modify
6+
it under the terms of the GNU Lesser General Public License as published by
7+
the Free Software Foundation; either version 2.1 of the License, or
8+
(at your option) any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU Lesser General Public License for more details.
14+
15+
You should have received a copy of the GNU Lesser General Public License along
16+
with this program; if not, write to the Free Software Foundation, Inc.,
17+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*/
19+
20+
#pragma once
21+
22+
#include "irrlichttypes.h"
23+
#include <string>
24+
#include <vector>
25+
26+
//! Bitmask enum specifying what a texture override should apply to
27+
enum class OverrideTarget : u8
28+
{
29+
INVALID = 0,
30+
TOP = 1 << 0,
31+
BOTTOM = 1 << 1,
32+
LEFT = 1 << 2,
33+
RIGHT = 1 << 3,
34+
FRONT = 1 << 4,
35+
BACK = 1 << 5,
36+
INVENTORY = 1 << 6,
37+
WIELD = 1 << 7,
38+
39+
SIDES = LEFT | RIGHT | FRONT | BACK,
40+
ALL_FACES = TOP | BOTTOM | SIDES,
41+
ITEM_TARGETS = INVENTORY | WIELD,
42+
};
43+
44+
struct TextureOverride
45+
{
46+
std::string id;
47+
std::string texture;
48+
u8 target;
49+
50+
// Helper function for checking if an OverrideTarget is found in
51+
// a TextureOverride without casting
52+
inline bool hasTarget(OverrideTarget overrideTarget) const
53+
{
54+
return (target & static_cast<u8>(overrideTarget)) != 0;
55+
}
56+
};
57+
58+
//! Class that provides texture override information from a texture pack
59+
class TextureOverrideSource
60+
{
61+
public:
62+
TextureOverrideSource(std::string filepath);
63+
64+
//! Get all overrides that apply to item definitions
65+
std::vector<TextureOverride> getItemTextureOverrides();
66+
67+
//! Get all overrides that apply to node definitions
68+
std::vector<TextureOverride> getNodeTileOverrides();
69+
70+
private:
71+
std::vector<TextureOverride> m_overrides;
72+
};

Diff for: ‎util/travis/clang-format-whitelist.txt

+1
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,7 @@ src/subgame.cpp
423423
src/subgame.h
424424
src/terminal_chat_console.cpp
425425
src/terminal_chat_console.h
426+
src/texture_override.cpp
426427
src/threading/atomic.h
427428
src/threading/event.cpp
428429
src/threading/mutex_auto_lock.h

0 commit comments

Comments
 (0)
Please sign in to comment.