Jump to content

Recommended Posts

Posted

How to add a new renderLayer to the player?

In the original player class we have its constructor:

Spoiler
@OnlyIn(Dist.CLIENT)
public class PlayerRenderer extends LivingEntityRenderer<AbstractClientPlayer, PlayerModel<AbstractClientPlayer>> {

   public PlayerRenderer(EntityRendererProvider.Context p_174557_, boolean p_174558_) {
      super(p_174557_, new PlayerModel<>(p_174557_.bakeLayer(p_174558_ ? ModelLayers.PLAYER_SLIM : ModelLayers.PLAYER), p_174558_), 0.5F);
      this.addLayer(new HumanoidArmorLayer<>(this, new HumanoidModel(p_174557_.bakeLayer(p_174558_ ? ModelLayers.PLAYER_SLIM_INNER_ARMOR : 	ModelLayers.PLAYER_INNER_ARMOR)), new HumanoidModel(p_174557_.bakeLayer(p_174558_ ? ModelLayers.PLAYER_SLIM_OUTER_ARMOR : 	ModelLayers.PLAYER_OUTER_ARMOR))));
      this.addLayer(new PlayerItemInHandLayer<>(this, p_174557_.getItemInHandRenderer()));
      this.addLayer(new ArrowLayer<>(p_174557_, this));
      this.addLayer(new Deadmau5EarsLayer(this));
      this.addLayer(new CapeLayer(this));
      this.addLayer(new CustomHeadLayer<>(this, p_174557_.getModelSet(), p_174557_.getItemInHandRenderer()));
      this.addLayer(new ElytraLayer<>(this, p_174557_.getModelSet()));
      this.addLayer(new ParrotOnShoulderLayer<>(this, p_174557_.getModelSet()));
      this.addLayer(new SpinAttackEffectLayer<>(this, p_174557_.getModelSet()));
      this.addLayer(new BeeStingerLayer<>(this));
   }
	// ..... MORE CODE
}

 

I would like to add an additional Layer through events.
I searched a lot and found the way below, using
EntityRenderersEvent.AddLayers.

Spoiler
@Mod.EventBusSubscriber(modid = ModCraft.MOD_ID, value = Dist.CLIENT)
public static class ClientForgeEvents {
	@SubscribeEvent
        public static void registerArmorRenderers(EntityRenderersEvent.AddLayers event) {
            boolean bool=true;
            //LivingEntityRenderer render = event.getRenderer(EntityType.PLAYER);
            LivingEntityRenderer<Player, PlayerModel<Player>> renderer = event.getRenderer(EntityType.PLAYER);
            ExampleTypeAcessoryLayer layer = new ExampleTypeAcessoryLayer(renderer, new HumanoidModel(event.getEntityModels().bakeLayer(bool ? ModelLayers.PLAYER_SLIM_INNER_ARMOR : ModelLayers.PLAYER_INNER_ARMOR)), new HumanoidModel(event.getEntityModels().bakeLayer(bool ? ModelLayers.PLAYER_SLIM_OUTER_ARMOR : ModelLayers.PLAYER_OUTER_ARMOR)));
            renderer.addLayer(layer);
        }
}

 

However, the code states that o renderer = null.
How to add this RenderLayer to entities that already exist in vanilla?

Posted

Thanks. The renderer isn't more null. But the layer not render nothing.

Let's go back a few houses!!!

To check if the exampleentityLayer is working(Is working).
-> I built a new entity (extends Skeleton)
-> I added this render (my renderLayer) to my new created entity. It works! see

My entity renderer (created by me) and the added renderlayer:

Spoiler
public class ExampleTypeRender extends HumanoidMobRenderer<AbstractSkeleton, HumanoidModel<AbstractSkeleton>> {
    private static final ResourceLocation SKELETON_LOCATION = new ResourceLocation(ModCraft.MOD_ID, "textures/entity/example_entity/skeleton.png");

    public ExampleTypeRender(EntityRendererProvider.Context context) {
        this(context, ModelLayers.SKELETON, ModelLayers.SKELETON_INNER_ARMOR, ModelLayers.SKELETON_OUTER_ARMOR);
    }

