Jump to content

Recommended Posts

Posted

Hi,

 

I'm currently working on a mod and now I want to now why Minecraft's performance is so bad.

So that when I know why Minecraft's performance is so bad I can maybe optimize my own mod to the maximum. ;)

 

Thx in advance.

Bektor

Developer of Primeval Forest.

Posted

This is like asking: "Why is economy so stupid? I can learn about it and make better one ON TOP of it!"

 

As of now I can only say that Minecraft fails on Server side, where there is no Multithreading (e.g: per world, which I heard might be implemented in future).

As to everything else - there are some stupid flaws (leftoverst from early code), but game like MC written in Java is probably worst part of it (GC and RAM freeing).

While saying it is bad, I personally love MC in Java so... yeah. :P

 

Anyway - you can't possibly lag whole game, unless you'd make large computational operations - which are special case so I'll skip them.

 

As to small things - you want to avoid making expensive per-tick operations and/or constant syncing. Prefere to send more small packets to update specific things, and only when it's needed, than sending everything (e.g whole player data) every tick or few.

 

I can't imagine how bad of a coder you'd have to be to actually write that laggy mod (again: not considering heavy computations).

1.7.10 is no longer supported by forge, you are on your own.

Posted

One of Minecraft's biggest problems in terms of performance is that they are stuck using outdated GL, because everyone would scream if suddenly the game stops working on grandma's potato.

yes.

DRAGONMANG: "I'm Dragonmang, m8. Here me roar."

HERO: "Oh no... not. Dragonmang."

DRAGONMANG: "Roar, m8."

HERO: "Ahhh......"

And so the brave knight and Dragonmang fought on the mountaintop for many moons....

Posted

As of now I can only say that Minecraft fails on Server side, where there is no Multithreading (e.g: per world, which I heard might be implemented in future).

 

If server side isn't able to handle multithreading, why would be the point to rent servers with huge cpu ?

Squirrel ! Squirrel ! Squirrel !

Posted

Hi,

 

I'm currently working on a mod and now I want to now why Minecraft's performance is so bad.

So that when I know why Minecraft's performance is so bad I can maybe optimize my own mod to the maximum. ;)

 

Thx in advance.

Bektor

 

The first two advices that came to me are based on the code of the many mods I've checked:

 

- stay away from "copy&paste" code

- don't be afraid to use the stack

 

 

Z

Posted

Thx for all the answers. ;)

 

One of Minecraft's biggest problems in terms of performance is that they are stuck using outdated GL, because everyone would scream if suddenly the game stops working on grandma's potato. Why people think Minecraft is an exception to the fact that you need at least a semi-decent PC to run games I don't know, but that's how it is.

 

This limits what they can do in terms of optimization.

What makes outdated OpenGL (I think Minecraft uses 2) so slow compared to modern OpenGL?

 

Next point: I want to implement some simple physics like TFC and a better world generator for my own dimension. How can I get a good performance beside optimizing the math behind it.

Developer of Primeval Forest.

Posted

What makes outdated OpenGL (I think Minecraft uses 2) so slow compared to modern OpenGL?

 

GL_QUADS is bad for performance because it requires triangle computation on the CPU.

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Posted

What makes outdated OpenGL (I think Minecraft uses 2) so slow compared to modern OpenGL?

I am no expert by any means, but here goes:

In traditional OpenGL the CPU issues very very many draw calls (e.g. to draw a quad you need glBegin, then glVertex stuff, then glEnd). These are all individual native calls that need to be transferred over the (comparatively) slow path from CPU to GPU. This has to happen every frame. There are some improvements to this such as display lists but it does not change the overall concept.

Modern GL let's you actually run code on the GPU (shaders) so that you do not have to pay the expensive transfer cost for data from CPU to GPU.

This is my view on it, I am probably wrong in a lot of ways, but I think that's the general concept.

Well, the data will still be transfererd from the CPU to the GPU. But the json files from 1.8 just feel to me like bad shaders from OpenGL 3.3+. xD

And I'm not an expert in that stuff, too. Just started once with OpenGL 3.3 and 4.1 programming, but never did that much.... (currently playing around with the new Vulkan API and C++14).

But I know for sure that OpenGL 3.3 supports texture compression and I don't think OpenGL or at least Mojang does it, because otherwhise I can't explain myself how someone can fill the VRAM with 8GB of Minecraft textures while playing a mod pack and Games like Battlefront and Battlefield don't use so much VRAM and have a way better texture quality.

 

But thx for the answer.

 

 

To the next point:

Could you give me an example of how to do multi-threading in MC. I've got really no idea of how to implement that in Minecraft.... (well, for me it sometimes is just easier to write my own 2D game then modding MC, because on my own Games I know every single line of code and what it does and how :P )

 

