@@ -12,6 +12,10 @@ export const FogOfWar = L.Layer.extend({
1212 this . _canvas . style . height = "100%" ;
1313 this . _canvas . style . pointerEvents = "none" ;
1414 this . _canvas . style . zIndex = "1000" ;
15+
16+ // Mark as protected to prevent removal
17+ this . _canvas . setAttribute ( "data-protected" , "true" ) ;
18+ this . _isProtected = true ;
1519
1620 const container = map . getContainer ( ) ;
1721 container . appendChild ( this . _canvas ) ;
@@ -21,14 +25,164 @@ export const FogOfWar = L.Layer.extend({
2125 map . on ( "moveend resize zoomend zoom" , this . _update , this ) ;
2226 map . on ( "viewreset move" , this . _update , this ) ;
2327
28+ // Set up watchers to prevent tampering
29+ this . _setupProtection ( ) ;
30+
2431 this . _update ( ) ;
2532 } ,
2633
2734 onRemove : function ( map ) {
35+ // Prevent removal - re-add immediately
36+ if ( this . _isProtected ) {
37+ setTimeout ( ( ) => {
38+ if ( this . _map && ! this . _map . hasLayer ( this ) ) {
39+ this . addTo ( this . _map ) ;
40+ }
41+ } , 0 ) ;
42+ return ;
43+ }
2844 L . DomUtil . remove ( this . _canvas ) ;
2945 map . off ( "moveend resize zoomend zoom viewreset move" , this . _update , this ) ;
3046 } ,
3147
48+ _setupProtection : function ( ) {
49+ // Generate random intervals
50+ const randomInterval = ( min , max ) => Math . floor ( Math . random ( ) * ( max - min + 1 ) ) + min ;
51+
52+ // Protection 1: Monitor canvas existence with random intervals
53+ const monitors = [ ] ;
54+ for ( let i = 0 ; i < 5 ; i ++ ) {
55+ const interval = setInterval ( ( ) => {
56+ if ( ! this . _canvas || ! this . _canvas . parentNode ) {
57+ this . _restoreCanvas ( ) ;
58+ }
59+ // Check if canvas is hidden
60+ if ( this . _canvas ) {
61+ const computed = window . getComputedStyle ( this . _canvas ) ;
62+ if (
63+ computed . display === "none" ||
64+ computed . visibility === "hidden" ||
65+ parseFloat ( computed . opacity ) < 0.99
66+ ) {
67+ this . _canvas . style . cssText = `
68+ position: absolute !important;
69+ top: 0 !important;
70+ left: 0 !important;
71+ width: 100% !important;
72+ height: 100% !important;
73+ pointer-events: none !important;
74+ z-index: 1000 !important;
75+ display: block !important;
76+ visibility: visible !important;
77+ opacity: 1 !important;
78+ ` ;
79+ }
80+ }
81+ } , randomInterval ( 30 , 150 ) ) ;
82+ monitors . push ( interval ) ;
83+ }
84+
85+ // Protection 2: MutationObserver to watch for canvas removal
86+ if ( typeof MutationObserver !== "undefined" ) {
87+ this . _observer = new MutationObserver ( ( mutations ) => {
88+ for ( let mutation of mutations ) {
89+ if ( mutation . type === "childList" && mutation . removedNodes . length > 0 ) {
90+ for ( let node of mutation . removedNodes ) {
91+ if ( node === this . _canvas ) {
92+ setTimeout ( ( ) => this . _restoreCanvas ( ) , randomInterval ( 0 , 50 ) ) ;
93+ }
94+ }
95+ }
96+ if ( mutation . type === "attributes" && mutation . target === this . _canvas ) {
97+ setTimeout ( ( ) => this . _restoreCanvas ( ) , randomInterval ( 0 , 50 ) ) ;
98+ }
99+ }
100+ } ) ;
101+ this . _observer . observe ( this . _map . getContainer ( ) , {
102+ childList : true ,
103+ subtree : true ,
104+ attributes : true ,
105+ attributeFilter : [ "style" , "class" , "id" ] ,
106+ } ) ;
107+
108+ // Additional observer for entire document
109+ this . _docObserver = new MutationObserver ( ( ) => {
110+ if ( ! this . _canvas . parentNode ) {
111+ setTimeout ( ( ) => this . _restoreCanvas ( ) , randomInterval ( 0 , 50 ) ) ;
112+ }
113+ } ) ;
114+ this . _docObserver . observe ( document . body , { childList : true , subtree : true } ) ;
115+ }
116+
117+ // Protection 3: Monitor layer attachment with random intervals
118+ for ( let i = 0 ; i < 3 ; i ++ ) {
119+ const interval = setInterval ( ( ) => {
120+ if ( this . _map && ! this . _map . hasLayer ( this ) ) {
121+ this . addTo ( this . _map ) ;
122+ }
123+ } , randomInterval ( 100 , 400 ) ) ;
124+ monitors . push ( interval ) ;
125+ }
126+
127+ // Protection 4: Lock canvas properties
128+ if ( this . _canvas ) {
129+ Object . defineProperty ( this . _canvas , "className" , {
130+ value : "leaflet-fog-of-war" ,
131+ writable : false ,
132+ configurable : false ,
133+ } ) ;
134+
135+ // Prevent canvas removal via replaceWith
136+ const originalReplaceWith = this . _canvas . replaceWith ;
137+ this . _canvas . replaceWith = function ( ) {
138+ console . warn ( "⚠️ Cannot replace protected canvas" ) ;
139+ return this ;
140+ } ;
141+ }
142+
143+ // Protection 5: Monitor requestAnimationFrame
144+ const rafMonitor = ( ) => {
145+ if ( this . _canvas && ! this . _canvas . parentNode ) {
146+ this . _restoreCanvas ( ) ;
147+ }
148+ if ( this . _map && ! this . _map . hasLayer ( this ) ) {
149+ this . addTo ( this . _map ) ;
150+ }
151+ requestAnimationFrame ( rafMonitor ) ;
152+ } ;
153+ requestAnimationFrame ( rafMonitor ) ;
154+
155+ // Store monitor IDs
156+ this . _monitors = monitors ;
157+
158+ // Protection 6: Prevent monitor clearing
159+ Object . freeze ( this . _monitors ) ;
160+ } ,
161+
162+ _restoreCanvas : function ( ) {
163+ if ( ! this . _canvas ) {
164+ this . _canvas = L . DomUtil . create ( "canvas" , "leaflet-fog-of-war" ) ;
165+ }
166+ this . _canvas . style . position = "absolute" ;
167+ this . _canvas . style . top = "0" ;
168+ this . _canvas . style . left = "0" ;
169+ this . _canvas . style . width = "100%" ;
170+ this . _canvas . style . height = "100%" ;
171+ this . _canvas . style . pointerEvents = "none" ;
172+ this . _canvas . style . zIndex = "1000" ;
173+ this . _canvas . style . display = "" ;
174+ this . _canvas . style . visibility = "visible" ;
175+ this . _canvas . style . opacity = "1" ;
176+ this . _canvas . setAttribute ( "data-protected" , "true" ) ;
177+
178+ const container = this . _map . getContainer ( ) ;
179+ if ( ! this . _canvas . parentNode ) {
180+ container . appendChild ( this . _canvas ) ;
181+ }
182+ this . _ctx = this . _canvas . getContext ( "2d" ) ;
183+ this . _update ( ) ;
184+ } ,
185+
32186 _update : function ( ) {
33187 if ( ! this . _map || ! this . _canvas || ! S . playerList ) return ;
34188
0 commit comments