2021-11-18 03:02:38 +00:00
/ *
2022-01-01 19:03:05 +00:00
* Copyright ( c ) 2019 - 2022 GeyserMC . http : //geysermc.org
2021-11-18 03:02:38 +00:00
*
* 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
* /
2021-11-20 21:34:30 +00:00
package org.geysermc.geyser.entity ;
2021-11-18 03:02:38 +00:00
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata ;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.MetadataType ;
import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType ;
2022-05-07 19:13:11 +00:00
import com.nukkitx.nbt.NbtMap ;
import com.nukkitx.nbt.NbtType ;
2021-11-18 03:02:38 +00:00
import it.unimi.dsi.fastutil.objects.ObjectArrayList ;
import lombok.Setter ;
2022-05-07 19:13:11 +00:00
import lombok.ToString ;
2021-11-18 03:02:38 +00:00
import lombok.experimental.Accessors ;
2021-11-20 21:34:30 +00:00
import org.geysermc.geyser.GeyserImpl ;
2022-05-07 19:13:11 +00:00
import org.geysermc.geyser.api.entity.EntityDefinition ;
import org.geysermc.geyser.api.entity.EntityIdentifier ;
2021-11-20 21:34:30 +00:00
import org.geysermc.geyser.entity.factory.EntityFactory ;
2021-11-20 23:29:46 +00:00
import org.geysermc.geyser.entity.type.Entity ;
2021-11-20 21:34:30 +00:00
import org.geysermc.geyser.registry.Registries ;
2021-11-20 23:29:46 +00:00
import org.geysermc.geyser.translator.entity.EntityMetadataTranslator ;
2022-05-07 19:13:11 +00:00
import org.geysermc.geyser.util.EntityUtils ;
2021-11-18 03:02:38 +00:00
2022-05-07 19:13:11 +00:00
import java.util.ArrayList ;
2021-11-18 03:02:38 +00:00
import java.util.List ;
import java.util.Locale ;
2022-05-07 19:13:11 +00:00
import java.util.Optional ;
2021-11-18 03:02:38 +00:00
import java.util.function.BiConsumer ;
/ * *
* Represents data for an entity . This includes properties such as height and width , as well as the list of entity
* metadata translators needed to translate the properties sent from the server . The translators are structured in such
* a way that inserting a new one ( for example in version updates ) is convenient .
*
* @param < T > the entity type this definition represents
* /
2022-05-07 19:13:11 +00:00
public record GeyserEntityDefinition < T extends Entity > ( EntityFactory < T > factory , EntityType entityType , EntityIdentifier entityIdentifier ,
float width , float height , float offset , List < EntityMetadataTranslator < ? super T , ? , ? > > translators ,
boolean custom ) implements EntityDefinition {
2021-11-18 03:02:38 +00:00
2022-05-07 19:13:11 +00:00
public static < T extends Entity > EntityDefinitionBuilder < T > inherited ( EntityFactory < T > factory , GeyserEntityDefinition < ? super T > parent ) {
return new EntityDefinitionBuilder < > ( factory , parent . entityType , parent . entityIdentifier , parent . width , parent . height , parent . offset , new ObjectArrayList < > ( parent . translators ) ) ;
2021-11-18 03:02:38 +00:00
}
2022-05-07 19:13:11 +00:00
public static < T extends Entity > EntityDefinitionBuilder < T > builder ( EntityFactory < T > factory ) {
return new EntityDefinitionBuilder < > ( factory ) ;
2021-11-18 03:02:38 +00:00
}
2021-11-20 19:25:21 +00:00
public < M > void translateMetadata ( T entity , EntityMetadata < M , ? extends MetadataType < M > > metadata ) {
EntityMetadataTranslator < ? super T , M , EntityMetadata < M , ? extends MetadataType < M > > > translator = ( EntityMetadataTranslator < ? super T , M , EntityMetadata < M , ? extends MetadataType < M > > > ) this . translators . get ( metadata . getId ( ) ) ;
if ( translator = = null ) {
// This can safely happen; it means we don't translate this entity metadata
return ;
}
if ( translator . acceptedType ( ) ! = metadata . getType ( ) ) {
2021-11-20 21:34:30 +00:00
GeyserImpl . getInstance ( ) . getLogger ( ) . warning ( " Metadata ID " + metadata . getId ( ) + " was received with type " + metadata . getType ( ) + " but we expected " + translator . acceptedType ( ) + " for " + entity . getDefinition ( ) . entityType ( ) ) ;
if ( GeyserImpl . getInstance ( ) . getConfig ( ) . isDebugMode ( ) ) {
GeyserImpl . getInstance ( ) . getLogger ( ) . debug ( metadata . toString ( ) ) ;
2021-11-20 19:25:21 +00:00
}
return ;
}
2021-11-20 23:29:46 +00:00
translator . translate ( entity , metadata ) ;
2021-11-20 19:25:21 +00:00
}
2022-05-07 19:13:11 +00:00
public String identifier ( ) {
return this . entityIdentifier . identifier ( ) ;
}
public boolean isRegistered ( ) {
return Registries . ENTITY_DEFINITIONS . get ( ) . containsValue ( this ) ;
}
public EntityDefinitionBuilder < T > toBuilder ( ) {
return new EntityDefinitionBuilder < > ( this ) ;
}
2021-11-18 03:02:38 +00:00
@Setter
@Accessors ( fluent = true , chain = true )
2022-05-07 19:13:11 +00:00
public static class EntityDefinitionBuilder < T extends Entity > implements EntityDefinition . Builder {
2021-11-18 03:02:38 +00:00
private final EntityFactory < T > factory ;
private EntityType type ;
2022-05-07 19:13:11 +00:00
private EntityIdentifier identifier ;
2021-11-18 03:02:38 +00:00
private float width ;
private float height ;
2021-12-03 00:56:12 +00:00
private float offset = 0 . 00001f ;
2021-11-20 19:25:21 +00:00
private final List < EntityMetadataTranslator < ? super T , ? , ? > > translators ;
2022-05-07 19:13:11 +00:00
private final boolean custom ;
private EntityDefinitionBuilder ( GeyserEntityDefinition < T > definition ) {
this . factory = definition . factory ;
this . type = definition . entityType ;
this . identifier = definition . entityIdentifier ;
this . width = definition . width ;
this . height = definition . height ;
this . offset = definition . offset ;
this . translators = new ArrayList < > ( definition . translators ) ;
this . custom = definition . custom ;
}
2021-11-18 03:02:38 +00:00
2022-05-07 19:13:11 +00:00
private EntityDefinitionBuilder ( EntityFactory < T > factory ) {
this ( factory , false ) ;
}
public EntityDefinitionBuilder ( EntityFactory < T > factory , boolean custom ) {
2021-11-18 03:02:38 +00:00
this . factory = factory ;
2022-05-07 19:13:11 +00:00
this . translators = new ObjectArrayList < > ( ) ;
this . custom = custom ;
2021-11-18 03:02:38 +00:00
}
2022-05-07 19:13:11 +00:00
public EntityDefinitionBuilder ( EntityFactory < T > factory , EntityType type , EntityIdentifier identifier , float width , float height , float offset , List < EntityMetadataTranslator < ? super T , ? , ? > > translators ) {
2021-11-18 03:02:38 +00:00
this . factory = factory ;
this . type = type ;
this . identifier = identifier ;
this . width = width ;
this . height = height ;
this . offset = offset ;
this . translators = translators ;
2022-05-07 19:13:11 +00:00
this . custom = false ;
}
@Override
public EntityDefinitionBuilder < T > identifier ( EntityIdentifier identifier ) {
this . identifier = identifier ;
return this ;
}
public EntityDefinitionBuilder < T > identifier ( String identifier ) {
NbtMap nbt = Registries . BEDROCK_ENTITY_IDENTIFIERS . get ( ) ;
List < NbtMap > idlist = nbt . getList ( " idlist " , NbtType . COMPOUND ) ;
Optional < NbtMap > entityIdentifier = idlist . stream ( ) . filter ( tag - > tag . getString ( " id " ) . equals ( identifier ) ) . findFirst ( ) ;
// Create a fake entity identifier for entities which are
// in Java but may not be in Bedrock (e.g. item frames).
if ( entityIdentifier . isEmpty ( ) ) {
this . identifier = new GeyserEntityIdentifier ( NbtMap . builder ( )
. putString ( " id " , identifier )
. putBoolean ( " hasspawnegg " , false )
. putBoolean ( " summonable " , false )
. build ( ) ) ;
return this ;
}
this . identifier = new GeyserEntityIdentifier ( entityIdentifier . get ( ) ) ;
return this ;
2021-11-18 03:02:38 +00:00
}
/ * *
* Sets the height and width as one value
* /
2022-05-07 19:13:11 +00:00
public EntityDefinitionBuilder < T > heightAndWidth ( float value ) {
2021-11-18 03:02:38 +00:00
height = value ;
width = value ;
return this ;
}
2022-05-07 19:13:11 +00:00
public EntityDefinitionBuilder < T > offset ( float offset ) {
2021-12-03 00:56:12 +00:00
this . offset = offset + 0 . 00001f ;
return this ;
}
2021-11-18 03:02:38 +00:00
/ * *
* Resets the identifier as well
* /
2022-05-07 19:13:11 +00:00
public EntityDefinitionBuilder < T > type ( EntityType type ) {
2021-11-18 03:02:38 +00:00
this . type = type ;
identifier = null ;
return this ;
}
2022-05-07 19:13:11 +00:00
public < U , EM extends EntityMetadata < U , ? extends MetadataType < U > > > EntityDefinitionBuilder < T > addTranslator ( MetadataType < U > type , BiConsumer < T , EM > translateFunction ) {
2021-11-18 03:02:38 +00:00
translators . add ( new EntityMetadataTranslator < > ( type , translateFunction ) ) ;
return this ;
}
2022-05-07 19:13:11 +00:00
public EntityDefinitionBuilder < T > addTranslator ( EntityMetadataTranslator < T , ? , ? > translator ) {
2021-11-18 03:02:38 +00:00
translators . add ( translator ) ;
return this ;
}
2022-05-07 19:13:11 +00:00
public GeyserEntityDefinition < T > build ( ) {
return build ( false ) ;
2021-11-18 03:02:38 +00:00
}
/ * *
* @param register whether to register this entity in the Registries for entity types . Generally this should be
* set to false if we ' re not expecting this entity to spawn from the network .
* /
2022-05-07 19:13:11 +00:00
public GeyserEntityDefinition < T > build ( boolean register ) {
String identifier = null ;
if ( this . identifier = = null & & type ! = null ) {
2021-11-18 03:02:38 +00:00
identifier = " minecraft: " + type . name ( ) . toLowerCase ( Locale . ROOT ) ;
2022-05-07 19:13:11 +00:00
this . identifier ( identifier ) ;
} else if ( this . identifier ! = null & & type = = null ) {
identifier = this . identifier . identifier ( ) ;
2021-11-18 03:02:38 +00:00
}
2022-05-07 19:13:11 +00:00
GeyserEntityDefinition < T > definition = new GeyserEntityDefinition < > ( factory , type , this . identifier , width , height , offset , translators , custom ) ;
if ( register & & identifier ! = null ) {
EntityUtils . registerEntity ( identifier , definition ) ;
2021-11-18 03:02:38 +00:00
}
2022-05-07 19:13:11 +00:00
2021-11-18 03:02:38 +00:00
return definition ;
}
}
}