    public ExampleTypeRender(EntityRendererProvider.Context context, ModelLayerLocation modelLayerLocation, ModelLayerLocation layerLocation, ModelLayerLocation location) {
        super(context, new SkeletonModel<>(context.bakeLayer(modelLayerLocation)), 0.3F);
		// Here I Add my Custom RenderLayer
        this.addLayer(new ExampleEntityLayer<>(this, new ExampleTypeModel(context.bakeLayer(layerLocation)), new ExampleTypeModel(context.bakeLayer(location))));
    }

    public ResourceLocation getTextureLocation(AbstractSkeleton skeleton) {
        return SKELETON_LOCATION;
    }

    protected boolean isShaking(AbstractSkeleton p_174389_) {
        return p_174389_.isShaking();
    }
}

 

Look at the image that works:

Spoiler

spacer.png

Now let's put my RenderLayer in a Vanila entity (a Skeleton). Not yet in the Player (we will do this later, if possible).
So all Skeletons must render this armor. But this does not happen: See the image below.

Adding the RenderLayer in Skeleton Vanilla via Register EntityRenderersEvent.AddLayers:

Spoiler
public class ClientEvents {
    @Mod.EventBusSubscriber(modid = ModCraft.MOD_ID, value = Dist.CLIENT)
    public static class ClientForgeEvents {
	@SubscribeEvent
        public static void registerArmorRenderers(final EntityRenderersEvent.AddLayers event) {
            boolean bool=true;
            LivingEntityRenderer render = event.getRenderer(EntityType.SKELETON);
            render.addLayer(new ExampleEntityLayer(render,new HumanoidModel(event.getEntityModels().bakeLayer(ModelLayers.PLAYER_INNER_ARMOR)),new HumanoidModel(event.getEntityModels().bakeLayer(ModelLayers.PLAYER_OUTER_ARMOR))));
        }

}

 

The Vanilla Skeleton Image:

Spoiler

spacer.png

Posted

Right. 

That is complete custom Skeleton:

Spoiler
public class ExampleTypeEntity extends AbstractSkeleton {
    private static final EntityDataAccessor<Boolean> DATA_STRAY_CONVERSION_ID = SynchedEntityData.defineId(Skeleton.class, EntityDataSerializers.BOOLEAN);
    public static final String CONVERSION_TAG = "StrayConversionTime";
    private int inPowderSnowTime;
    private int conversionTime;

    @Nullable
    @Override
    public SpawnGroupData finalizeSpawn(ServerLevelAccessor p_levelAccessor2146_, DifficultyInstance instance, MobSpawnType spawnType, @Nullable SpawnGroupData groupData, @Nullable CompoundTag tag) {
        return super.finalizeSpawn(p_levelAccessor2146_, instance, spawnType, groupData, tag);
    }

    public ExampleTypeEntity(EntityType<? extends ExampleTypeEntity> entityType, Level level) {
        super(entityType, level);
    }

    protected void defineSynchedData() {
        super.defineSynchedData();
        this.getEntityData().define(DATA_STRAY_CONVERSION_ID, false);
    }

    public boolean isFreezeConverting() {
        return this.getEntityData().get(DATA_STRAY_CONVERSION_ID);
    }

    public void setFreezeConverting(boolean p_149843_) {
        this.entityData.set(DATA_STRAY_CONVERSION_ID, p_149843_);
    }

    public boolean isShaking() {
        return this.isFreezeConverting();
    }

    public void tick() {
        if (!this.level.isClientSide && this.isAlive() && !this.isNoAi()) {
            if (this.isFreezeConverting()) {
                --this.conversionTime;
                if (this.conversionTime < 0) {
                    this.doFreezeConversion();
                }
            } else if (this.isInPowderSnow) {
                ++this.inPowderSnowTime;
                if (this.inPowderSnowTime >= 140) {
                    this.startFreezeConversion(300);
                }
            } else {
                this.inPowderSnowTime = -1;
            }
        }

        super.tick();
    }

    public void addAdditionalSaveData(CompoundTag p_149836_) {
        super.addAdditionalSaveData(p_149836_);
        p_149836_.putInt("StrayConversionTime", this.isFreezeConverting() ? this.conversionTime : -1);
    }

