Jump to content

[1.19.2] Rendersystem called from wrong thread


Ezio214

Recommended Posts

I can't figure out why I get the exception "java.lang.IllegalStateException: Rendersystem called from wrong thread"

Exception:

Spoiler
[11:10:48] [Server thread/ERROR] [minecraft/PacketUtils]: Failed to handle packet net.minecraft.network.protocol.game.ServerboundInteractPacket@7d415afd, suppressing error
java.lang.IllegalStateException: Rendersystem called from wrong thread
	at com.mojang.blaze3d.systems.RenderSystem.constructThreadException(RenderSystem.java:152) ~[forge-1.19.2-43.1.52_mapped_official_1.19.2-recomp.jar%23183!/:?] {re:classloading,pl:runtimedistcleaner:A}
	at com.mojang.blaze3d.systems.RenderSystem.assertOnRenderThreadOrInit(RenderSystem.java:135) ~[forge-1.19.2-43.1.52_mapped_official_1.19.2-recomp.jar%23183!/:?] {re:classloading,pl:runtimedistcleaner:A}
	at com.mojang.blaze3d.platform.GlStateManager._clear(GlStateManager.java:700) ~[forge-1.19.2-43.1.52_mapped_official_1.19.2-recomp.jar%23183!/:?] {re:classloading,pl:runtimedistcleaner:A}
	at com.mojang.blaze3d.systems.RenderSystem.clear(RenderSystem.java:378) ~[forge-1.19.2-43.1.52_mapped_official_1.19.2-recomp.jar%23183!/:?] {re:classloading,pl:runtimedistcleaner:A}
	at net.minecraft.client.Minecraft.runTick(Minecraft.java:1104) ~[forge-1.19.2-43.1.52_mapped_official_1.19.2-recomp.jar%23183!/:?] {re:classloading,pl:accesstransformer:B,pl:runtimedistcleaner:A}
	at net.minecraft.client.Minecraft.forceSetScreen(Minecraft.java:2123) ~[forge-1.19.2-43.1.52_mapped_official_1.19.2-recomp.jar%23183!/:?] {re:classloading,pl:accesstransformer:B,pl:runtimedistcleaner:A}
	at com.talesofcraft.common.entity.QuestGiverVillager.mobInteract(QuestGiverVillager.java:80) ~[%23188!/:?] {re:classloading}
	at net.minecraft.world.entity.Mob.interact(Mob.java:1061) ~[forge-1.19.2-43.1.52_mapped_official_1.19.2-recomp.jar%23183!/:?] {re:classloading,pl:accesstransformer:B}
	at net.minecraft.world.entity.player.Player.interactOn(Player.java:996) ~[forge-1.19.2-43.1.52_mapped_official_1.19.2-recomp.jar%23183!/:?] {re:classloading,pl:accesstransformer:B}
	at net.minecraft.server.network.ServerGamePacketListenerImpl$1.performInteraction(ServerGamePacketListenerImpl.java:1550) ~[forge-1.19.2-43.1.52_mapped_official_1.19.2-recomp.jar%23183!/:?] {re:classloading}
	at net.minecraft.server.network.ServerGamePacketListenerImpl$1.onInteraction(ServerGamePacketListenerImpl.java:1561) ~[forge-1.19.2-43.1.52_mapped_official_1.19.2-recomp.jar%23183!/:?] {re:classloading}
	at net.minecraft.network.protocol.game.ServerboundInteractPacket$InteractionAction.dispatch(ServerboundInteractPacket.java:124) ~[forge-1.19.2-43.1.52_mapped_official_1.19.2-recomp.jar%23183!/:?] {re:classloading}
	at net.minecraft.network.protocol.game.ServerboundInteractPacket.dispatch(ServerboundInteractPacket.java:75) ~[forge-1.19.2-43.1.52_mapped_official_1.19.2-recomp.jar%23183!/:?] {re:classloading}
	at net.minecraft.server.network.ServerGamePacketListenerImpl.handleInteract(ServerGamePacketListenerImpl.java:1546) ~[forge-1.19.2-43.1.52_mapped_official_1.19.2-recomp.jar%23183!/:?] {re:classloading}
	at net.minecraft.network.protocol.game.ServerboundInteractPacket.handle(ServerboundInteractPacket.java:62) ~[forge-1.19.2-43.1.52_mapped_official_1.19.2-recomp.jar%23183!/:?] {re:classloading}
	at net.minecraft.network.protocol.game.ServerboundInteractPacket.handle(ServerboundInteractPacket.java:12) ~[forge-1.19.2-43.1.52_mapped_official_1.19.2-recomp.jar%23183!/:?] {re:classloading}
	at net.minecraft.network.protocol.PacketUtils.lambda$ensureRunningOnSameThread$0(PacketUtils.java:22) ~[forge-1.19.2-43.1.52_mapped_official_1.19.2-recomp.jar%23183!/:?] {re:classloading}
	at net.minecraft.server.TickTask.run(TickTask.java:17) ~[forge-1.19.2-43.1.52_mapped_official_1.19.2-recomp.jar%23183!/:?] {re:classloading}
	at net.minecraft.util.thread.BlockableEventLoop.doRunTask(BlockableEventLoop.java:143) ~[forge-1.19.2-43.1.52_mapped_official_1.19.2-recomp.jar%23183!/:?] {re:classloading,pl:accesstransformer:B}
	at net.minecraft.util.thread.ReentrantBlockableEventLoop.doRunTask(ReentrantBlockableEventLoop.java:22) ~[forge-1.19.2-43.1.52_mapped_official_1.19.2-recomp.jar%23183!/:?] {re:classloading}
	at net.minecraft.server.MinecraftServer.doRunTask(MinecraftServer.java:763) ~[forge-1.19.2-43.1.52_mapped_official_1.19.2-recomp.jar%23183!/:?] {re:classloading,pl:accesstransformer:B}
	at net.minecraft.server.MinecraftServer.doRunTask(MinecraftServer.java:157) ~[forge-1.19.2-43.1.52_mapped_official_1.19.2-recomp.jar%23183!/:?] {re:classloading,pl:accesstransformer:B}
	at net.minecraft.util.thread.BlockableEventLoop.pollTask(BlockableEventLoop.java:116) ~[forge-1.19.2-43.1.52_mapped_official_1.19.2-recomp.jar%23183!/:?] {re:classloading,pl:accesstransformer:B}
	at net.minecraft.server.MinecraftServer.pollTaskInternal(MinecraftServer.java:746) ~[forge-1.19.2-43.1.52_mapped_official_1.19.2-recomp.jar%23183!/:?] {re:classloading,pl:accesstransformer:B}
	at net.minecraft.server.MinecraftServer.pollTask(MinecraftServer.java:740) ~[forge-1.19.2-43.1.52_mapped_official_1.19.2-recomp.jar%23183!/:?] {re:classloading,pl:accesstransformer:B}
	at net.minecraft.util.thread.BlockableEventLoop.managedBlock(BlockableEventLoop.java:126) ~[forge-1.19.2-43.1.52_mapped_official_1.19.2-recomp.jar%23183!/:?] {re:classloading,pl:accesstransformer:B}
	at net.minecraft.server.MinecraftServer.waitUntilNextTick(MinecraftServer.java:726) ~[forge-1.19.2-43.1.52_mapped_official_1.19.2-recomp.jar%23183!/:?] {re:classloading,pl:accesstransformer:B}
	at net.minecraft.server.MinecraftServer.runServer(MinecraftServer.java:658) ~[forge-1.19.2-43.1.52_mapped_official_1.19.2-recomp.jar%23183!/:?] {re:classloading,pl:accesstransformer:B}
	at net.minecraft.server.MinecraftServer.lambda$spin$2(MinecraftServer.java:244) ~[forge-1.19.2-43.1.52_mapped_official_1.19.2-recomp.jar%23183!/:?] {re:classloading,pl:accesstransformer:B}
	at java.lang.Thread.run(Thread.java:833) [?:?] {}

 

 

