Skip to content

Developing with ServerMobs

techno-sam edited this page Aug 22, 2022 · 2 revisions

Preface

This repository contains several working example entities, but to see a simpler example check out techno-sam/AncientArmory

Step 1: build.gradle

ServerMobs

repositories { //Merge this with your repositiories block
    maven {
        name = "Modrinth"
        url = "https://api.modrinth.com/maven"
        content {
            includeGroup "maven.modrinth"
        }
    }
}

dependencies { //Merge this with your dependencies block
    modImplementation "maven.modrinth:server_mobs_api:1.0.3+1.19.2" //Replace with latest version
}

Polymer

You'll want to include Polymer too, see here to add it.

Step 2: fabric.mod.json

Add these lines to your depends block: (Replacing version numbers with latest version)

"polymer": "*",
"server_mobs_api": ">=1.0.3+1.19.2"

Step 3: Entity class

Must implement PolymerEntity and IServerRenderedEntity.

Example
package a.b.modid.entities;

import com.slimeist.server_mobs.api.server_rendering.entity.IServerRenderedEntity;
import com.slimeist.server_mobs.api.server_rendering.model.BakedServerEntityModel;
import eu.pb4.polymer.api.entity.PolymerEntity;
/*...*/

//This can extend any class extending Entity
public class ExampleEntity extends PersistentProjectileEntity implements PolymerEntity, IServerRenderedEntity {

    private static Supplier<BakedServerEntityModel> bakedModelSupplier;
    private BakedServerEntityModel.Instance modelInstance;

    /*...*/

    public ExampleEntity(EntityType<? extends PersistentProjectileEntity> entityType, World world) {
        super(entityType, world);
    }

    @Override
    public BakedServerEntityModel.Instance createModelInstance() {
        return getBakedModel().createInstance(this);
    }

    @Override
    public BakedServerEntityModel.Instance getModelInstance() {
        if (modelInstance == null) {
            modelInstance = createModelInstance();
        }
        return modelInstance;
    }

    @Override
    public BakedServerEntityModel getBakedModel() {
        return bakedModelSupplier.get();
    }

    //Initialization code for model: gets run every time entity is loaded
    @Override
    public void initAngles() {
        this.getModelInstance().setPartPivot("base", Vec3d.ZERO); //I didn't center my model in BlockBench, so correct for it here
    }

    //Run every time model updates, you can update more than just angles here. NOTE: Position automatically follows entity
    @Override
    public void updateAngles() {
        this.getModelInstance().setPartRotation("base", new EulerAngle(-this.getPitch(), -this.getYaw(), 0)); //rotate model to follow entity
    }

    public static void setBakedModelSupplier(Supplier<BakedServerEntityModel> bakedModel) {
        bakedModelSupplier = bakedModel;
    }

    //You will want to change this to something else if you want the client to be able to interact with it.
    //See the tools directory in this repository to find the ideal entity to use here
    @Override
    public EntityType<?> getPolymerEntityType() {
        return EntityType.MARKER;
    }

//Uncomment following method if you change EntityType.MARKER to something else
/*
    @Override
    public void modifyTrackedData(List<DataTracker.Entry<?>> data) {
        byte baseFlag = 0;
        baseFlag = modifyFlag(baseFlag, 5, true); //set invisible
        baseFlag = modifyFlag(baseFlag, 6, this.isGlowing()); //set glowing
        baseFlag = modifyFlag(baseFlag, ON_FIRE_FLAG_INDEX, this.doesRenderOnFire());
        data.add(new DataTracker.Entry<>(FLAGS, baseFlag));
        data.add(new DataTracker.Entry<>(EntityAccessor.getSILENT(), true));
    }
*/

    @Override
    public void tick() {
        super.tick();
        this.getModelInstance().updateHologram(); //this needs to be called at least once to initialize the model, and continuously if you want the model to animate
    }

    /*...*/
}

Step 4: Registering entities

In mod class:

public static final EntityType<ExampleEntity> EXAMPLE_ENTITY = Registry.register(
        Registry.ENTITY_TYPE,
        new Identifier("modid", "example_entity"),
        FabricEntityTypeBuilder.create(SpawnGroup.MISC, ExampleEntity::new)
            .dimensions(EntityDimensions.fixed(0.5f, 0.5f)) //Set some value here
            .build()
);

//Check ServerEntityModelLoader for constructors with more options
//Automatically loads model from mod resources, and disables damage tint for this model
private static final ServerEntityModelLoader EXAMPLE_ENTITY_LOADER = new ServerEntityModelLoader(EXAMPLE_ENTITY, false);
static {
    ExampleEntity.setBakedModelSupplier(EXAMPLE_ENTITY_LOADER::getBakedModel);
}

In onInitializeServer:

if (PolymerRPUtils.addAssetSource("modid")) {
    LOGGER.info("Successfully marked as asset source");
} else {
    LOGGER.error("Failed to mark as asset source");
}
PolymerRPUtils.markAsRequired(); //Without the resourcepack, clients will just see a bunch of carved pumpkins floating around

PolymerEntityUtils.registerType(EXAMPLE_ENTITY);

Step 5: Creating a model

Resource Structure

Resources for a specific entity go in this folder: resources/assets/<modid>/server_entities/<example_entity>

The folder should contain an <example_entity>.bbmodel and an <example_entity>.png. You should add <example_entity>_tint.png unless you disable damage tint on your entity.

Model Restrictions

  • Create it with Blockbench.
  • Mesh is not supported.
  • It must have only one texture
  • Each group is a separate item model
  • It must be item-model compatible, that is:
    • Each group has a maximum size of a few blocks by a few blocks. (I can't remember the exact values)
    • Each box can only be rotated in one axis by either:
      • ± 22.5°
      • ± 45°
  • If you create a box in a root group called hitbox, ServerMobs API will log it's mc-scale size in the console
  • The whole display model should be inside a root group called base
Example Group Setup

For the crocodile:

Group Overview