Jump to content

Recommended Posts

Posted

Okay, so I have a custom dimension in my mod and it is really bugging me. When I test it in Eclipse it works just fine. I can enter it and exit it without any issue. However, people are reporting that they are crashing when entering the dimension in the released version of the mod. Here is what one crash report says:

 

http://pastebin.com/VxqFEYJN

 

This is incredibly hard to debug because like I said, on my test environment in eclipse the dimension works just fine. Here is the dimension code:

 

ChunkProvider

http://pastebin.com/SS0Zxya2

 

Dimension Class

 

package com.halestormxv.worldALT;

import net.minecraftforge.common.DimensionManager;

public class Dimension {
/**
 * Regster dimension world providers with the dimension manager.
 */
public static void registerWorldProvider(){
	DimensionManager.registerProviderType(DimensionIDs.LIGHTFORESTDIMENSION, WorldProviderForest.class, true);
}

/**
 * Register dimensions.
 * @param register
 */
public static void registerDimensions(){
	DimensionManager.registerDimension(DimensionIDs.LIGHTFORESTDIMENSION, DimensionIDs.LIGHTFORESTDIMENSION);
}

}

 

 

DimensionID Class

 

package com.halestormxv.worldALT;

import com.halestormxv.Main.celConfiguration;

public class DimensionIDs {

public static int LIGHTFORESTDIMENSION = celConfiguration.celDim_ID;
}

 

 

WorldChunkManager for dimension

http://pastebin.com/nenHN90C

 

WorldProvider for dimension

http://pastebin.com/JkJLgYYr

 

Sky Rendere - Here is the SkyRenderer where it seems like the issue might be originating:

http://pastebin.com/mU2mkQ5Y

 

 

And here is a beautiful picture of my dimension so I can look at it on my screen and say "I know you are working for me"

http://i.imgur.com/VfUXatv.png

Posted

You're trying to access the

RenderGlobal#starGLCallList

field via reflection, but there's no field with that name in the obfuscated client; the field has an SRG name instead.

 

You need to try both the MCP and SRG names of a field/method when using reflection.

ReflectionHelper

accounts for this by accepting multiple names for a field/method and trying each one until it finds one that works.

 

You can find the SRG name of a field/method using the MCP mapping CSV files. The default 1.7.10 mappings can be found in ~/.gradle/caches/minecraft/net/minecraftforge/forge/<forge_version>/unpacked/conf, the default 1.8 mappings and any manually-specified mappings can be found in ~/.gradle/caches/minecraft/de/oceanlabs/mcp/<mappings_channel>/<mappings_version> (replace ~ with %USERPROFILE% on Windows). You can also download mappings from the MCPBot website.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Posted

Well thank you for that. I had absolutely no idea about that.

 

Am I able to add

 

minecraft {

    mappings = 'stable_12'

}

 

to my build.gradle and will that resolve the issue for all future builds? Or will I still need to manually switch around the names? Pardon my ignorance but I found no documentation on this when I first started modding and this is only my first mod.

 

EDIT: Apparently I can't do that as adding that to my gradle.build causes my project to fail to compile with a stupid amount of errors that don't even appear in eclipse. So i image that means I have to d it manually?

 

EDIT 2: And just to make sure I am understanding you correctly I would need to change: RenderGlobal#starGLCallList to RenderGlobal#field_72772_v because that is obfuscated ID of it according to the csv file correct? As well as change any references to starGLCallList (which only appears in the SkyRender class to field_72772_v)

Posted

You can update your mappings like that, but a couple of names of widely-used methods/fields have changed since 1.7.10's default mappings versions; so you need to fix your code to use the new names. Most deobfuscated builds of 1.7.10 mods are built for the older mappings, so they won't work properly with the new mappings unless you recompile them yourself. One way around this is to use manually recompiled deobfuscated builds of CodeChickenLib and CodeChickenCore and obfuscated builds of all other mods, which CodeChickenCore will deobfuscate at runtime.

 

If you reference a field/method directly in your code, ForgeGradle will automatically reobfuscate it for you when you build your mod. It's only when dealing with reflection that you need to use both names, since ForgeGradle can't reobfuscate reflection calls.

 

Instead of using this:

ReflectionHelper.getPrivateValue(RenderGlobal.class, renderGlobal, "starGLCallList") // Only MCP name

Use this:

ReflectionHelper.getPrivateValue(RenderGlobal.class, renderGlobal, "starGLCallList", "field_72772_v") // MCP and SRG names

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Posted

Okay that makes sense. Although I am probably too far into my mod to re-update all of my methods that have been rewritten. So I will probably have to just keep that in mind when doing future mods. Furthermore I am only using the ReflectionHelper.getPrivateValue in one spot in my entire mod so it is probably more efficient and timely to just change that piece of the code.

 

Now that that has been resolved I seem to be running into another issue. When trying to enter my dimension on the server I get a crash report: http://pastebin.com/T8gsRgHN

 

Now do note this crash report is from my mod, compiled, while installed in my modpack, which is why all those other mods are listed. However the issue seems to be with my dimension provider as it is clearly saying it is non-existent. I have once again utilized this in my test environment and it works fine as we can see by my screenshot. So I know the dimension seems to be working in the test environment.

 

