Added a base renderer class and added another example entity to test with

This commit is contained in:
Halbear
2026-05-19 23:04:16 +01:00
parent 826bf04ffd
commit f7ec9b9b42
12 changed files with 3350 additions and 133 deletions
@@ -1,84 +0,0 @@
package net.halbear.hvf.Entity.Example.Renderer;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.vertex.IVertexBuilder;
import net.halbear.hvf.Entity.Example.Renderer.Models.AeroplaneModel;
import net.halbear.hvf.Entity.VehicleBaseEntity;
import net.halbear.hvf.Halsvehicleframework;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.entity.EntityRenderer;
import net.minecraft.client.renderer.entity.EntityRendererManager;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.vector.Vector3f;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import javax.annotation.Nonnull;
@OnlyIn(Dist.CLIENT)
public class AeroplaneRenderer extends EntityRenderer<VehicleBaseEntity> {
private AeroplaneModel model = new AeroplaneModel();
public AeroplaneRenderer(EntityRendererManager renderManagerIn) {
super(renderManagerIn );
}
@Override
public void render(VehicleBaseEntity entity, float entityYaw, float partialTicks, MatrixStack matrixStack, IRenderTypeBuffer buffer, int packedLight) {
matrixStack.push();
matrixStack.rotate(Vector3f.YP.rotationDegrees(180.0F - entityYaw));
matrixStack.scale(-1.0F, -1.0F, 1.0F);
matrixStack.translate(0.0D, -1.5D, 0.0D);
IVertexBuilder vertexBuilder = buffer.getBuffer(this.model.getRenderType(getEntityTexture(entity)));
this.model.setRotationAngles(entity, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F);
this.model.render(matrixStack, vertexBuilder, packedLight, OverlayTexture.NO_OVERLAY, 1.0F, 1.0F, 1.0F, 1.0F);
matrixStack.pop();
super.render(entity, entityYaw, partialTicks, matrixStack, buffer, packedLight);
}
@Override
@Nonnull
public ResourceLocation getEntityTexture(VehicleBaseEntity entity) {
return new ResourceLocation(Halsvehicleframework.MOD_ID,"textures/entities/biplaneupdated.png");
}
/* @Override
public boolean shouldRender(Aeroplane livingEntity, ClippingHelper camera, double camX, double camY, double camZ) {
return true;
}*/
//i can use this to render mutliple models on one entity
/*private List<EntityModel<Aeroplane>> modelParts = new ArrayList<>();
public AeroplaneRenderer(EntityRendererManager renderManagerIn) {
super(renderManagerIn );
}
@Override
public void render(Aeroplane entity, float entityYaw, float partialTicks, MatrixStack matrixStack, IRenderTypeBuffer buffer, int packedLight) {
modelParts.add(new AeroplaneModel());
modelParts.add(new AeroplaneModel());
modelParts.add(new AeroplaneModel());
modelParts.add(new AeroplaneModel());
matrixStack.push();
matrixStack.rotate(Vector3f.YP.rotationDegrees(180.0F - entityYaw));
matrixStack.scale(-1.0F, -1.0F, 1.0F);
matrixStack.translate(0.0D, -1.5D, 0.0D);
for(int i = 0; i < modelParts.toArray().length; i++) {
IVertexBuilder vertexBuilder = buffer.getBuffer(this.modelParts.get(i).getRenderType(getEntityTexture(entity)));
this.modelParts.get(i).setRotationAngles(entity, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F);
this.modelParts.get(i).render(matrixStack, vertexBuilder, packedLight, OverlayTexture.NO_OVERLAY, 1.0F, 1.0F, 1.0F, 1.0F);
}
matrixStack.pop();
super.render(entity, entityYaw, partialTicks, matrixStack, buffer, packedLight);
}*/
}
@@ -0,0 +1,54 @@
package net.halbear.hvf.Entity.Renderer;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.vertex.IVertexBuilder;
import net.halbear.hvf.Entity.VehicleBaseEntity;
import net.halbear.hvf.Halsvehicleframework;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.entity.EntityRenderer;
import net.minecraft.client.renderer.entity.EntityRendererManager;
import net.minecraft.client.renderer.entity.model.EntityModel;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.vector.Vector3f;
import javax.annotation.Nonnull;
import java.util.Arrays;
public class VehicleBaseRenderer<T extends VehicleBaseEntity, M extends EntityModel<VehicleBaseEntity>> extends EntityRenderer<T> {
private M[] models;
private final String TextureLocation;
protected VehicleBaseRenderer(EntityRendererManager renderManager, M[] models, String TextureLocation) {
super(renderManager);
this.TextureLocation = TextureLocation;
this.models = models;
}
@Override
public void render(T entity, float entityYaw, float partialTicks, MatrixStack matrixStack, IRenderTypeBuffer buffer, int packedLight) {
matrixStack.push();
matrixStack.translate( entity.GetPilotSeat().x, -entity.GetPilotSeat().y, entity.GetPilotSeat().z);
matrixStack.rotate(Vector3f.YP.rotationDegrees(180.0F - entity.GetVehicleYaw()));
matrixStack.rotate(Vector3f.XP.rotationDegrees(entity.GetVehiclePitch()));
matrixStack.rotate(Vector3f.ZP.rotationDegrees(entity.GetVehicleRoll()));
matrixStack.translate( -entity.GetPilotSeat().x, entity.GetPilotSeat().y, -entity.GetPilotSeat().z);
matrixStack.scale(-1.0F, -1.0F, 1.0F);
matrixStack.translate(0.0D, -1.5D, 0.0D);
Arrays.asList(models).forEach(model->{
IVertexBuilder vertexBuilder = buffer.getBuffer(model.getRenderType(getEntityTexture(entity)));
model.setRotationAngles(entity, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F);
model.render(matrixStack, vertexBuilder, packedLight, OverlayTexture.NO_OVERLAY, 1.0F, 1.0F, 1.0F, 1.0F);
});
matrixStack.pop();
super.render(entity, entityYaw, partialTicks, matrixStack, buffer, packedLight);
}
@Override
@Nonnull
public ResourceLocation getEntityTexture(T entity) {
return new ResourceLocation(Halsvehicleframework.MOD_ID,TextureLocation);
}
}
@@ -28,15 +28,23 @@ public class VehicleBaseEntity extends Entity {
private Map<String, Float> BASE_FLOAT_PARAMETERS = new HashMap<>(); private Map<String, Float> BASE_FLOAT_PARAMETERS = new HashMap<>();
private Map<String, Integer> BASE_INT_PARAMETERS = new HashMap<>(); private Map<String, Integer> BASE_INT_PARAMETERS = new HashMap<>();
private Map<String, Boolean> BASE_BOOLEAN_PARAMETERS = new HashMap<>(); private Map<String, Boolean> BASE_BOOLEAN_PARAMETERS = new HashMap<>();
private VehicleClassification vehicleClassification; private final VehicleClassification vehicleClassification;
private Vector3d[] VehicleSeatOffsets; private final Vector3d[] VehicleSeatOffsets;
private EngineCategories EngineType; private EngineCategories EngineType;
public Vector3d GetPilotSeat(){return VehicleSeatOffsets.length > 0 ? VehicleSeatOffsets[0] : new Vector3d(0,0,0);}
public VehicleBaseEntity(EntityType<?> entityTypeIn, World worldIn, Vector3d[] VehicleSeatOffsets, VehicleBuildInfo vehicleBuildInfo) { public VehicleBaseEntity(EntityType<?> entityTypeIn, World worldIn, Vector3d[] VehicleSeatOffsets, VehicleBuildInfo vehicleBuildInfo) {
super(entityTypeIn, worldIn); super(entityTypeIn, worldIn);
this.VehicleSeatOffsets = VehicleSeatOffsets; this.VehicleSeatOffsets = VehicleSeatOffsets;
vehicleClassification = vehicleBuildInfo.GetVehicleClassification(); vehicleClassification = vehicleBuildInfo.GetVehicleClassification();
EngineType = vehicleBuildInfo.GetEngineType(); EngineType = vehicleBuildInfo.GetEngineType();
VEHICLE_SYNCHED_FLOAT_PARAMETERS.put("ORIENTATION_ROLL", EntityDataManager.createKey(VehicleBaseEntity.class, DataSerializers.FLOAT));
BASE_FLOAT_PARAMETERS.put("ORIENTATION_ROLL",0f);
VEHICLE_SYNCHED_FLOAT_PARAMETERS.put("ORIENTATION_YAW", EntityDataManager.createKey(VehicleBaseEntity.class, DataSerializers.FLOAT));
BASE_FLOAT_PARAMETERS.put("ORIENTATION_YAW",0f);
VEHICLE_SYNCHED_FLOAT_PARAMETERS.put("ORIENTATION_PITCH", EntityDataManager.createKey(VehicleBaseEntity.class, DataSerializers.FLOAT));
BASE_FLOAT_PARAMETERS.put("ORIENTATION_PITCH",0f);
switch (vehicleClassification){ switch (vehicleClassification){
case Aeroplane: case Aeroplane:
VEHICLE_SYNCHED_INT_PARAMETERS.put("ENGINE_COUNT", EntityDataManager.createKey(VehicleBaseEntity.class, DataSerializers.VARINT)); VEHICLE_SYNCHED_INT_PARAMETERS.put("ENGINE_COUNT", EntityDataManager.createKey(VehicleBaseEntity.class, DataSerializers.VARINT));
@@ -45,12 +53,6 @@ public class VehicleBaseEntity extends Entity {
BASE_FLOAT_PARAMETERS.put("MAX_ENGINE_RPM",(float)vehicleBuildInfo.GetMaxEngineRPM()); BASE_FLOAT_PARAMETERS.put("MAX_ENGINE_RPM",(float)vehicleBuildInfo.GetMaxEngineRPM());
VEHICLE_SYNCHED_FLOAT_PARAMETERS.put("WING_SPAN", EntityDataManager.createKey(VehicleBaseEntity.class, DataSerializers.FLOAT)); VEHICLE_SYNCHED_FLOAT_PARAMETERS.put("WING_SPAN", EntityDataManager.createKey(VehicleBaseEntity.class, DataSerializers.FLOAT));
BASE_FLOAT_PARAMETERS.put("WING_SPAN",(float)vehicleBuildInfo.GetWingSpan()); BASE_FLOAT_PARAMETERS.put("WING_SPAN",(float)vehicleBuildInfo.GetWingSpan());
VEHICLE_SYNCHED_FLOAT_PARAMETERS.put("ORIENTATION_ROLL", EntityDataManager.createKey(VehicleBaseEntity.class, DataSerializers.FLOAT));
BASE_FLOAT_PARAMETERS.put("ORIENTATION_ROLL",0f);
VEHICLE_SYNCHED_FLOAT_PARAMETERS.put("ORIENTATION_YAW", EntityDataManager.createKey(VehicleBaseEntity.class, DataSerializers.FLOAT));
BASE_FLOAT_PARAMETERS.put("ORIENTATION_YAW",0f);
VEHICLE_SYNCHED_FLOAT_PARAMETERS.put("ORIENTATION_PITCH", EntityDataManager.createKey(VehicleBaseEntity.class, DataSerializers.FLOAT));
BASE_FLOAT_PARAMETERS.put("ORIENTATION_PITCH",0f);
break; break;
case Zepplin: case Zepplin:
VEHICLE_SYNCHED_INT_PARAMETERS.put("ENGINE_COUNT", EntityDataManager.createKey(VehicleBaseEntity.class, DataSerializers.VARINT)); VEHICLE_SYNCHED_INT_PARAMETERS.put("ENGINE_COUNT", EntityDataManager.createKey(VehicleBaseEntity.class, DataSerializers.VARINT));
@@ -76,26 +78,27 @@ public class VehicleBaseEntity extends Entity {
}); });
} }
public void SetIntDataValue(String ValueName, Integer Value){if(VEHICLE_SYNCHED_INT_PARAMETERS.containsKey(ValueName)) this.dataManager.set(VEHICLE_SYNCHED_INT_PARAMETERS.get(ValueName),Value);}
public void SetIntDataValue(String ValueName, Integer Value){ public Integer GetIntDataValue(String ValueName){return this.dataManager.get(VEHICLE_SYNCHED_INT_PARAMETERS.get(ValueName)); }
if(VEHICLE_SYNCHED_INT_PARAMETERS.containsKey(ValueName)) this.dataManager.set(VEHICLE_SYNCHED_INT_PARAMETERS.get(ValueName),Value); public void SetFloatDataValue(String ValueName, Float Value){if(VEHICLE_SYNCHED_FLOAT_PARAMETERS.containsKey(ValueName)) this.dataManager.set(VEHICLE_SYNCHED_FLOAT_PARAMETERS.get(ValueName),Value);}
public Float GetFloatDataValue(String ValueName){ return this.dataManager.get(VEHICLE_SYNCHED_FLOAT_PARAMETERS.get(ValueName));}
public void SetBooleanDataValue(String ValueName, Boolean Value){ if(VEHICLE_SYNCHED_BOOLEAN_PARAMETERS.containsKey(ValueName)) this.dataManager.set(VEHICLE_SYNCHED_BOOLEAN_PARAMETERS.get(ValueName),Value); }
public Boolean GetBooleanDataValue(String ValueName){ return this.dataManager.get(VEHICLE_SYNCHED_BOOLEAN_PARAMETERS.get(ValueName));}
public void SetVehicleRoll(float value){
SetFloatDataValue("ORIENTATION_ROLL",value);
} }
public Integer GetIntDataValue(String ValueName){ public void SetVehicleYaw(float value){SetFloatDataValue("ORIENTATION_YAW", value);}
return this.dataManager.get(VEHICLE_SYNCHED_INT_PARAMETERS.get(ValueName)); public void SetVehiclePitch(float value){SetFloatDataValue("ORIENTATION_PITCH", value); }
public float GetVehicleRoll(){return GetFloatDataValue("ORIENTATION_ROLL"); }
public float GetVehicleYaw(){ return GetFloatDataValue("ORIENTATION_YAW"); }
public float GetVehiclePitch(){return GetFloatDataValue("ORIENTATION_PITCH"); }
public float[] GetVehicleRotations(){
return new float[]{GetVehicleYaw(),GetVehiclePitch(),GetVehicleRoll()};
} }
public void SetVehicleRotations(float Yaw, float Pitch, float Roll){
public void SetFloatDataValue(String ValueName, Float Value){ SetVehicleRoll(Roll);
if(VEHICLE_SYNCHED_FLOAT_PARAMETERS.containsKey(ValueName)) this.dataManager.set(VEHICLE_SYNCHED_FLOAT_PARAMETERS.get(ValueName),Value); SetVehicleYaw(Yaw);
} SetVehiclePitch(Pitch);
public Float GetFloatDataValue(String ValueName){
return this.dataManager.get(VEHICLE_SYNCHED_FLOAT_PARAMETERS.get(ValueName));
}
public void SetBooleanDataValue(String ValueName, Boolean Value){
if(VEHICLE_SYNCHED_BOOLEAN_PARAMETERS.containsKey(ValueName)) this.dataManager.set(VEHICLE_SYNCHED_BOOLEAN_PARAMETERS.get(ValueName),Value);
}
public Boolean GetBooleanDataValue(String ValueName){
return this.dataManager.get(VEHICLE_SYNCHED_BOOLEAN_PARAMETERS.get(ValueName));
} }
@Override @Override
@@ -1,4 +1,4 @@
package net.halbear.hvf.Entity.Example; package net.halbear.hvf.Example;
import net.halbear.hvf.Entity.VehicleBaseEntity; import net.halbear.hvf.Entity.VehicleBaseEntity;
import net.halbear.hvf.Util.Client.VehicleCameraPreset; import net.halbear.hvf.Util.Client.VehicleCameraPreset;
@@ -26,21 +26,5 @@ public class Aeroplane extends VehicleBaseEntity {
new VehicleCameraPreset(new Vector3f(0,0,4.5f), new VehicleCameraPreset(new Vector3f(0,0,4.5f),
new Vector3f(0,0,0),70,60)); new Vector3f(0,0,0),70,60));
} }
public void SetVehicleRoll(float value){
SetFloatDataValue("ORIENTATION_ROLL",value);
}
public void SetVehicleYaw(float value){SetFloatDataValue("ORIENTATION_YAW", value);}
public void SetVehiclePitch(float value){SetFloatDataValue("ORIENTATION_PITCH", value); }
public float GetVehicleRoll(){return GetFloatDataValue("ORIENTATION_ROLL"); }
public float GetVehicleYaw(){ return GetFloatDataValue("ORIENTATION_YAW"); }
public float GetVehiclePitch(){return GetFloatDataValue("ORIENTATION_PITCH"); }
public float[] GetVehicleRotations(){
return new float[]{GetVehicleYaw(),GetVehiclePitch(),GetVehicleRoll()};
}
public void SetVehicleRotations(float Yaw, float Pitch, float Roll){
SetVehicleRoll(Roll);
SetVehicleYaw(Yaw);
SetVehiclePitch(Pitch);
}
} }
@@ -0,0 +1,30 @@
package net.halbear.hvf.Example;
import net.halbear.hvf.Entity.VehicleBaseEntity;
import net.halbear.hvf.Util.Client.VehicleCameraPreset;
import net.halbear.hvf.Util.Client.VehicleCameraSettings;
import net.halbear.hvf.Util.VehicleData.EngineCategories;
import net.halbear.hvf.Util.VehicleData.VehicleBuildInfo;
import net.halbear.hvf.Util.VehicleData.VehicleClassification;
import net.minecraft.entity.EntityType;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.util.math.vector.Vector3f;
import net.minecraft.world.World;
public class Airboat extends VehicleBaseEntity {
private static final VehicleBuildInfo buildInfo = new VehicleBuildInfo(VehicleClassification.Zepplin)
.SetEngineCount(2)
.SetEngineType(EngineCategories.Aircraft_Propeller)
.SetMaxEngineRPM(3000)
.SetMaxSpeedMS(70)
.SetGasCelCount(8)
.SetGasCelCapacity(1000);
public Airboat(EntityType<?> Type, World WorldIn) {
super(Type, WorldIn, new Vector3d[]{new Vector3d(0.0D, -1D, 0.0D)}, buildInfo);
VehicleCameraSettings.AddEntityCameraPreset(this.getType(),
new VehicleCameraPreset(new Vector3f(0,4.0f, 16.0f),
new Vector3f(0,0,0),70,65f));
}
}
@@ -0,0 +1,16 @@
package net.halbear.hvf.Example.Renderer;
import net.halbear.hvf.Example.Renderer.Models.AeroplaneModel;
import net.halbear.hvf.Entity.Renderer.VehicleBaseRenderer;
import net.minecraft.client.renderer.entity.EntityRendererManager;
import net.minecraft.client.renderer.entity.model.EntityModel;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class AeroplaneRenderer extends VehicleBaseRenderer {
public AeroplaneRenderer(EntityRendererManager renderManagerIn) {
super(renderManagerIn, new EntityModel<?>[]{new AeroplaneModel()},"textures/entities/biplaneupdated.png");
}
}
@@ -0,0 +1,16 @@
package net.halbear.hvf.Example.Renderer;
import net.halbear.hvf.Entity.Renderer.VehicleBaseRenderer;
import net.halbear.hvf.Example.Renderer.Models.AirboatModel;
import net.minecraft.client.renderer.entity.EntityRendererManager;
import net.minecraft.client.renderer.entity.model.EntityModel;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@OnlyIn(Dist.CLIENT)
public class AirboatRenderer extends VehicleBaseRenderer {
public AirboatRenderer(EntityRendererManager renderManagerIn) {
super(renderManagerIn, new EntityModel<?>[]{new AirboatModel()},"textures/entities/airboat.png" );
}
}
@@ -1,12 +1,11 @@
package net.halbear.hvf.Entity.Example.Renderer.Models; package net.halbear.hvf.Example.Renderer.Models;
import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.vertex.IVertexBuilder; import com.mojang.blaze3d.vertex.IVertexBuilder;
import net.halbear.hvf.Entity.Example.Aeroplane; import net.halbear.hvf.Example.Aeroplane;
import net.halbear.hvf.Entity.VehicleBaseEntity; import net.halbear.hvf.Entity.VehicleBaseEntity;
import net.minecraft.client.renderer.entity.model.EntityModel; import net.minecraft.client.renderer.entity.model.EntityModel;
import net.minecraft.client.renderer.model.ModelRenderer; import net.minecraft.client.renderer.model.ModelRenderer;
import net.halbear.hvf.*;
public class AeroplaneModel extends EntityModel<VehicleBaseEntity> { public class AeroplaneModel extends EntityModel<VehicleBaseEntity> {
private final ModelRenderer Body; private final ModelRenderer Body;
File diff suppressed because it is too large Load Diff
@@ -1,6 +1,7 @@
package net.halbear.hvf.Registry.EventHandlers; package net.halbear.hvf.Registry.EventHandlers;
import net.halbear.hvf.Entity.Example.Renderer.AeroplaneRenderer; import net.halbear.hvf.Example.Renderer.AeroplaneRenderer;
import net.halbear.hvf.Example.Renderer.AirboatRenderer;
import net.halbear.hvf.Halsvehicleframework; import net.halbear.hvf.Halsvehicleframework;
import net.halbear.hvf.Registry.ModEntities; import net.halbear.hvf.Registry.ModEntities;
import net.minecraft.block.Block; import net.minecraft.block.Block;
@@ -24,5 +25,6 @@ public class ClientEventHandler {
@SubscribeEvent @SubscribeEvent
public static void init(final FMLClientSetupEvent event) { public static void init(final FMLClientSetupEvent event) {
RenderingRegistry.registerEntityRenderingHandler(ModEntities.AEROPLANE.get(), AeroplaneRenderer::new); RenderingRegistry.registerEntityRenderingHandler(ModEntities.AEROPLANE.get(), AeroplaneRenderer::new);
RenderingRegistry.registerEntityRenderingHandler(ModEntities.AIRBOAT.get(), AirboatRenderer::new);
} }
} }
@@ -1,6 +1,7 @@
package net.halbear.hvf.Registry; package net.halbear.hvf.Registry;
import net.halbear.hvf.Entity.Example.Aeroplane; import net.halbear.hvf.Example.Aeroplane;
import net.halbear.hvf.Example.Airboat;
import net.halbear.hvf.Halsvehicleframework; import net.halbear.hvf.Halsvehicleframework;
import net.minecraft.entity.EntityClassification; import net.minecraft.entity.EntityClassification;
import net.minecraft.entity.EntityType; import net.minecraft.entity.EntityType;
@@ -15,4 +16,7 @@ public class ModEntities {
public static final RegistryObject<EntityType<Aeroplane>> AEROPLANE = public static final RegistryObject<EntityType<Aeroplane>> AEROPLANE =
ENTITY_TYPES.register("aeroplane", ()-> EntityType.Builder.create(Aeroplane::new, ENTITY_TYPES.register("aeroplane", ()-> EntityType.Builder.create(Aeroplane::new,
EntityClassification.MISC ).size(3f,2f).build(new ResourceLocation(Halsvehicleframework.MOD_ID, "aeroplane").toString())); EntityClassification.MISC ).size(3f,2f).build(new ResourceLocation(Halsvehicleframework.MOD_ID, "aeroplane").toString()));
public static final RegistryObject<EntityType<Airboat>> AIRBOAT =
ENTITY_TYPES.register("airboat", ()-> EntityType.Builder.create(Airboat::new,
EntityClassification.MISC ).size(3f,2f).build(new ResourceLocation(Halsvehicleframework.MOD_ID, "airboat").toString()));
} }
Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB