TLDR
Whenever LuaEntity.color is set, defines.events.on_entity_color_changed will be raised, even if old and new color are the same. Please consider raising the event only if old and new color differ! Alternatively, it would also help if the old color was added to the event data so that mods can easily compare it with the new color.What?
Start a new game and run the following commands from the console:Code: Select all
/c script.on_event(defines.events.on_entity_color_changed, function(event) game.print(string.format("New color of %s: %s", event.entity.name.." ("..event.entity.unit_number..")", serpent.line(event.entity.color))) end)
/c p = game.player; v = p.surface.create_entity{name = "car", position = {p.position.x + 2, p.position.y}, force = p.force}
/c v.color = {r = 1}
/c v.color = {r = 1}
Use case
My mods Autodrive and GCKI will make sure that the vehicles they control will always have the same color as the player who controls them (this could be somebody who is neither driver nor passenger). They keep track of the color of vehicles based on a prototype they support from the time the vehicle is created until it is mined or destroyed. If a player manually changes the color of a vehicle controlled by one or both mods (e.g. via the native GUI of spider-vehicles or with mods like Custom Color), my mods will update the stored color and reset it to that of the player controlling the vehicle. After the last mod has stopped to control a given vehicle, its color will be reset to the stored color.If both mods are active, resetting vehicle colors involves running several checks and remote calls which cause some overhead that would be unnecessary if the event had been raised although old and new color are the same.
Not our business, the mods should handle this!
Working on it from both of my mods' ends, I've already invested a lot of time on making color changes and responses to color changes as efficient as possible. My optimizations so far:- If both mods are active, one of them ("server") will take care of color changes for the other ("client") as well. Only the server will listen to on_entity_color_changed and use remote calls to tell the client it should update its data.
- Both mods will store and update the original color of any vehicle that is based on a prototype supported by one or both mods. In response to on_configuration_changed, the server will initiate synchronizing the list of original colors with the client.
- Instead of using remote calls to ask the other mod for the player controlling a vehicle each time one of the mods wants to change colors (pull), they now inform each other per remote call when they start/stop controlling a vehicle (push). If a vehicle is controlled by both mods, the player controlling it on the other end will be stored with the vehicle data. Thus, when changing colors I rely on locally stored data whenever possible and only use remote calls if a vehicle is controlled by just one mod. (If one of the mods is removed, obsolete data will be deleted during cleanup.)
- If both mods are active and the client wants to change a vehicle's color, it will just update its data and ask the server to change the color (server will skip the callback to client in this case).
- The color of a vehicle will only be changed if old and new color are different.
- Before a mod changes the color of a vehicle, it will store entity and expected new color. This way, it can skip the on_entity_color_changed event that was raised in response to its own color changes.
Code: Select all
util.table.compare(old_color, new_color)
Code: Select all
require('util')
-- Map default Factorio player colors to color names
assert.colors = {
default = {r = 1.000, g = 0.630, b = 0.259},
red = {r = 1.000, g = 0.166, b = 0.141},
green = {r = 0.173, g = 0.824, b = 0.250},
blue = {r = 0.343, g = 0.683, b = 1.000},
orange = {r = 1.000, g = 0.630, b = 0.259},
yellow = {r = 1.000, g = 0.828, b = 0.231},
pink = {r = 1.000, g = 0.520, b = 0.633},
purple = {r = 0.821, g = 0.440, b = 0.998},
white = {r = 0.900, g = 0.900, b = 0.900},
black = {r = 0.500, g = 0.500, b = 0.500},
gray = {r = 0.700, g = 0.700, b = 0.700},
brown = {r = 0.757, g = 0.522, b = 0.371},
cyan = {r = 0.335, g = 0.918, b = 0.866},
acid = {r = 0.708, g = 0.996, b = 0.134},
-- This is the default color for vehicles without an owner/locker in AD/GCKI!
no_color = {r = 0, g = 0, b = 0, a = 0.5}
}
-- Get color from name, hex, or table
assert.ascertain_color = function(color)
assert.assert(color, {"table", "string", "nil"})
local ret
local c = type(color)
-- Named colors or hex colors
if c == "string" then
ret = assert.colors[color] or
(color:match("^#*[0-9a-fA-F]+$") and util.color(color))
if ret then
ret.a = 1
end
-- Lua color
elseif c == "table" then
ret = {
r = color.r or color[1] or 0,
g = color.g or color[2] or 0,
b = color.b or color[3] or 0,
a = color.a or color[4] or 1,
}
end
return ret
end
-- Compare two colors. Returns true if the colors are the same
assert.compare_colors = function(c1, c2)
c1 = assert.ascertain_color(c1)
c2 = assert.ascertain_color(c2)
return not (c1 or c2) or
( c1 and c2 and util.table.compare(c1, c2) )
end