Custom Screen:

Spoiler
@OnlyIn(Dist.CLIENT)
public class QuestScreen extends Screen {
	private String name;
	private String[] descriptionLines;
	private Entity questGiver;

	public QuestScreen(String name, Entity questGiver) {
		super(Component.translatable("quest.tutorialmod." + name).withStyle(ChatFormatting.GOLD));
		this.name = "quest.tutorialmod." + name;
		this.descriptionLines = Component.translatable(this.name + ".description").getString().split("\n");
		this.questGiver = questGiver;
	}

	@Override
	protected void init() {
		addRenderableWidget(new Button(this.width / 2 - 100, this.height - 30, 100, 20, Component.literal("Accept"), this::onAccept));
		addRenderableWidget(new Button(this.width / 2 + 10, this.height - 30, 100, 20, Component.literal("Decline"), (button) -> { closeScreen(); }));
	}
	
	public void render(PoseStack poseStack, int p_96693_, int p_96694_, float p_96695_) {
		this.renderBackground(poseStack);
		drawCenteredString(poseStack, this.font, this.title, this.width / 2, 20, 16777215); // title
		// load descriptionText
		int posY = 40;
		for (int i = 0; i < this.descriptionLines.length; i++) {
			drawString(poseStack, this.font, Component.literal(this.descriptionLines[i]).withStyle(ChatFormatting.WHITE), this.width / 2 - 100, posY, 16777215);
			posY += 10;
		}
		super.render(poseStack, p_96693_, p_96694_, p_96695_);
	}

