Prevent players from hiding Fog of War layers
Some checks are pending
Windows Release / windows-x86_64 (push) Waiting to run
Some checks are pending
Windows Release / windows-x86_64 (push) Waiting to run
Clients could toggle fog visibility (and fade alpha); DisplayData synced that to everyone and defeated FoW. Block client set_visible/set_alpha, clamp host-side DisplayData updates, and ignore eye toggles for fog. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
fea392b65d
commit
3140f9bb55
4 changed files with 31 additions and 3 deletions
2
FORK.md
2
FORK.md
|
|
@ -33,4 +33,4 @@ Not automatic on import. Choose **Paste Image + Freistellen** from the canvas ri
|
|||
|
||||
## Fog of War / layer lock (host)
|
||||
|
||||
In the layer panel (host / local file only): mark a leaf layer as **Fog of War layer** (must sit **above** the content it covers), then paint fog with brush/shapes on that layer. Players receive a **stripped** world — only objects **fully** covered by opaque fog (not merely overlapping) are omitted from join sync and from their save. Partially covered images stay. Moving or reshaping fog (or content under it) live-updates clients: newly covered objects are unloaded, revealed ones are sent again with their resources. The host file stays complete. Fog draws at the layer’s real alpha (1.0 = fully opaque for host and players). **Lock for players** blocks client edits on a normal layer; fog layers are always locked for players (move/edit/erase rejected on the host).
|
||||
In the layer panel (host / local file only): mark a leaf layer as **Fog of War layer** (must sit **above** the content it covers), then paint fog with brush/shapes on that layer. Players receive a **stripped** world — only objects **fully** covered by opaque fog (not merely overlapping) are omitted from join sync and from their save. Partially covered images stay. Moving or reshaping fog (or content under it) live-updates clients: newly covered objects are unloaded, revealed ones are sent again with their resources. The host file stays complete. Fog draws at the layer’s real alpha (1.0 = fully opaque for host and players). **Lock for players** blocks client edits on a normal layer; fog layers are always locked for players (move/edit/erase rejected on the host). Players also **cannot hide or fade** a fog layer (eye / alpha); only the host can toggle fog visibility, and the host rejects client DisplayData that would strip FoW.
|
||||
|
|
|
|||
0
linuxinstall/install-local.sh
Normal file → Executable file
0
linuxinstall/install-local.sh
Normal file → Executable file
|
|
@ -20,6 +20,7 @@
|
|||
#include "DrawingProgramLayerFolder.hpp"
|
||||
#include <cereal/types/string.hpp>
|
||||
#include "DrawingProgramLayer.hpp"
|
||||
#include "FogStripper.hpp"
|
||||
#include "../../World.hpp"
|
||||
#include "../../MainProgram.hpp"
|
||||
#include "SerializedBlendMode.hpp"
|
||||
|
|
@ -258,6 +259,9 @@ const std::string& DrawingProgramLayerListItem::get_name() const {
|
|||
}
|
||||
|
||||
void DrawingProgramLayerListItem::set_alpha(DrawingProgramLayerManager& layerMan, float newAlpha) const {
|
||||
// Players must not fade fog out — same authority as visibility.
|
||||
if(is_fog_layer() && !FogStripper::world_is_host(layerMan.drawP.world))
|
||||
return;
|
||||
if(displayData && displayData->alpha != newAlpha) {
|
||||
displayData->alpha = newAlpha;
|
||||
layerMan.drawP.drawCache.clear_own_cached_surfaces();
|
||||
|
|
@ -270,6 +274,9 @@ float DrawingProgramLayerListItem::get_alpha() const {
|
|||
}
|
||||
|
||||
void DrawingProgramLayerListItem::set_visible(DrawingProgramLayerManager& layerMan, bool newVisible) const {
|
||||
// Fog of War is host-controlled; clients hiding it would sync and strip FoW for everyone.
|
||||
if(is_fog_layer() && !FogStripper::world_is_host(layerMan.drawP.world))
|
||||
return;
|
||||
if(displayData && displayData->visible != newVisible) {
|
||||
displayData->visible = newVisible;
|
||||
layerMan.drawP.drawCache.clear_own_cached_surfaces();
|
||||
|
|
@ -393,6 +400,24 @@ void DrawingProgramLayerListItem::register_class(World& w) {
|
|||
}
|
||||
});
|
||||
w.delayedUpdateObjectManager.register_class<DisplayData>(w.netObjMan, NetworkingObjects::DelayUpdateSerializedClassManager::CustomConstructors<DisplayData>{
|
||||
.readUpdate = [](DisplayData& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr<NetServer::ClientData>& c) {
|
||||
DisplayData incoming;
|
||||
a(incoming);
|
||||
// Client→host: never allow stripping fog, unlocking, hiding, or fading fog.
|
||||
if(c) {
|
||||
if(o.fogLayer || incoming.fogLayer) {
|
||||
incoming.fogLayer = true;
|
||||
incoming.playerLocked = true;
|
||||
incoming.visible = true;
|
||||
incoming.alpha = o.alpha;
|
||||
}
|
||||
else {
|
||||
incoming.fogLayer = false;
|
||||
incoming.playerLocked = o.playerLocked;
|
||||
}
|
||||
}
|
||||
o = incoming;
|
||||
},
|
||||
.postUpdateFunc = [&](DisplayData& o) {
|
||||
(void)o;
|
||||
w.drawProg.drawCache.clear_own_cached_surfaces();
|
||||
|
|
|
|||
|
|
@ -144,11 +144,14 @@ void DrawingProgramLayerManagerGUI::setup_list_gui() {
|
|||
});
|
||||
}
|
||||
gui.set_z_index_keep_clipping_region(gui.get_z_index() + 1, [&] {
|
||||
// Fog stays visible for players — eye is informational only on clients.
|
||||
const bool fogVisibilityLocked = layer->is_fog_layer() && !FogStripper::world_is_host(world);
|
||||
svg_icon_button(gui, "visible button", layer->get_visible() ? "data/icons/eyeopen.svg" : "data/icons/eyeclose.svg", {
|
||||
.drawType = SelectableButton::DrawType::TRANSPARENT_ALL,
|
||||
.size = TreeListing::ENTRY_HEIGHT,
|
||||
.onClick = [&, layer] {
|
||||
layer->set_visible(layerMan, !layer->get_visible());
|
||||
.onClick = [&, layer, fogVisibilityLocked] {
|
||||
if(!fogVisibilityLocked)
|
||||
layer->set_visible(layerMan, !layer->get_visible());
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue