2023-08-21 23:04:08 +00:00
/ *
* Copyright ( c ) 2019 - 2022 GeyserMC . http : //geysermc.org
*
* Permission is hereby granted , free of charge , to any person obtaining a copy
* of this software and associated documentation files ( the " Software " ) , to deal
* in the Software without restriction , including without limitation the rights
* to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
* copies of the Software , and to permit persons to whom the Software is
* furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE .
*
* @author GeyserMC
* @link https : //github.com/GeyserMC/Geyser
* /
package org.geysermc.geyser.level.block ;
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap ;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap ;
import it.unimi.dsi.fastutil.objects.Object2ObjectMaps ;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap ;
import lombok.Value ;
import org.checkerframework.checker.nullness.qual.NonNull ;
2023-11-09 07:44:13 +00:00
import org.checkerframework.checker.nullness.qual.Nullable ;
2023-08-21 23:04:08 +00:00
import org.geysermc.geyser.api.block.custom.component.BoxComponent ;
import org.geysermc.geyser.api.block.custom.component.CustomBlockComponents ;
import org.geysermc.geyser.api.block.custom.component.GeometryComponent ;
import org.geysermc.geyser.api.block.custom.component.MaterialInstance ;
import org.geysermc.geyser.api.block.custom.component.PlacementConditions ;
import org.geysermc.geyser.api.block.custom.component.TransformationComponent ;
import java.util.HashSet ;
import java.util.List ;
import java.util.Map ;
import java.util.Set ;
2023-11-09 07:44:13 +00:00
import java.util.Objects ;
2023-08-21 23:04:08 +00:00
@Value
public class GeyserCustomBlockComponents implements CustomBlockComponents {
BoxComponent selectionBox ;
BoxComponent collisionBox ;
String displayName ;
GeometryComponent geometry ;
Map < String , MaterialInstance > materialInstances ;
List < PlacementConditions > placementFilter ;
Float destructibleByMining ;
Float friction ;
Integer lightEmission ;
Integer lightDampening ;
TransformationComponent transformation ;
boolean unitCube ;
boolean placeAir ;
Set < String > tags ;
2024-01-31 10:21:06 +00:00
private GeyserCustomBlockComponents ( Builder builder ) {
2023-08-21 23:04:08 +00:00
this . selectionBox = builder . selectionBox ;
this . collisionBox = builder . collisionBox ;
this . displayName = builder . displayName ;
this . geometry = builder . geometry ;
if ( builder . materialInstances . isEmpty ( ) ) {
this . materialInstances = Object2ObjectMaps . emptyMap ( ) ;
} else {
this . materialInstances = Object2ObjectMaps . unmodifiable ( new Object2ObjectArrayMap < > ( builder . materialInstances ) ) ;
}
this . placementFilter = builder . placementFilter ;
this . destructibleByMining = builder . destructibleByMining ;
this . friction = builder . friction ;
this . lightEmission = builder . lightEmission ;
this . lightDampening = builder . lightDampening ;
this . transformation = builder . transformation ;
this . unitCube = builder . unitCube ;
this . placeAir = builder . placeAir ;
if ( builder . tags . isEmpty ( ) ) {
this . tags = Set . of ( ) ;
} else {
this . tags = Set . copyOf ( builder . tags ) ;
}
}
@Override
public BoxComponent selectionBox ( ) {
return selectionBox ;
}
@Override
public BoxComponent collisionBox ( ) {
return collisionBox ;
}
@Override
public String displayName ( ) {
return displayName ;
}
@Override
public GeometryComponent geometry ( ) {
return geometry ;
}
@Override
public @NonNull Map < String , MaterialInstance > materialInstances ( ) {
return materialInstances ;
}
@Override
public List < PlacementConditions > placementFilter ( ) {
return placementFilter ;
}
@Override
public Float destructibleByMining ( ) {
return destructibleByMining ;
}
@Override
public Float friction ( ) {
return friction ;
}
@Override
public Integer lightEmission ( ) {
return lightEmission ;
}
@Override
public Integer lightDampening ( ) {
return lightDampening ;
}
@Override
public TransformationComponent transformation ( ) {
return transformation ;
}
@Override
public boolean unitCube ( ) {
return unitCube ;
}
@Override
public boolean placeAir ( ) {
return placeAir ;
}
@Override
2023-11-09 07:44:13 +00:00
public @NonNull Set < String > tags ( ) {
2023-08-21 23:04:08 +00:00
return tags ;
}
2024-01-31 10:21:06 +00:00
public static class Builder implements CustomBlockComponents . Builder {
2023-08-21 23:04:08 +00:00
protected BoxComponent selectionBox ;
protected BoxComponent collisionBox ;
protected String displayName ;
protected GeometryComponent geometry ;
protected final Object2ObjectMap < String , MaterialInstance > materialInstances = new Object2ObjectOpenHashMap < > ( ) ;
protected List < PlacementConditions > placementFilter ;
protected Float destructibleByMining ;
protected Float friction ;
protected Integer lightEmission ;
protected Integer lightDampening ;
protected TransformationComponent transformation ;
protected boolean unitCube = false ;
protected boolean placeAir = false ;
2023-11-09 07:44:13 +00:00
protected Set < String > tags = new HashSet < > ( ) ;
2023-08-21 23:04:08 +00:00
private void validateBox ( BoxComponent box ) {
if ( box = = null ) {
return ;
}
if ( box . sizeX ( ) < 0 | | box . sizeY ( ) < 0 | | box . sizeZ ( ) < 0 ) {
throw new IllegalArgumentException ( " Box size must be non-negative. " ) ;
}
float minX = box . originX ( ) + 8 ;
float minY = box . originY ( ) ;
float minZ = box . originZ ( ) + 8 ;
float maxX = minX + box . sizeX ( ) ;
float maxY = minY + box . sizeY ( ) ;
float maxZ = minZ + box . sizeZ ( ) ;
if ( minX < 0 | | minY < 0 | | minZ < 0 | | maxX > 16 | | maxY > 16 | | maxZ > 16 ) {
throw new IllegalArgumentException ( " Box bounds must be within (0, 0, 0) and (16, 16, 16). Recieved: ( " + minX + " , " + minY + " , " + minZ + " ) to ( " + maxX + " , " + maxY + " , " + maxZ + " ) " ) ;
}
}
@Override
public Builder selectionBox ( BoxComponent selectionBox ) {
validateBox ( selectionBox ) ;
this . selectionBox = selectionBox ;
return this ;
}
@Override
public Builder collisionBox ( BoxComponent collisionBox ) {
validateBox ( collisionBox ) ;
this . collisionBox = collisionBox ;
return this ;
}
@Override
public Builder displayName ( String displayName ) {
this . displayName = displayName ;
return this ;
}
@Override
public Builder geometry ( GeometryComponent geometry ) {
this . geometry = geometry ;
return this ;
}
@Override
2023-11-09 07:44:13 +00:00
public Builder materialInstance ( @NonNull String name , @NonNull MaterialInstance materialInstance ) {
2023-08-21 23:04:08 +00:00
this . materialInstances . put ( name , materialInstance ) ;
return this ;
}
@Override
public Builder placementFilter ( List < PlacementConditions > placementFilter ) {
this . placementFilter = placementFilter ;
return this ;
}
@Override
public Builder destructibleByMining ( Float destructibleByMining ) {
if ( destructibleByMining ! = null & & destructibleByMining < 0 ) {
throw new IllegalArgumentException ( " Destructible by mining must be non-negative " ) ;
}
this . destructibleByMining = destructibleByMining ;
return this ;
}
@Override
public Builder friction ( Float friction ) {
if ( friction ! = null ) {
if ( friction < 0 | | friction > 1 ) {
throw new IllegalArgumentException ( " Friction must be in the range 0-1 " ) ;
}
}
this . friction = friction ;
return this ;
}
@Override
public Builder lightEmission ( Integer lightEmission ) {
if ( lightEmission ! = null ) {
if ( lightEmission < 0 | | lightEmission > 15 ) {
throw new IllegalArgumentException ( " Light emission must be in the range 0-15 " ) ;
}
}
this . lightEmission = lightEmission ;
return this ;
}
@Override
public Builder lightDampening ( Integer lightDampening ) {
if ( lightDampening ! = null ) {
if ( lightDampening < 0 | | lightDampening > 15 ) {
throw new IllegalArgumentException ( " Light dampening must be in the range 0-15 " ) ;
}
}
this . lightDampening = lightDampening ;
return this ;
}
@Override
public Builder transformation ( TransformationComponent transformation ) {
if ( transformation . rx ( ) % 90 ! = 0 | | transformation . ry ( ) % 90 ! = 0 | | transformation . rz ( ) % 90 ! = 0 ) {
throw new IllegalArgumentException ( " Rotation of transformation must be a multiple of 90 degrees. " ) ;
}
this . transformation = transformation ;
return this ;
}
@Override
public Builder unitCube ( boolean unitCube ) {
this . unitCube = unitCube ;
return this ;
}
@Override
public Builder placeAir ( boolean placeAir ) {
this . placeAir = placeAir ;
return this ;
}
@Override
2023-11-09 07:44:13 +00:00
public Builder tags ( @Nullable Set < String > tags ) {
this . tags = Objects . requireNonNullElseGet ( tags , Set : : of ) ;
2023-08-21 23:04:08 +00:00
return this ;
}
@Override
public CustomBlockComponents build ( ) {
return new GeyserCustomBlockComponents ( this ) ;
}
}
}