	private void onAccept(Button button) {
		closeScreen();
		// add quest to player
	}
	
	public void closeScreen() {
		if(this.questGiver instanceof QuestGiverVillager) {
			((QuestGiverVillager) this.questGiver).closeQuestScreen();
			this.onClose();
		}
	}
	
	public void show() {
		Minecraft.getInstance().setScreen(this);
	}

	@Override
	public boolean isPauseScreen() {
		return false;
	}
}

 

 

Custom Entity

Spoiler
public class QuestGiverVillager extends Villager implements IAnimatable {
	private AnimationFactory factory = GeckoLibUtil.createFactory(this);
	private EntityDimensions dimensions = new EntityDimensions(1.0f, 2.0f, true); // dimensions for hitbox
	private boolean isTalking = false;
	private QuestScreen questScreen;

	public QuestGiverVillager(EntityType<? extends Villager> type, Level level) {
		super(type, level);
		this.setCustomName(Component.literal("Malthor").withStyle(ChatFormatting.BLUE));
		this.setCustomNameVisible(true);
		this.questScreen = new QuestScreen("a_long_forgotten_tale", this);
	}
	
	public static AttributeSupplier setAttributes() {
		return Villager.createAttributes()
				.add(Attributes.MAX_HEALTH, 20.0D)
				.add(Attributes.FOLLOW_RANGE, 50.0D).build();
	}
	
	private <E extends IAnimatable> PlayState predicate(AnimationEvent<E> event) {
		if(event.isMoving()) {
			event.getController().setAnimation(new AnimationBuilder().addAnimation("walk"));
			return PlayState.CONTINUE;
		}
		
		event.getController().setAnimation(new AnimationBuilder().addAnimation("idle"));
		return PlayState.CONTINUE;
	}


	@Override
	public void registerControllers(AnimationData data) {
		data.addAnimationController(new AnimationController<QuestGiverVillager>(this, "controller", 0, this::predicate));
	}

	@Override
	public AnimationFactory getFactory() {
		return factory;
	}
	
	@Override
	public EntityDimensions getDimensions(Pose p_21047_) {
		// return new dimensions (width, length, fixed) for hitbox
		return p_21047_ == Pose.SLEEPING ? SLEEPING_DIMENSIONS : dimensions;
	}
	
	@Override
	public InteractionResult mobInteract(Player player, InteractionHand interactionHand) {
		// when isTalking == false AND isSleeping == false AND "shift"-key isn't pushed then show QuestScreen
	    if(!this.isTalking && !this.isSleeping() && !player.isSecondaryUseActive()) {
	    	if(interactionHand == InteractionHand.MAIN_HAND) {
	    		// successful talking with Entity (QuestGiverVillager)
	    		this.isTalking = true;
	    	   	this.questScreen.show();
		        return InteractionResult.sidedSuccess(this.level.isClientSide);
	    	} else {
	    		// unsuccessful talking with Entity (QuestGiverVillager)
	    		return InteractionResult.PASS;
	    	}
	    } else {
    		// unsuccessful talking with Entity (QuestGiverVillager)
	        return InteractionResult.PASS;
	    }
	}
	
	public void closeQuestScreen() {
		this.isTalking = false;
	}
}

 

 

When I show the Custom Screen (QuestScreen) for the first time it's all perfect without any exception or error. Just when I close it by clicking a button or pressing ESC and then right click my QuestGiverVillager again the problem occours.

Edited by Ezio214
forgot title
Link to comment
Share on other sites

  • Ezio214 changed the title to [1.19.2] Rendersystem called from wrong thread

You are calling setScreen() on the server thread. mobInteract() is called on both the client and server.

https://forge.gemwire.uk/wiki/Sides

You shouldn't even be referencing client classes directly, like your QuestScreen, in common classes like an Entity that exists on dedicated servers.

The vanilla villager's mobInteract() uses Player.openMenu() which opens a container menu. i.e. a screen that is managed on the server with a "proxy" on the client.

In particular MerchantMenu with its gui MerchantScreen.

Boilerplate:

If you don't post your logs/debug.log we can't help you. For curseforge you need to enable the forge debug.log in its minecraft settings. You should also post your crash report if you have one.

If there is no error in the log file and you don't have a crash report then post the launcher_log.txt from the minecraft folder. Again for curseforge this will be in your curseforge/minecraft/Install

Large files should be posted to a file sharing site like https://gist.github.com  You should also read the support forum sticky post.

Link to comment
Share on other sites

If you don't want to use a container menu, you will need to send a custom network packet to the client that tells it to the open the screen.

I don't know of any vanilla code that does this?

You normally want the linkage between client and server that the container menu provides for making sure state is updated on the server.

Boilerplate:

If you don't post your logs/debug.log we can't help you. For curseforge you need to enable the forge debug.log in its minecraft settings. You should also post your crash report if you have one.

If there is no error in the log file and you don't have a crash report then post the launcher_log.txt from the minecraft folder. Again for curseforge this will be in your curseforge/minecraft/Install

Large files should be posted to a file sharing site like https://gist.github.com  You should also read the support forum sticky post.

Link to comment
Share on other sites

But why dont I get the exception when it opens the first time? Why is it only when it shows the second time?

Also I wouldn't like to rewrite it to a new container menu, because I don't need the players inventory. I just want to show some text and give the player to press the accept or decline.

Since any vanilla code does not send a network packet to the client I think I shouldn't either.

Isn't there any other way I can show a screen to the player when he interacts with an entity?

Link to comment
Share on other sites

If there is no data or processing relevant on the server, you can check the side.

You basically let the client decide to show the screen with no veto by the server.

You still shouldn't have client classes directly in your entity.

 

But I don't think that is what you want? You have an "isTalking" field which doesn't look to implemented properly no synch server <-> client

I am guessing your intention is that the villager can only talk to one player at once? As it stands, that is kind of true on the server, but not on the client.

The client has no idea if the villager is talking to other players only if the local player is.

And the server has no idea when players stop talking to villagers.

Edited by warjort

Boilerplate:

If you don't post your logs/debug.log we can't help you. For curseforge you need to enable the forge debug.log in its minecraft settings. You should also post your crash report if you have one.

If there is no error in the log file and you don't have a crash report then post the launcher_log.txt from the minecraft folder. Again for curseforge this will be in your curseforge/minecraft/Install

Large files should be posted to a file sharing site like https://gist.github.com  You should also read the support forum sticky post.

Link to comment
Share on other sites

Yep you are right. There is no synch between server <-> client with my variable isTalking, which indeed was for my intention, that only one player can talk to the villager at a time. I removed it completly since I already had in mind to change it because it doesn't make any sense for my mod. With that said, thank you again !

Link to comment
Share on other sites

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



×
×
  • Create New...

Important Information

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