    public void readAdditionalSaveData(CompoundTag p_149833_) {
        super.readAdditionalSaveData(p_149833_);
        if (p_149833_.contains("StrayConversionTime", 99) && p_149833_.getInt("StrayConversionTime") > -1) {
            this.startFreezeConversion(p_149833_.getInt("StrayConversionTime"));
        }

    }

    private void startFreezeConversion(int p_149831_) {
        this.conversionTime = p_149831_;
        this.entityData.set(DATA_STRAY_CONVERSION_ID, true);
    }

    protected void doFreezeConversion() {
        this.convertTo(EntityType.STRAY, true);
        if (!this.isSilent()) {
            this.level.levelEvent((Player)null, 1048, this.blockPosition(), 0);
        }

    }

    public boolean canFreeze() {
        return false;
    }

    protected SoundEvent getAmbientSound() {
        return SoundEvents.SKELETON_AMBIENT;
    }

    protected SoundEvent getHurtSound(DamageSource p_33579_) {
        return SoundEvents.SKELETON_HURT;
    }

    protected SoundEvent getDeathSound() {
        return SoundEvents.SKELETON_DEATH;
    }

    protected SoundEvent getStepSound() {
        return SoundEvents.SKELETON_STEP;
    }

    protected void dropCustomDeathLoot(DamageSource p_33574_, int p_33575_, boolean p_33576_) {
        super.dropCustomDeathLoot(p_33574_, p_33575_, p_33576_);
        Entity entity = p_33574_.getEntity();
        if (entity instanceof Creeper creeper) {
            if (creeper.canDropMobsSkull()) {
                creeper.increaseDroppedSkulls();
                this.spawnAtLocation(Items.SKELETON_SKULL);
            }
        }

    }
}

 

And this is the Complete Custom ExampleEntityLayer (the custom renderLayer to Custom Skeletom)

(It's basically an adapted HumanoidArmorLayer class)

Spoiler

@OnlyIn(Dist.CLIENT)
public class ExampleEntityLayer <T extends LivingEntity, M extends HumanoidModel<T>, A extends HumanoidModel<T>> extends RenderLayer<T, M> {
    private static final Map<String, ResourceLocation> ARMOR_LOCATION_CACHE = Maps.newHashMap();
    private final A innerModel;
    private final A outerModel;

    public ExampleEntityLayer(RenderLayerParent<T, M> p_117075_, A p_117076_, A p_117077_) {
        super(p_117075_);
        this.innerModel = p_117076_;
        this.outerModel = p_117077_;
    }

    public void render(PoseStack p_117096_, MultiBufferSource p_117097_, int p_117098_, T p_117099_, float p_117100_, float p_117101_, float p_117102_, float p_117103_, float p_117104_, float p_117105_) {
        this.renderArmorPiece(p_117096_, p_117097_, p_117099_, EquipmentSlot.CHEST, p_117098_, this.getArmorModel(EquipmentSlot.CHEST));
        this.renderArmorPiece(p_117096_, p_117097_, p_117099_, EquipmentSlot.LEGS, p_117098_, this.getArmorModel(EquipmentSlot.LEGS));
        this.renderArmorPiece(p_117096_, p_117097_, p_117099_, EquipmentSlot.FEET, p_117098_, this.getArmorModel(EquipmentSlot.FEET));
        this.renderArmorPiece(p_117096_, p_117097_, p_117099_, EquipmentSlot.HEAD, p_117098_, this.getArmorModel(EquipmentSlot.HEAD));
    }

    private void renderArmorPiece(PoseStack poseStack, MultiBufferSource bufferSource, T livingEntity, EquipmentSlot equipmentSlot, int i1, A armorModel) {
        ItemStack itemstack = livingEntity.getItemBySlot(equipmentSlot);
        equipmentSlot = EquipmentSlot.HEAD;
        itemstack = new ItemStack(ModItem.STEEL_ARMOR_STANDART_HELMET.get());
        if (itemstack.getItem() instanceof ArmorItem) {
            ArmorItem armoritem = (ArmorItem)itemstack.getItem();
            if (armoritem.getSlot() == equipmentSlot) {
                //this.getParentModel().copyPropertiesTo(p_117124_);
                //ModelPartUtils.copyOriginalPropertiesTo(this.getParentModel(), armorModel,0.1F);// trabalho dobrado a frente
                //this.setPartVisibility(armorModel, equipmentSlot);
                net.minecraft.client.model.Model model = getArmorModelHook(livingEntity, itemstack, equipmentSlot, armorModel);
                boolean flag = this.usesInnerModel(equipmentSlot);
                boolean flag1 = itemstack.hasFoil();
                if (armoritem instanceof net.minecraft.world.item.DyeableLeatherItem) {
                    int i = ((net.minecraft.world.item.DyeableLeatherItem)armoritem).getColor(itemstack);
                    float f = (float)(i >> 16 & 255) / 255.0F;
                    float f1 = (float)(i >> 8 & 255) / 255.0F;
                    float f2 = (float)(i & 255) / 255.0F;
                    this.renderModel(poseStack, bufferSource, i1, flag1, model, f, f1, f2, this.getArmorResource(livingEntity, itemstack, equipmentSlot, null));
                    this.renderModel(poseStack, bufferSource, i1, flag1, model, 1.0F, 1.0F, 1.0F, this.getArmorResource(livingEntity, itemstack, equipmentSlot, "overlay"));
                } else {
                    this.renderModel(poseStack, bufferSource, i1, flag1, model, 1.0F, 1.0F, 1.0F, this.getArmorResource(livingEntity, itemstack, equipmentSlot, null));
                }

            }
        }
    }

    protected void setPartVisibility(A p_117126_, EquipmentSlot p_117127_) {
        p_117126_.setAllVisible(false);
        switch (p_117127_) {
            case HEAD:
                p_117126_.head.visible = true;
                p_117126_.hat.visible = true;
                break;
            case CHEST:
                p_117126_.body.visible = true;
                p_117126_.rightArm.visible = true;
                p_117126_.leftArm.visible = true;
                break;
            case LEGS:
                p_117126_.body.visible = true;
                p_117126_.rightLeg.visible = true;
                p_117126_.leftLeg.visible = true;
                break;
            case FEET:
                p_117126_.rightLeg.visible = true;
                p_117126_.leftLeg.visible = true;
        }

    }

    private void renderModel(PoseStack p_117107_, MultiBufferSource p_117108_, int p_117109_, ArmorItem p_117110_, boolean p_117111_, A p_117112_, boolean p_117113_, float p_117114_, float p_117115_, float p_117116_, @Nullable String p_117117_) {
        renderModel(p_117107_, p_117108_, p_117109_, p_117111_, p_117112_, p_117114_, p_117115_, p_117116_, this.getArmorLocation(p_117110_, p_117113_, p_117117_));
    }
    private void renderModel(PoseStack p_117107_, MultiBufferSource p_117108_, int p_117109_, boolean p_117111_, net.minecraft.client.model.Model p_117112_, float p_117114_, float p_117115_, float p_117116_, ResourceLocation armorResource) {
        VertexConsumer vertexconsumer = ItemRenderer.getArmorFoilBuffer(p_117108_, RenderType.armorCutoutNoCull(armorResource), false, p_117111_);
        p_117112_.renderToBuffer(p_117107_, vertexconsumer, p_117109_, OverlayTexture.NO_OVERLAY, p_117114_, p_117115_, p_117116_, 1.0F);
    }

    private A getArmorModel(EquipmentSlot p_117079_) {
        return (A)(this.usesInnerModel(p_117079_) ? this.innerModel : this.outerModel);
    }

    private boolean usesInnerModel(EquipmentSlot p_117129_) {
        return p_117129_ == EquipmentSlot.LEGS;
    }

    @Deprecated //Use the more sensitive version getArmorResource below
    private ResourceLocation getArmorLocation(ArmorItem p_117081_, boolean p_117082_, @Nullable String p_117083_) {
        String s = "textures/models/armor/" + p_117081_.getMaterial().getName() + "_layer_" + (p_117082_ ? 2 : 1) + (p_117083_ == null ? "" : "_" + p_117083_) + ".png";
        return ARMOR_LOCATION_CACHE.computeIfAbsent(s, ResourceLocation::new);
    }

    /*=================================== FORGE START =========================================*/

    /**
     * Hook to allow item-sensitive armor model. for HumanoidArmorLayer.
     */
    protected net.minecraft.client.model.Model getArmorModelHook(T entity, ItemStack itemStack, EquipmentSlot slot, A model) {
        return net.minecraftforge.client.ForgeHooksClient.getArmorModel(entity, itemStack, slot, model);
    }

    /**
     * More generic ForgeHook version of the above function, it allows for Items to have more control over what texture they provide.
     *
     * @param entity Entity wearing the armor
     * @param stack ItemStack for the armor
     * @param slot Slot ID that the item is in
     * @param type Subtype, can be null or "overlay"
     * @return ResourceLocation pointing at the armor's texture
     */
    public ResourceLocation getArmorResource(net.minecraft.world.entity.Entity entity, ItemStack stack, EquipmentSlot slot, @Nullable String type) {
        ArmorItem item = (ArmorItem)stack.getItem();
        String texture = item.getMaterial().getName();
        String domain = "minecraft";
        int idx = texture.indexOf(':');
        if (idx != -1) {
            domain = texture.substring(0, idx);
            texture = texture.substring(idx + 1);
        }
        String s1 = String.format(java.util.Locale.ROOT, "%s:textures/models/armor/%s_layer_%d%s.png", domain, texture, (usesInnerModel(slot) ? 2 : 1), type == null ? "" : String.format(java.util.Locale.ROOT, "_%s", type));

        s1 = net.minecraftforge.client.ForgeHooksClient.getArmorTexture(entity, stack, s1, slot, type);
        ResourceLocation resourcelocation = ARMOR_LOCATION_CACHE.get(s1);

        if (resourcelocation == null) {
            resourcelocation = new ResourceLocation(s1);
            ARMOR_LOCATION_CACHE.put(s1, resourcelocation);
        }

        return resourcelocation;
    }
    /*=================================== FORGE END ===========================================*/
}

 

 

Posted

Is Here:

Spoiler
public class ExampleTypeRender extends HumanoidMobRenderer<AbstractSkeleton, HumanoidModel<AbstractSkeleton>> {
    private static final ResourceLocation SKELETON_LOCATION = new ResourceLocation(ModCraft.MOD_ID, "textures/entity/example_entity/skeleton.png");

    public ExampleTypeRender(EntityRendererProvider.Context context) {
        this(context, ModelLayers.SKELETON, ModelLayers.SKELETON_INNER_ARMOR, ModelLayers.SKELETON_OUTER_ARMOR);
    }

    public ExampleTypeRender(EntityRendererProvider.Context context, ModelLayerLocation modelLayerLocation, ModelLayerLocation layerLocation, ModelLayerLocation location) {
        super(context, new SkeletonModel<>(context.bakeLayer(modelLayerLocation)), 0.3F);
        this.addLayer(new ExampleEntityLayer<>(this, new ExampleTypeModel(context.bakeLayer(layerLocation)), new ExampleTypeModel(context.bakeLayer(location))));
    }

    public ResourceLocation getTextureLocation(AbstractSkeleton skeleton) {
        return SKELETON_LOCATION;
    }

    protected boolean isShaking(AbstractSkeleton p_174389_) {
        return p_174389_.isShaking();
    }
}

 

 

Posted

I discovered the error: My Event Bus was in the wrong place.

Correct Place:

Spoiler
@Mod.EventBusSubscriber(modid = ModCraft.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD)
public class ModEventBusEvents {

    @SubscribeEvent
    public static void registerArmorLayers(EntityRenderersEvent.AddLayers event){
        LivingEntityRenderer render = event.getRenderer(EntityType.SKELETON);
        EntityModelSet models = Minecraft.getInstance().getEntityModels();
        ModelPart rootInner = models.bakeLayer(ModelLayers.SKELETON_INNER_ARMOR);
        ModelPart rootOuter = models.bakeLayer(ModelLayers.SKELETON_OUTER_ARMOR);
        RenderLayer<LivingEntity, EntityModel<LivingEntity>> renderlayer1 = new ExampleEntityLayer(render, new HumanoidModel(rootInner), new HumanoidModel(rootOuter));
        render.addLayer(renderlayer1);

       

    }


}

 

 

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • that happens every time I enter a new dimension.
    • This is the last line before the crash: [ebwizardry]: Synchronising spell emitters for PixelTraveler But I have no idea what this means
    • What in particular? I barely used that mod this time around, and it's never been a problem in the past.
    • Im trying to build my mod using shade since i use the luaj library however i keep getting this error Reason: Task ':reobfJar' uses this output of task ':shadowJar' without declaring an explicit or implicit dependency. This can lead to incorrect results being produced, depending on what order the tasks are executed. So i try adding reobfJar.dependsOn shadowJar  Could not get unknown property 'reobfJar' for object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler. my gradle file plugins { id 'eclipse' id 'idea' id 'maven-publish' id 'net.minecraftforge.gradle' version '[6.0,6.2)' id 'com.github.johnrengelman.shadow' version '7.1.2' id 'org.spongepowered.mixin' version '0.7.+' } apply plugin: 'net.minecraftforge.gradle' apply plugin: 'org.spongepowered.mixin' apply plugin: 'com.github.johnrengelman.shadow' version = mod_version group = mod_group_id base { archivesName = mod_id } // Mojang ships Java 17 to end users in 1.18+, so your mod should target Java 17. java.toolchain.languageVersion = JavaLanguageVersion.of(17) //jarJar.enable() println "Java: ${System.getProperty 'java.version'}, JVM: ${System.getProperty 'java.vm.version'} (${System.getProperty 'java.vendor'}), Arch: ${System.getProperty 'os.arch'}" minecraft { mappings channel: mapping_channel, version: mapping_version copyIdeResources = true runs { configureEach { workingDirectory project.file('run') property 'forge.logging.markers', 'REGISTRIES' property 'forge.logging.console.level', 'debug' arg "-mixin.config=derp.mixin.json" mods { "${mod_id}" { source sourceSets.main } } } client { // Comma-separated list of namespaces to load gametests from. Empty = all namespaces. property 'forge.enabledGameTestNamespaces', mod_id } server { property 'forge.enabledGameTestNamespaces', mod_id args '--nogui' } gameTestServer { property 'forge.enabledGameTestNamespaces', mod_id } data { workingDirectory project.file('run-data') args '--mod', mod_id, '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/') } } } sourceSets.main.resources { srcDir 'src/generated/resources' } repositories { flatDir { dirs './libs' } maven { url = "https://jitpack.io" } } configurations { shade implementation.extendsFrom shade } dependencies { minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}" implementation 'org.luaj:luaj-jse-3.0.2' implementation fg.deobf("com.github.Virtuoel:Pehkui:${pehkui_version}") annotationProcessor 'org.spongepowered:mixin:0.8.5:processor' minecraftLibrary 'luaj:luaj-jse:3.0.2' shade 'luaj:luaj-jse:3.0.2' } // Example for how to get properties into the manifest for reading at runtime. tasks.named('jar', Jar).configure { manifest { attributes([ 'Specification-Title' : mod_id, 'Specification-Vendor' : mod_authors, 'Specification-Version' : '1', // We are version 1 of ourselves 'Implementation-Title' : project.name, 'Implementation-Version' : project.jar.archiveVersion, 'Implementation-Vendor' : mod_authors, 'Implementation-Timestamp': new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"), "TweakClass" : "org.spongepowered.asm.launch.MixinTweaker", "TweakOrder" : 0, "MixinConfigs" : "derp.mixin.json" ]) } rename 'mixin.refmap.json', 'derp.mixin-refmap.json' } shadowJar { archiveClassifier = '' configurations = [project.configurations.shade] finalizedBy 'reobfShadowJar' } assemble.dependsOn shadowJar reobf { re shadowJar {} } publishing { publications { mavenJava(MavenPublication) { artifact jar } } repositories { maven { url "file://${project.projectDir}/mcmodsrepo" } } } my entire project:https://github.com/kevin051606/DERP-Mod/tree/Derp-1.0-1.20
  • Topics

  • Who's Online (See full list)

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.