mirror of
https://github.com/luanti-org/luanti.git
synced 2025-09-15 18:57:08 +00:00
Automatic item and node colorization (#5640)
* Automatic item and node colorization Now nodes with a palette yield colored item stacks, and colored items place colored nodes by default. The client predicts the colorization. * Backwards compatibility * Use nil * Style fixes * Fix code style * Document changes
This commit is contained in:
parent
7c07cb4ec2
commit
0fcaf9fb1b
8 changed files with 114 additions and 38 deletions
57
src/game.cpp
57
src/game.cpp
|
@ -774,8 +774,8 @@ public:
|
|||
};
|
||||
|
||||
|
||||
bool nodePlacementPrediction(Client &client,
|
||||
const ItemDefinition &playeritem_def, v3s16 nodepos, v3s16 neighbourpos)
|
||||
bool nodePlacementPrediction(Client &client, const ItemDefinition &playeritem_def,
|
||||
const ItemStack &playeritem, v3s16 nodepos, v3s16 neighbourpos)
|
||||
{
|
||||
std::string prediction = playeritem_def.node_placement_prediction;
|
||||
INodeDefManager *nodedef = client.ndef();
|
||||
|
@ -818,11 +818,13 @@ bool nodePlacementPrediction(Client &client,
|
|||
return false;
|
||||
}
|
||||
|
||||
const ContentFeatures &predicted_f = nodedef->get(id);
|
||||
|
||||
// Predict param2 for facedir and wallmounted nodes
|
||||
u8 param2 = 0;
|
||||
|
||||
if (nodedef->get(id).param_type_2 == CPT2_WALLMOUNTED ||
|
||||
nodedef->get(id).param_type_2 == CPT2_COLORED_WALLMOUNTED) {
|
||||
if (predicted_f.param_type_2 == CPT2_WALLMOUNTED ||
|
||||
predicted_f.param_type_2 == CPT2_COLORED_WALLMOUNTED) {
|
||||
v3s16 dir = nodepos - neighbourpos;
|
||||
|
||||
if (abs(dir.Y) > MYMAX(abs(dir.X), abs(dir.Z))) {
|
||||
|
@ -834,8 +836,8 @@ bool nodePlacementPrediction(Client &client,
|
|||
}
|
||||
}
|
||||
|
||||
if (nodedef->get(id).param_type_2 == CPT2_FACEDIR ||
|
||||
nodedef->get(id).param_type_2 == CPT2_COLORED_FACEDIR) {
|
||||
if (predicted_f.param_type_2 == CPT2_FACEDIR ||
|
||||
predicted_f.param_type_2 == CPT2_COLORED_FACEDIR) {
|
||||
v3s16 dir = nodepos - floatToInt(client.getEnv().getLocalPlayer()->getPosition(), BS);
|
||||
|
||||
if (abs(dir.X) > abs(dir.Z)) {
|
||||
|
@ -848,7 +850,7 @@ bool nodePlacementPrediction(Client &client,
|
|||
assert(param2 <= 5);
|
||||
|
||||
//Check attachment if node is in group attached_node
|
||||
if (((ItemGroupList) nodedef->get(id).groups)["attached_node"] != 0) {
|
||||
if (((ItemGroupList) predicted_f.groups)["attached_node"] != 0) {
|
||||
static v3s16 wallmounted_dirs[8] = {
|
||||
v3s16(0, 1, 0),
|
||||
v3s16(0, -1, 0),
|
||||
|
@ -859,8 +861,8 @@ bool nodePlacementPrediction(Client &client,
|
|||
};
|
||||
v3s16 pp;
|
||||
|
||||
if (nodedef->get(id).param_type_2 == CPT2_WALLMOUNTED ||
|
||||
nodedef->get(id).param_type_2 == CPT2_COLORED_WALLMOUNTED)
|
||||
if (predicted_f.param_type_2 == CPT2_WALLMOUNTED ||
|
||||
predicted_f.param_type_2 == CPT2_COLORED_WALLMOUNTED)
|
||||
pp = p + wallmounted_dirs[param2];
|
||||
else
|
||||
pp = p + v3s16(0, -1, 0);
|
||||
|
@ -869,6 +871,28 @@ bool nodePlacementPrediction(Client &client,
|
|||
return false;
|
||||
}
|
||||
|
||||
// Apply color
|
||||
if ((predicted_f.param_type_2 == CPT2_COLOR
|
||||
|| predicted_f.param_type_2 == CPT2_COLORED_FACEDIR
|
||||
|| predicted_f.param_type_2 == CPT2_COLORED_WALLMOUNTED)) {
|
||||
const std::string &indexstr = playeritem.metadata.getString(
|
||||
"palette_index", 0);
|
||||
if (!indexstr.empty()) {
|
||||
s32 index = mystoi(indexstr);
|
||||
if (predicted_f.param_type_2 == CPT2_COLOR) {
|
||||
param2 = index;
|
||||
} else if (predicted_f.param_type_2
|
||||
== CPT2_COLORED_WALLMOUNTED) {
|
||||
// param2 = pure palette index + other
|
||||
param2 = (index & 0xf8) | (param2 & 0x07);
|
||||
} else if (predicted_f.param_type_2
|
||||
== CPT2_COLORED_FACEDIR) {
|
||||
// param2 = pure palette index + other
|
||||
param2 = (index & 0xe0) | (param2 & 0x1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add node to client map
|
||||
MapNode n(id, 0, param2);
|
||||
|
||||
|
@ -1277,8 +1301,9 @@ protected:
|
|||
const core::line3d<f32> &shootline, bool liquids_pointable,
|
||||
bool look_for_object, const v3s16 &camera_offset);
|
||||
void handlePointingAtNothing(const ItemStack &playerItem);
|
||||
void handlePointingAtNode(const PointedThing &pointed, const ItemDefinition &playeritem_def,
|
||||
const ToolCapabilities &playeritem_toolcap, f32 dtime);
|
||||
void handlePointingAtNode(const PointedThing &pointed,
|
||||
const ItemDefinition &playeritem_def, const ItemStack &playeritem,
|
||||
const ToolCapabilities &playeritem_toolcap, f32 dtime);
|
||||
void handlePointingAtObject(const PointedThing &pointed, const ItemStack &playeritem,
|
||||
const v3f &player_position, bool show_debug);
|
||||
void handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
|
||||
|
@ -3599,7 +3624,8 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug)
|
|||
if (playeritem.name.empty() && hand_def.tool_capabilities != NULL) {
|
||||
playeritem_toolcap = *hand_def.tool_capabilities;
|
||||
}
|
||||
handlePointingAtNode(pointed, playeritem_def, playeritem_toolcap, dtime);
|
||||
handlePointingAtNode(pointed, playeritem_def, playeritem,
|
||||
playeritem_toolcap, dtime);
|
||||
} else if (pointed.type == POINTEDTHING_OBJECT) {
|
||||
handlePointingAtObject(pointed, playeritem, player_position, show_debug);
|
||||
} else if (isLeftPressed()) {
|
||||
|
@ -3734,8 +3760,9 @@ void Game::handlePointingAtNothing(const ItemStack &playerItem)
|
|||
}
|
||||
|
||||
|
||||
void Game::handlePointingAtNode(const PointedThing &pointed, const ItemDefinition &playeritem_def,
|
||||
const ToolCapabilities &playeritem_toolcap, f32 dtime)
|
||||
void Game::handlePointingAtNode(const PointedThing &pointed,
|
||||
const ItemDefinition &playeritem_def, const ItemStack &playeritem,
|
||||
const ToolCapabilities &playeritem_toolcap, f32 dtime)
|
||||
{
|
||||
v3s16 nodepos = pointed.node_undersurface;
|
||||
v3s16 neighbourpos = pointed.node_abovesurface;
|
||||
|
@ -3795,7 +3822,7 @@ void Game::handlePointingAtNode(const PointedThing &pointed, const ItemDefinitio
|
|||
// If the wielded item has node placement prediction,
|
||||
// make that happen
|
||||
bool placed = nodePlacementPrediction(*client,
|
||||
playeritem_def,
|
||||
playeritem_def, playeritem,
|
||||
nodepos, neighbourpos);
|
||||
|
||||
if (placed) {
|
||||
|
|
|
@ -658,7 +658,7 @@ bool InventoryList::roomForItem(const ItemStack &item_) const
|
|||
return false;
|
||||
}
|
||||
|
||||
bool InventoryList::containsItem(const ItemStack &item) const
|
||||
bool InventoryList::containsItem(const ItemStack &item, bool match_meta) const
|
||||
{
|
||||
u32 count = item.count;
|
||||
if(count == 0)
|
||||
|
@ -669,9 +669,9 @@ bool InventoryList::containsItem(const ItemStack &item) const
|
|||
{
|
||||
if(count == 0)
|
||||
break;
|
||||
if(i->name == item.name)
|
||||
{
|
||||
if(i->count >= count)
|
||||
if (i->name == item.name
|
||||
&& (!match_meta || (i->metadata == item.metadata))) {
|
||||
if (i->count >= count)
|
||||
return true;
|
||||
else
|
||||
count -= i->count;
|
||||
|
|
|
@ -223,9 +223,10 @@ public:
|
|||
// Checks whether there is room for a given item
|
||||
bool roomForItem(const ItemStack &item) const;
|
||||
|
||||
// Checks whether the given count of the given item name
|
||||
// Checks whether the given count of the given item
|
||||
// exists in this inventory list.
|
||||
bool containsItem(const ItemStack &item) const;
|
||||
// If match_meta is false, only the items' names are compared.
|
||||
bool containsItem(const ItemStack &item, bool match_meta) const;
|
||||
|
||||
// Removes the given count of the given item name from
|
||||
// this inventory list. Walks the list in reverse order.
|
||||
|
|
|
@ -325,8 +325,8 @@ int InvRef::l_room_for_item(lua_State *L)
|
|||
return 1;
|
||||
}
|
||||
|
||||
// contains_item(self, listname, itemstack or itemstring or table or nil) -> true/false
|
||||
// Returns true if the list contains the given count of the given item name
|
||||
// contains_item(self, listname, itemstack or itemstring or table or nil, [match_meta]) -> true/false
|
||||
// Returns true if the list contains the given count of the given item
|
||||
int InvRef::l_contains_item(lua_State *L)
|
||||
{
|
||||
NO_MAP_LOCK_REQUIRED;
|
||||
|
@ -334,8 +334,11 @@ int InvRef::l_contains_item(lua_State *L)
|
|||
const char *listname = luaL_checkstring(L, 2);
|
||||
ItemStack item = read_item(L, 3, getServer(L)->idef());
|
||||
InventoryList *list = getlist(L, ref, listname);
|
||||
if(list){
|
||||
lua_pushboolean(L, list->containsItem(item));
|
||||
bool match_meta = false;
|
||||
if (lua_isboolean(L, 4))
|
||||
match_meta = lua_toboolean(L, 4);
|
||||
if (list) {
|
||||
lua_pushboolean(L, list->containsItem(item, match_meta));
|
||||
} else {
|
||||
lua_pushboolean(L, false);
|
||||
}
|
||||
|
|
|
@ -93,7 +93,7 @@ private:
|
|||
// Returns true if the item completely fits into the list
|
||||
static int l_room_for_item(lua_State *L);
|
||||
|
||||
// contains_item(self, listname, itemstack or itemstring or table or nil) -> true/false
|
||||
// contains_item(self, listname, itemstack or itemstring or table or nil, [match_meta]) -> true/false
|
||||
// Returns true if the list contains the given count of the given item name
|
||||
static int l_contains_item(lua_State *L);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue