diff --git a/README.md b/README.md index 51fa7ba..c02592a 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,8 @@ This addon adds new features to DynamX : - Klaxon and siren - Fuel tank - Immatriculation plates -- Speed display on the vehicle +- Speed, gear and speed limit display on the vehicle +- Needle ### How to add modules: @@ -71,6 +72,55 @@ FuelTank#Op{ } ``` +#### Better speed-display + +``` +TextInfo#Op{ + Position: 0 0 0 + Scale: 1 1 1 + Rotation: 0 0 0 + Color: 0 0 0 + DetailToShow: GEAR + CarStartedReact: True +} +``` + +The `DetailToShow` can be one of the following: + - GEAR + - SPEED + - SPEEDLIMITOR + +It will display the current gear, speed or speedlimitor value at the position. + +The `CarStartedReact` can be `True` or `False` and will enable or disable the display when the car is started. + +### DashboardNeedle + +``` +DashboardNeedle_2 { + Position: 0 0 0 + Rotation: 0 0 -120 + ObjectName: speedneedle + NeedleMaxTurn: 160 + DashboardMaxValue: 6000 + NeedleType: RPM +} +``` + +| Key | Value | +|------------------- |------------------------------------------ | +| Rotation | Default rotation | +| Position | Default position | +| ObjectName | Name of the object in the 3D model | +| NeedleMaxTurn | Max rotation in degrees on the dashboard | +| DashboardMaxValue | Max value displayed on dashboard | +| NeedleType | It can be `RPM` or `SPEED` | + + +
+ +> Here for RPM, max DashboardMaxValue is 6000 and max NeedleMaxTurn is 160. + ## Links DynamX website: https://dynamx.fr diff --git a/exemple.png b/exemple.png new file mode 100644 index 0000000..b391d52 Binary files /dev/null and b/exemple.png differ diff --git a/src/main/java/fr/dynamx/addons/basics/BasicsAddon.java b/src/main/java/fr/dynamx/addons/basics/BasicsAddon.java index 5230f71..8e7ac79 100644 --- a/src/main/java/fr/dynamx/addons/basics/BasicsAddon.java +++ b/src/main/java/fr/dynamx/addons/basics/BasicsAddon.java @@ -4,10 +4,13 @@ import fr.dynamx.addons.basics.client.BasicsAddonController; import fr.dynamx.addons.basics.client.InteractionKeyController; import fr.dynamx.addons.basics.common.infos.BasicsItemInfo; +import fr.dynamx.addons.basics.common.infos.DashboardNeedleInfo.EnumDashboardNeedleType; +import fr.dynamx.addons.basics.common.infos.DashboardTextInfos.EnumDashboardTextType; import fr.dynamx.addons.basics.server.CommandBasicsSpawn; import fr.dynamx.addons.basics.utils.FuelJerrycanUtils; import fr.dynamx.addons.basics.utils.VehicleKeyUtils; import fr.dynamx.api.contentpack.DynamXAddon; +import fr.dynamx.api.contentpack.registry.DefinitionType; import fr.dynamx.common.contentpack.type.objects.ItemObject; import fr.dynamx.common.items.DynamXItem; import fr.dynamx.common.items.DynamXItemRegistry; @@ -20,7 +23,6 @@ import net.minecraft.world.World; import net.minecraftforge.fml.client.registry.ClientRegistry; import net.minecraftforge.fml.common.FMLCommonHandler; -import net.minecraftforge.fml.common.Loader; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.event.FMLServerStartingEvent; import net.minecraftforge.fml.relauncher.Side; @@ -47,6 +49,8 @@ public static void initAddon() { } registerKey(); registerJerrycan(); + new DefinitionType<>(EnumDashboardNeedleType.class, EnumDashboardNeedleType::fromString, "type.dashboardneedletype"); + new DefinitionType<>(EnumDashboardTextType.class, EnumDashboardTextType::fromString, "type.dashboardtexttype"); } private static void registerKey() { diff --git a/src/main/java/fr/dynamx/addons/basics/common/infos/DashboardNeedleInfo.java b/src/main/java/fr/dynamx/addons/basics/common/infos/DashboardNeedleInfo.java new file mode 100644 index 0000000..c303f3b --- /dev/null +++ b/src/main/java/fr/dynamx/addons/basics/common/infos/DashboardNeedleInfo.java @@ -0,0 +1,146 @@ +package fr.dynamx.addons.basics.common.infos; + +import com.jme3.math.Vector3f; +import fr.dynamx.addons.basics.utils.TextUtils; +import fr.dynamx.api.contentpack.object.part.BasePart; +import fr.dynamx.api.contentpack.object.part.IDrawablePart; +import fr.dynamx.api.contentpack.registry.DefinitionType; +import fr.dynamx.api.contentpack.registry.PackFileProperty; +import fr.dynamx.api.contentpack.registry.RegisteredSubInfoType; +import fr.dynamx.api.contentpack.registry.SubInfoTypeRegistries; +import fr.dynamx.api.entities.VehicleEntityProperties; +import fr.dynamx.client.renders.model.renderer.DxModelRenderer; +import fr.dynamx.client.renders.scene.EntityRenderContext; +import fr.dynamx.client.renders.scene.SceneBuilder; +import fr.dynamx.client.renders.scene.SceneGraph; +import fr.dynamx.common.contentpack.type.vehicle.ModularVehicleInfo; +import fr.dynamx.common.entities.BaseVehicleEntity; +import fr.dynamx.common.entities.modules.engines.CarEngineModule; +import fr.dynamx.utils.DynamXUtils; +import net.minecraft.client.renderer.GlStateManager; +import org.lwjgl.opengl.GL11; + +import javax.annotation.Nullable; +import java.util.List; +import java.util.Objects; + +@RegisteredSubInfoType(name = "DashboardNeedle", registries = SubInfoTypeRegistries.WHEELED_VEHICLES, strictName = false) +public class DashboardNeedleInfo extends BasePart implements IDrawablePart, ModularVehicleInfo> { + @PackFileProperty(configNames = "Rotation", type = DefinitionType.DynamXDefinitionTypes.VECTOR3F) + protected Vector3f rotation; + + @PackFileProperty(configNames = "ObjectName", required = false, defaultValue = "speedneedle") + protected String objectName; + + @PackFileProperty(configNames = "NeedleMaxTurn", required = false, defaultValue = "140", description = "common.NeedleMaxTurn") + protected int needleMaxTurn; + + @PackFileProperty(configNames = "DashboardMaxValue", required = false, defaultValue = "140", description = "common.DashboardMaxSpeed") + protected int dashboardMaxValue; + + @PackFileProperty(configNames = "DependsOnNode", required = false, description = "common.DependsOnNode") + protected String nodeDependingOnName; + + @PackFileProperty(configNames = "NeedleType", required = false, defaultValue = "SPEED", description = "common.NeedleType") + protected EnumDashboardNeedleType needleType; + + @Override + public String getNodeName() { + return getPartName(); + } + + @Override + public String getObjectName() { + return this.objectName; + } + + @Override + public void addToSceneGraph(ModularVehicleInfo packInfo, SceneBuilder, ModularVehicleInfo> sceneBuilder) { + if (nodeDependingOnName != null) { + sceneBuilder.addNode(this, nodeDependingOnName, getNodeName()); + } else { + sceneBuilder.addNode(this, getNodeName()); + } + } + + @Override + public SceneGraph, ModularVehicleInfo> createSceneGraph(Vector3f modelScale, List, ModularVehicleInfo>> childGraph) { + if (childGraph != null) throw new IllegalArgumentException("DashboardNeedleInfo can't have children parts"); + return new SpeedNeedleNode<>(modelScale, null); + } + + @Override + public String getName() { + return "PartShape named " + getPartName() + " in " + Objects.requireNonNull(getOwner()).getName(); + } + + public int getNeedleMaxTurn() { + return needleMaxTurn; + } + + public int getDashboardMaxValue() { + return dashboardMaxValue; + } + + public EnumDashboardNeedleType getNeedleType() { + return needleType; + } + + public Vector3f getRotation() { + return rotation; + } + + public String getNodeDependingOnName() { + return this.nodeDependingOnName; + } + + public DashboardNeedleInfo(ModularVehicleInfo owner, String partName) { + super(owner, partName); + } + + + class SpeedNeedleNode, A extends ModularVehicleInfo> extends SceneGraph.Node { + + public SpeedNeedleNode(Vector3f scale, List> linkedChilds) { + super(null, null, scale, linkedChilds); + } + + @Override + public void render(@Nullable T entity, EntityRenderContext entityRenderContext, A packInfo) { + if (entity == null) return; + DxModelRenderer vehicleModel = entityRenderContext.getModel(); + byte b = entityRenderContext.getTextureId(); + if (entityRenderContext.getModel().containsObjectOrNode(DashboardNeedleInfo.this.getObjectName()) && entity.getModuleByType(CarEngineModule.class) != null && DashboardNeedleInfo.this.getPosition() != null) { + GlStateManager.pushMatrix(); + Vector3f pos = DashboardNeedleInfo.this.getPosition(); + GL11.glTranslatef(pos.x, pos.y, pos.z); + TextUtils.makeGLRotation(getRotation()); + switch (DashboardNeedleInfo.this.getNeedleType()) { + case RPM: + int rpms = Math.round(entity.getModuleByType(CarEngineModule.class).getEngineProperty(VehicleEntityProperties.EnumEngineProperties.REVS) * 10000); + GlStateManager.rotate((float) DashboardNeedleInfo.this.needleMaxTurn * rpms / DashboardNeedleInfo.this.dashboardMaxValue, 0, 0, 1); + break; + case SPEED: + GlStateManager.rotate((float) DashboardNeedleInfo.this.needleMaxTurn * DynamXUtils.getSpeed(entity) / DashboardNeedleInfo.this.dashboardMaxValue, 0, 0, 1); + break; + } + vehicleModel.renderGroup(DashboardNeedleInfo.this.getObjectName(), b, entityRenderContext.isUseVanillaRender()); + GlStateManager.popMatrix(); + } + } + } + + public enum EnumDashboardNeedleType { + SPEED, RPM; + + public static EnumDashboardNeedleType fromString(String targetName) { + for (EnumDashboardNeedleType dashboardNeedleType : values()) { + if (dashboardNeedleType.name().equalsIgnoreCase(targetName)) { + return dashboardNeedleType; + } + } + throw new IllegalArgumentException("Invalid DashboardNeedleType value '" + targetName + "'"); + } + } + +} diff --git a/src/main/java/fr/dynamx/addons/basics/common/infos/DashboardTextInfos.java b/src/main/java/fr/dynamx/addons/basics/common/infos/DashboardTextInfos.java new file mode 100644 index 0000000..550bf04 --- /dev/null +++ b/src/main/java/fr/dynamx/addons/basics/common/infos/DashboardTextInfos.java @@ -0,0 +1,150 @@ +package fr.dynamx.addons.basics.common.infos; + +import com.jme3.math.Vector3f; +import fr.dynamx.addons.basics.BasicsAddon; +import fr.dynamx.addons.basics.utils.TextUtils; +import fr.dynamx.api.contentpack.object.part.BasePart; +import fr.dynamx.api.contentpack.object.part.IDrawablePart; +import fr.dynamx.api.contentpack.registry.DefinitionType; +import fr.dynamx.api.contentpack.registry.PackFileProperty; +import fr.dynamx.api.contentpack.registry.RegisteredSubInfoType; +import fr.dynamx.api.contentpack.registry.SubInfoTypeRegistries; +import fr.dynamx.api.entities.VehicleEntityProperties; +import fr.dynamx.client.renders.scene.EntityRenderContext; +import fr.dynamx.client.renders.scene.SceneBuilder; +import fr.dynamx.client.renders.scene.SceneGraph; +import fr.dynamx.common.contentpack.type.vehicle.ModularVehicleInfo; +import fr.dynamx.common.entities.BaseVehicleEntity; +import fr.dynamx.common.entities.modules.engines.CarEngineModule; +import fr.dynamx.utils.DynamXUtils; + +import javax.annotation.Nullable; +import java.util.List; +import java.util.Objects; + +@RegisteredSubInfoType(name = "TextInfo", registries = {SubInfoTypeRegistries.WHEELED_VEHICLES}, strictName = false) +public class DashboardTextInfos extends BasePart implements IDrawablePart, ModularVehicleInfo> { + @PackFileProperty(configNames = "Rotation", type = DefinitionType.DynamXDefinitionTypes.VECTOR3F, description = "common.rotation") + protected Vector3f rotation; + + @PackFileProperty(configNames = "Font", required = false) + protected String font = BasicsAddon.ID + ":e"; + + @PackFileProperty(configNames = "DetailToShow", required = false, defaultValue = "GEAR") + protected EnumDashboardTextType detailToShow; + @PackFileProperty(configNames = "CarStartedReact", required = false, defaultValue = "false", type = DefinitionType.DynamXDefinitionTypes.BOOL) + protected boolean carStartedReact; + + @PackFileProperty(configNames = "Color", description = "common.color", required = false) + protected int[] color = new int[]{10, 10, 10}; + + @PackFileProperty(configNames = "DependsOnNode", required = false, description = "common.DependsOnNode") + protected String nodeDependingOnName; + + public DashboardTextInfos(ModularVehicleInfo owner, String partName) { + super(owner, partName); + } + + @Override + public void appendTo(ModularVehicleInfo owner) { + owner.addSubProperty(this); + } + + public Vector3f getRotation() { + return rotation; + } + + public int[] getColor() { + return color; + } + + public boolean isCarStartedReact() { + return carStartedReact; + } + + public String getFont() { + return font; + } + + public EnumDashboardTextType getDetailToShow() { + return detailToShow; + } + + @Override + public String getName() { + return "PartShape named " + getPartName() + " in " + getOwner().getName(); + } + + @Override + public String getObjectName() { + return null; + } + + + @Override + public String getNodeName() { + + return getPartName(); + } + + @Override + public void addToSceneGraph(ModularVehicleInfo packInfo, SceneBuilder, ModularVehicleInfo> sceneBuilder) { + if (nodeDependingOnName != null) { + sceneBuilder.addNode(this, nodeDependingOnName, getNodeName()); + } else { + sceneBuilder.addNode(this, getNodeName()); + } + } + + @Override + public SceneGraph, ModularVehicleInfo> createSceneGraph(Vector3f modelScale, List, ModularVehicleInfo>> childGraph) { + if (childGraph != null) throw new IllegalArgumentException("TextInfo can't have children parts"); + return new SpeedDisplayNode<>(modelScale, null); + } + + class SpeedDisplayNode, A extends ModularVehicleInfo> extends SceneGraph.Node { + public SpeedDisplayNode(Vector3f scale, List> linkedChilds) { + super(null, null, scale, linkedChilds); + } + + @Override + public void render(@Nullable T entity, EntityRenderContext entityRenderContext, A packInfo) { + if (entity == null) return; + if (DashboardTextInfos.this.getRotation() != null) { + if (entity.getModuleByType(CarEngineModule.class).getPhysicsHandler().getEngine().isStarted() && DashboardTextInfos.this.isCarStartedReact()) { + String value = ""; + switch (DashboardTextInfos.this.getDetailToShow()) { + case GEAR: + float gear = entity.getModuleByType(CarEngineModule.class).getEngineProperty(VehicleEntityProperties.EnumEngineProperties.ACTIVE_GEAR); + if (gear == 0) value = "N"; + else if (gear == -1) value = "R" + (int) Math.abs(gear); + else value = "D" + (int) gear; + break; + case SPEEDLIMITOR: + int tempvalue = Math.round(entity.getModuleByType(CarEngineModule.class).getSpeedLimit()); + if (tempvalue != 0 & tempvalue < 10000000) value = String.valueOf(tempvalue); + else value = ""; + break; + case SPEED: + value = String.valueOf(DynamXUtils.getSpeed(entity)); + break; + } + TextUtils.drawText(DashboardTextInfos.this.getPosition(), DashboardTextInfos.this.getScale(), DashboardTextInfos.this.getRotation(), value, getColor(), getFont()); + } + } + } + } + + public enum EnumDashboardTextType { + SPEED, GEAR, SPEEDLIMITOR; + + public static EnumDashboardTextType fromString(String targetName) { + for (EnumDashboardTextType dashboardNeedleType : values()) { + if (dashboardNeedleType.name().equalsIgnoreCase(targetName)) { + return dashboardNeedleType; + } + } + throw new IllegalArgumentException("Invalid EnumDashboardTextType value '" + targetName + "'"); + } + } +} \ No newline at end of file diff --git a/src/main/java/fr/dynamx/addons/basics/common/infos/SpeedDisplayInfos.java b/src/main/java/fr/dynamx/addons/basics/common/infos/SpeedDisplayInfos.java index 575ca3e..30b7823 100644 --- a/src/main/java/fr/dynamx/addons/basics/common/infos/SpeedDisplayInfos.java +++ b/src/main/java/fr/dynamx/addons/basics/common/infos/SpeedDisplayInfos.java @@ -80,6 +80,7 @@ public String getNodeName() { @Override public void addToSceneGraph(ModularVehicleInfo packInfo, SceneBuilder, ModularVehicleInfo> sceneBuilder) { + if(getRotation() == null) return; if (nodeDependingOnName != null) { sceneBuilder.addNode(this, nodeDependingOnName, getNodeName()); } else { @@ -89,7 +90,7 @@ public void addToSceneGraph(ModularVehicleInfo packInfo, SceneBuilder, ModularVehicleInfo> createSceneGraph(Vector3f modelScale, List, ModularVehicleInfo>> childGraph) { - if(childGraph != null) + if (childGraph != null) throw new IllegalArgumentException("SpeedDisplayInfos can't have children parts"); return new SpeedDisplayNode<>(modelScale, null); } @@ -105,6 +106,7 @@ public void render(@Nullable T entity, EntityRenderContext entityRenderContext, return; String speed = "" + DynamXUtils.getSpeed(entity); TextUtils.drawText(SpeedDisplayInfos.this.getPosition(), SpeedDisplayInfos.this.getScale(), SpeedDisplayInfos.this.getRotation(), speed, getColor(), getFont()); + } } } \ No newline at end of file diff --git a/src/main/java/fr/dynamx/addons/basics/utils/TextUtils.java b/src/main/java/fr/dynamx/addons/basics/utils/TextUtils.java index e5fccc8..b879898 100644 --- a/src/main/java/fr/dynamx/addons/basics/utils/TextUtils.java +++ b/src/main/java/fr/dynamx/addons/basics/utils/TextUtils.java @@ -19,15 +19,7 @@ public static void drawText(Vector3f pos, Vector3f scale, Vector3f rotation, Str GlStateManager.translate(pos.x, pos.y, pos.z); GlStateManager.rotate(180, 1, 0, 0); GlStateManager.rotate(180, 0, 1, 0); - float rotate = rotation.x; - if (rotate != 0) - GlStateManager.rotate(rotate, 1, 0, 0); - rotate = rotation.y; - if (rotate != 0) - GlStateManager.rotate(rotate, 0, 1, 0); - rotate = rotation.z; - if (rotate != 0) - GlStateManager.rotate(rotate, 0, 0, 1); + makeGLRotation(rotation); GlStateManager.scale(scale.x / 40, scale.y / 40, scale.z / 40); GlStateManager.disableLighting(); @@ -45,4 +37,16 @@ public static void drawText(Vector3f pos, Vector3f scale, Vector3f rotation, Str GlStateManager.popMatrix(); } } + + public static void makeGLRotation(Vector3f rotation) { + float rotate = rotation.x; + if (rotate != 0) + GlStateManager.rotate(rotate, 1, 0, 0); + rotate = rotation.y; + if (rotate != 0) + GlStateManager.rotate(rotate, 0, 1, 0); + rotate = rotation.z; + if (rotate != 0) + GlStateManager.rotate(rotate, 0, 0, 1); + } }