However the big difference is that my server runs on kCauldron/Cauldron/MCPC+ (whatever you want to refer to it as).

 

Now I know my provider is being created as indicated in the worldProviderForest class specifically here:

http://pastebin.com/JkJLgYYr (WorldProvider ClassS)

	/** Get Provider for Dimension **/
public static WorldProvider getProviderForDimension(int id)
{
	return DimensionManager.createProviderFor(DimensionIDs.LIGHTFORESTDIMENSION);
}

 

This makes me wonder if this is an issue utilizing kCauldron? Or perhaps I am creating my provider wrong? I know it is something I have done because mods like Twilight Forest, Abyssal Craft, or any other mod that adds dimensions works fine on the server, so it clearly is something on my end.

Posted

Where are you calling

Dimension.registerWorldProvider

and

Dimension.registerDimensions

from?

 

Even if you used the stable_12 mappings, you'd still need to provide both the SRG and MCP names of any method/field you access via reflection. The only time you can use a single name is when the method/field has no MCP name (so it appears as

func_2234_b

/

field_1212_a

even in the development environment).

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Posted

Ahh thank you, I didn't realize that. The more you know the better lol.

 

As for where I am calling them I am calling them here: http://pastebin.com/XCTP31ej (in my main class)

 

However in going back over my code perhaps it is because I did this:

public WorldProviderForest()
{
	setDimension(DimensionIDs.LIGHTFORESTDIMENSION);
	this.getSaveFolder();
}

 

And I should be doing this:

  public WorldProviderForest()
  {
    setDimension(DimensionIDs.LIGHTFORESTDIMENSION);
    this.saveFolder = ("DIM" + DimensionIDs.LIGHTFORESTDIMENSION);
  }

  public String getSaveFolder()
  {
    return this.saveFolder;
  }

 

that is just a guess and would semi-explain what is going on, maybe?

 

EDIT: Even with the above updates the client still crashes, yet the server doesn't. Matter of fact the achv for entering that dimension still gets complete according to the server console.

 

EDIT 2: Wow total noob move - my server dimID was different from the client dimID. Now my question becomes, is there a way to force sync between the server ID and the client ID and if so how? Forgive my ignorance.

 

EDIT 3: Lastly when the mod has been compiled the custom texture for the sun and the moon in that dimension do not show, yet in the uncompiled testing state they show just fine. Specifically these are set in the SkyRenderer class: http://pastebin.com/mU2mkQ5Y  at lines 116 (sun) and 129 (moon) once the issue in Edit 2 and Edit 3 are resolved that will basically conclude my custom dimension problems. And thank you for the help you have given me thus far.

 

Posted

EDIT 2: Wow total noob move - my server dimID was different from the client dimID. Now my question becomes, is there a way to force sync between the server ID and the client ID and if so how? Forgive my ignorance.

 

There's no built-in config syncing mechanism, but you can send a packet from the server with its configuration options when a client joins and then apply these on the client. You'll need to unregister the previous provider/dimension IDs and register the new ones.

 

EDIT 3: Lastly when the mod has been compiled the custom texture for the sun and the moon in that dimension do not show, yet in the uncompiled testing state they show just fine. Specifically these are set in the SkyRenderer class: http://pastebin.com/mU2mkQ5Y  at lines 116 (sun) and 129 (moon) once the issue in Edit 2 and Edit 3 are resolved that will basically conclude my custom dimension problems. And thank you for the help you have given me thus far.

 

I'm not entirely sure what the problem is there. Do the

ResourceLocation

paths exactly match the paths on disk (including capitalisation)? Try removing the leading slash from the paths.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Posted

Just another tidbit: ReflectionHelper#getPrivateValue can take the field index instead of names, e.g.:

// field index is zero-indexed, so n-1
Object o = ReflectionHelper.getPrivateValue(RenderGlobal.class, renderGlobal, 13);
// you'll need to check type and cast to get the actual value

Granted, it's less readable, but sometimes you just want something quick and dirty, e.g. for initial testing (especially if there are only a handful of fields - RenderGlobal is not a good use case).

Posted

I am unfortunately not familiar enough with packets yet to figure out how to get that to work. But I will have to do some research. Perhaps you have some guidance I can look to? However thankfully my pack is distributed via FTB and Technic so my client and server files will always be in sync. But this is good practice to get into regardless.

 

And with respect to the moon and sun. You are correct. Looks like removing the trailing / was all it took lol. Had to recompile the whole mod because of it lol but now it seems to work just fine both on the server and on the client with no issue. Custom sun and moon are showing wonderfully. THANK YOU!

 

And thank you as well coolAlias. I will be happy to keep that in mind. Much appreciated.

Posted

I am unfortunately not familiar enough with packets yet to figure out how to get that to work. But I will have to do some research. Perhaps you have some guidance I can look to?

 

diesieben07 has a tutorial on the Simple Network Implementation here.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Posted

Thank You I will try and learn it. I can't imagine it would be too hard to check an int.

 

I will mark this topic as solved. Thank you again for all the help. Everything seems to be working wonderfully.

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.