Could you please explain the last thing again? I didn't understand it. :( [kannst ja auch in Deutsch erklären wenn du willst ;) ]

 

Bektor

Developer of Primeval Forest.

Posted

Doing Multithreading in Minecraft is difficult, since most of Minecraft is not threadsafe in any way. For example you cannot just put blocks in the world from a 2nd thread or you will risk crashes and very hard to track bugs.

But what you could do is e.g. generate a maze in a 2nd thread and then place the blocks in the main thread based on the already generated maze data.

 

How to do this depends on exactly which task you are trying to do. Some tasks are better done in just one thread, some can be very easily split up into as many threads as you want (keywords: divide and conquer, ForkJoin). How all this works is much more than fits into a forum post here though.

Ok, thx. ;)

Developer of Primeval Forest.

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

    • Version 1.19 - Forge 41.0.63 I want to create a wolf entity that I can ride, so far it seems to be working, but the problem is that when I get on the wolf, I can’t control it. I then discovered that the issue is that the server doesn’t detect that I’m riding the wolf, so I’m struggling with synchronization. However, it seems to not be working properly. As I understand it, the server receives the packet but doesn’t register it correctly. I’m a bit new to Java, and I’ll try to provide all the relevant code and prints *The comments and prints are translated by chatgpt since they were originally in Spanish* Thank you very much in advance No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. MountableWolfEntity package com.vals.valscraft.entity; import com.vals.valscraft.network.MountSyncPacket; import com.vals.valscraft.network.NetworkHandler; import net.minecraft.client.Minecraft; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.ai.attributes.AttributeSupplier; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.animal.Wolf; import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.Entity; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; import net.minecraftforge.event.TickEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.network.PacketDistributor; public class MountableWolfEntity extends Wolf { private boolean hasSaddle; private static final EntityDataAccessor<Byte> DATA_ID_FLAGS = SynchedEntityData.defineId(MountableWolfEntity.class, EntityDataSerializers.BYTE); public MountableWolfEntity(EntityType<? extends Wolf> type, Level level) { super(type, level); this.hasSaddle = false; } @Override protected void defineSynchedData() { super.defineSynchedData(); this.entityData.define(DATA_ID_FLAGS, (byte)0); } public static AttributeSupplier.Builder createAttributes() { return Wolf.createAttributes() .add(Attributes.MAX_HEALTH, 20.0) .add(Attributes.MOVEMENT_SPEED, 0.3); } @Override public InteractionResult mobInteract(Player player, InteractionHand hand) { ItemStack itemstack = player.getItemInHand(hand); if (itemstack.getItem() == Items.SADDLE && !this.hasSaddle()) { if (!player.isCreative()) { itemstack.shrink(1); } this.setSaddle(true); return InteractionResult.SUCCESS; } else if (!level.isClientSide && this.hasSaddle()) { player.startRiding(this); MountSyncPacket packet = new MountSyncPacket(true); // 'true' means the player is mounted NetworkHandler.CHANNEL.sendToServer(packet); // Ensure the server handles the packet return InteractionResult.SUCCESS; } return InteractionResult.PASS; } @Override public void travel(Vec3 travelVector) { if (this.isVehicle() && this.getControllingPassenger() instanceof Player) { System.out.println("The wolf has a passenger."); System.out.println("The passenger is a player."); Player player = (Player) this.getControllingPassenger(); // Ensure the player is the controller this.setYRot(player.getYRot()); this.yRotO = this.getYRot(); this.setXRot(player.getXRot() * 0.5F); this.setRot(this.getYRot(), this.getXRot()); this.yBodyRot = this.getYRot(); this.yHeadRot = this.yBodyRot; float forward = player.zza; float strafe = player.xxa; if (forward <= 0.0F) { forward *= 0.25F; } this.flyingSpeed = this.getSpeed() * 0.1F; this.setSpeed((float) this.getAttributeValue(Attributes.MOVEMENT_SPEED) * 1.5F); this.setDeltaMovement(new Vec3(strafe, travelVector.y, forward).scale(this.getSpeed())); this.calculateEntityAnimation(this, false); } else { // The wolf does not have a passenger or the passenger is not a player System.out.println("No player is mounted, or the passenger is not a player."); super.travel(travelVector); } } public boolean hasSaddle() { return this.hasSaddle; } public void setSaddle(boolean hasSaddle) { this.hasSaddle = hasSaddle; } @Override protected void dropEquipment() { super.dropEquipment(); if (this.hasSaddle()) { this.spawnAtLocation(Items.SADDLE); this.setSaddle(false); } } @SubscribeEvent public static void onServerTick(TickEvent.ServerTickEvent event) { if (event.phase == TickEvent.Phase.START) { MinecraftServer server = net.minecraftforge.server.ServerLifecycleHooks.getCurrentServer(); if (server != null) { for (ServerPlayer player : server.getPlayerList().getPlayers()) { if (player.isPassenger() && player.getVehicle() instanceof MountableWolfEntity) { MountableWolfEntity wolf = (MountableWolfEntity) player.getVehicle(); System.out.println("Tick: " + player.getName().getString() + " is correctly mounted on " + wolf); } } } } } private boolean lastMountedState = false; @Override public void tick() { super.tick(); if (!this.level.isClientSide) { // Only on the server boolean isMounted = this.isVehicle() && this.getControllingPassenger() instanceof Player; // Only print if the state changed if (isMounted != lastMountedState) { if (isMounted) { Player player = (Player) this.getControllingPassenger(); // Verify the passenger is a player System.out.println("Server: Player " + player.getName().getString() + " is now mounted."); } else { System.out.println("Server: The wolf no longer has a passenger."); } lastMountedState = isMounted; } } } @Override public void addPassenger(Entity passenger) { super.addPassenger(passenger); if (passenger instanceof Player) { Player player = (Player) passenger; if (!this.level.isClientSide && player instanceof ServerPlayer) { // Send the packet to the server to indicate the player is mounted NetworkHandler.CHANNEL.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new MountSyncPacket(true)); } } } @Override public void removePassenger(Entity passenger) { super.removePassenger(passenger); if (passenger instanceof Player) { Player player = (Player) passenger; if (!this.level.isClientSide && player instanceof ServerPlayer) { // Send the packet to the server to indicate the player is no longer mounted NetworkHandler.CHANNEL.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new MountSyncPacket(false)); } } } @Override public boolean isControlledByLocalInstance() { Entity entity = this.getControllingPassenger(); return entity instanceof Player; } @Override public void positionRider(Entity passenger) { if (this.hasPassenger(passenger)) { double xOffset = Math.cos(Math.toRadians(this.getYRot() + 90)) * 0.4; double zOffset = Math.sin(Math.toRadians(this.getYRot() + 90)) * 0.4; passenger.setPos(this.getX() + xOffset, this.getY() + this.getPassengersRidingOffset() + passenger.getMyRidingOffset(), this.getZ() + zOffset); } } } MountSyncPacket package com.vals.valscraft.network; import com.vals.valscraft.entity.MountableWolfEntity; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraftforge.network.NetworkEvent; import java.util.function.Supplier; public class MountSyncPacket { private final boolean isMounted; public MountSyncPacket(boolean isMounted) { this.isMounted = isMounted; } public void encode(FriendlyByteBuf buffer) { buffer.writeBoolean(isMounted); } public static MountSyncPacket decode(FriendlyByteBuf buffer) { return new MountSyncPacket(buffer.readBoolean()); } public void handle(NetworkEvent.Context context) { context.enqueueWork(() -> { ServerPlayer player = context.getSender(); // Get the player from the context if (player != null) { // Verifies if the player has dismounted if (!isMounted) { Entity vehicle = player.getVehicle(); if (vehicle instanceof MountableWolfEntity wolf) { // Logic to remove the player as a passenger wolf.removePassenger(player); System.out.println("Server: Player " + player.getName().getString() + " is no longer mounted."); } } } }); context.setPacketHandled(true); // Marks the packet as handled } } networkHandler package com.vals.valscraft.network; import com.vals.valscraft.valscraft; import net.minecraft.resources.ResourceLocation; import net.minecraftforge.network.NetworkRegistry; import net.minecraftforge.network.simple.SimpleChannel; import net.minecraftforge.network.NetworkEvent; import java.util.function.Supplier; public class NetworkHandler { private static final String PROTOCOL_VERSION = "1"; public static final SimpleChannel CHANNEL = NetworkRegistry.newSimpleChannel( new ResourceLocation(valscraft.MODID, "main"), () -> PROTOCOL_VERSION, PROTOCOL_VERSION::equals, PROTOCOL_VERSION::equals ); public static void init() { int packetId = 0; // Register the mount synchronization packet CHANNEL.registerMessage( packetId++, MountSyncPacket.class, MountSyncPacket::encode, MountSyncPacket::decode, (msg, context) -> msg.handle(context.get()) // Get the context with context.get() ); } }  
    • Do you use features of inventory profiles next (ipnext) or is there a change without it?
    • Remove rubidium - you are already using embeddium, which is a fork of rubidium
  • Topics

×
×
  • Create New...

Important Information

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