@@ -208,25 +208,25 @@ export class Mask implements CustomArgType {
208208 }
209209 } else if ( token . value == "#" ) {
210210 const t = tokens . next ( ) ;
211- if ( t . value == "slope" ) {
212- let t = tokens . next ( ) ;
213- if ( t . value != "[" ) throwTokenError ( t ) ;
214- t = tokens . next ( ) ;
215- if ( t . type != "number" ) throwTokenError ( t ) ;
216- const lowerAngle = < number > t . value ;
217- t = tokens . next ( ) ;
218- if ( t . value != ":" ) throwTokenError ( t ) ;
219- t = tokens . next ( ) ;
220- if ( t . type != "number" ) throwTokenError ( t ) ;
221- const upperAngle = < number > t . value ;
222- t = tokens . next ( ) ;
223- if ( t . value != "]" ) throwTokenError ( t ) ;
224-
225- out . push ( new SlopeMaskNode ( nodeToken ( ) , lowerAngle , upperAngle ) ) ;
226- } else if ( t . value == "existing" ) {
211+ if ( t . value == "existing" ) {
227212 out . push ( new ExistingMaskNode ( nodeToken ( ) ) ) ;
228213 } else if ( t . value == "surface" || t . value == "exposed" ) {
229- out . push ( new SurfaceMaskNode ( nodeToken ( ) ) ) ;
214+ let lowerAngle : number | undefined ;
215+ let upperAngle : number | undefined ;
216+ if ( tokens . peek ( ) . value == "[" ) {
217+ tokens . next ( ) ;
218+ let t = tokens . next ( ) ;
219+ if ( t . type != "number" ) throwTokenError ( t ) ;
220+ lowerAngle = < number > t . value ;
221+ t = tokens . next ( ) ;
222+ if ( t . value != ":" ) throwTokenError ( t ) ;
223+ t = tokens . next ( ) ;
224+ if ( t . type != "number" ) throwTokenError ( t ) ;
225+ upperAngle = < number > t . value ;
226+ t = tokens . next ( ) ;
227+ if ( t . value != "]" ) throwTokenError ( t ) ;
228+ }
229+ out . push ( new SurfaceMaskNode ( nodeToken ( ) , lowerAngle , upperAngle ) ) ;
230230 } else if ( t . value == "shadow" ) {
231231 out . push ( new ShadowMaskNode ( nodeToken ( ) ) ) ;
232232 } else if ( t . value == "#" ) {
@@ -384,22 +384,61 @@ export class SurfaceMaskNode extends MaskNode {
384384 readonly prec = - 1 ;
385385 readonly opCount = 0 ;
386386
387+ static readonly testDistance = 2 ;
388+ static readonly testOffsets = {
389+ "-z" : Vector . from ( Direction . North ) . mul ( SurfaceMaskNode . testDistance ) ,
390+ "+z" : Vector . from ( Direction . South ) . mul ( SurfaceMaskNode . testDistance ) ,
391+ "+x" : Vector . from ( Direction . East ) . mul ( SurfaceMaskNode . testDistance ) ,
392+ "-x" : Vector . from ( Direction . West ) . mul ( SurfaceMaskNode . testDistance ) ,
393+ } ;
394+
395+ constructor (
396+ token : Token ,
397+ public lowerAngle ?: number ,
398+ public upperAngle ?: number
399+ ) {
400+ super ( token ) ;
401+ }
402+
387403 matchesBlock ( block : BlockUnit ) {
388404 const loc = Vector . from ( block . location ) ;
389405 const dim = block . dimension ;
390406 const isEmpty = ( loc : Vector3 ) => {
391407 return dim . getBlock ( loc ) . isAir ;
392408 } ;
393409
394- return (
410+ const isSurface =
395411 ! isEmpty ( loc ) &&
396412 ( isEmpty ( loc . offset ( 0 , 1 , 0 ) ) ||
397413 isEmpty ( loc . offset ( 0 , - 1 , 0 ) ) ||
398414 isEmpty ( loc . offset ( - 1 , 0 , 0 ) ) ||
399415 isEmpty ( loc . offset ( 1 , 0 , 0 ) ) ||
400416 isEmpty ( loc . offset ( 0 , 0 , - 1 ) ) ||
401- isEmpty ( loc . offset ( 0 , 0 , 1 ) ) )
402- ) ;
417+ isEmpty ( loc . offset ( 0 , 0 , 1 ) ) ) ;
418+
419+ if ( ! isSurface ) return false ;
420+ if ( this . lowerAngle === undefined || this . upperAngle === undefined ) return true ;
421+
422+ const heights : { [ dir : string ] : number } = { } ;
423+
424+ for ( const [ entry , offset ] of Object . entries ( SurfaceMaskNode . testOffsets ) ) {
425+ const start = Vector . add ( block , offset ) . add ( 0.5 ) ;
426+
427+ let testBlock = block . dimension . getBlock ( start ) ;
428+ while ( testBlock ?. isSolid ) {
429+ testBlock = testBlock . above ( ) ;
430+ start . y ++ ;
431+ }
432+
433+ const hit = block . dimension . getBlockFromRay ( start , Vector . DOWN , { includePassableBlocks : false , includeLiquidBlocks : false } ) ;
434+ if ( hit ) heights [ entry ] = hit . block . y + hit . faceLocation . y ;
435+ }
436+
437+ const distance2 = SurfaceMaskNode . testDistance * 2 ;
438+ const slopeX = Math . abs ( heights [ "+z" ] - heights [ "-z" ] ) / distance2 ;
439+ const slopeZ = Math . abs ( heights [ "+x" ] - heights [ "-x" ] ) / distance2 ;
440+ const pitch = 90 - Math . atan ( 1 / Math . sqrt ( slopeX ** 2 + slopeZ ** 2 ) ) * ( 180 / Math . PI ) ;
441+ return pitch >= this . lowerAngle && pitch <= this . upperAngle ;
403442 }
404443}
405444
@@ -442,50 +481,6 @@ export class ShadowMaskNode extends MaskNode {
442481 }
443482}
444483
445- export class SlopeMaskNode extends MaskNode {
446- readonly prec = - 1 ;
447- readonly opCount = 0 ;
448-
449- static readonly testDistance = 2 ;
450- static readonly testOffsets = {
451- "-z" : Vector . from ( Direction . North ) . mul ( SlopeMaskNode . testDistance ) ,
452- "+z" : Vector . from ( Direction . South ) . mul ( SlopeMaskNode . testDistance ) ,
453- "+x" : Vector . from ( Direction . East ) . mul ( SlopeMaskNode . testDistance ) ,
454- "-x" : Vector . from ( Direction . West ) . mul ( SlopeMaskNode . testDistance ) ,
455- } ;
456-
457- constructor (
458- token : Token ,
459- public lowerAngle : number ,
460- public upperAngle : number
461- ) {
462- super ( token ) ;
463- }
464-
465- matchesBlock ( block : BlockUnit ) {
466- const heights : { [ dir : string ] : number } = { } ;
467-
468- for ( const [ entry , offset ] of Object . entries ( SlopeMaskNode . testOffsets ) ) {
469- const start = Vector . add ( block , offset ) . add ( 0.5 ) ;
470-
471- let testBlock = block . dimension . getBlock ( start ) ;
472- while ( testBlock ?. isSolid ) {
473- testBlock = testBlock . above ( ) ;
474- start . y ++ ;
475- }
476-
477- const hit = block . dimension . getBlockFromRay ( start , Vector . DOWN , { includePassableBlocks : false , includeLiquidBlocks : false } ) ;
478- if ( hit ) heights [ entry ] = hit . block . y + hit . faceLocation . y ;
479- }
480-
481- const distance2 = SlopeMaskNode . testDistance * 2 ;
482- const slopeX = Math . abs ( heights [ "+z" ] - heights [ "-z" ] ) / distance2 ;
483- const slopeZ = Math . abs ( heights [ "+x" ] - heights [ "-x" ] ) / distance2 ;
484- const pitch = 90 - Math . atan ( 1 / Math . sqrt ( slopeX ** 2 + slopeZ ** 2 ) ) * ( 180 / Math . PI ) ;
485- return pitch >= this . lowerAngle && pitch <= this . upperAngle ;
486- }
487- }
488-
489484export class TagMaskNode extends MaskNode {
490485 readonly prec = - 1 ;
491486 readonly opCount = 0 ;
0 commit comments