Jump to content
Search In
  • More options...
Find results that contain...
Find results in...

[SOLVED][1.15.2] Updating world space rendering from 1.12 to 1.15


xChris6041x
 Share

Recommended Posts

Like it says in the title I am attempting to update my old mod which can render cubes of any position, rotation, and scale in world space to the new rendering engine in 1.15 with little success. I got it to start rendering the cubes by using the MatrixStack but it only renders them what appears to be screen space. I've also converted all of my GlStateManager calls to RenderSystem calls. Below is some of the code from the project which deals with cube rendering.

 

Render Entry

@SubscribeEvent
public static void onWorldRender(RenderWorldLastEvent event) {
	// Grab Minecraft instance and check if player exists (in world).
	Minecraft mc = Minecraft.getInstance();
	ClientPlayerEntity player = mc.player;
	if(player == null) return;
	
	CubeBatch batch = new CubeBatch();
	batch.begin(event.getMatrixStack(), mc.gameRenderer.getActiveRenderInfo().getProjectedView());
	for(ICubeScene scene : scenes) {
		if(!scene.isVisible()) continue;
		scene.render(batch, player, event.getPartialTicks());
	}
	batch.end();
}

 

Cube Batch

public class CubeBatch {
	private List<Cube> buffer;
	private Vec3d origin;
	private MatrixStack matrixStack;
	
	/**
	 * @return the current origin.
	 */
	public Vec3d getOrigin() {
		return origin;
	}
	/**
	 * @return the current matrix stack.
	 */
	public MatrixStack getMatrixStack() {
		return matrixStack;
	}
	
	/**
	 * Starts a CubeBatch instruction instance.
	 * @param matrixStack - 
	 * @param origin - The origin for the CubeRenderer.
	 */
	public void begin(MatrixStack matrixStack, Vec3d origin) {
		this.matrixStack = matrixStack;
		this.origin = origin;
		this.buffer = new ArrayList<Cube>();
	}
	/**
	 * Flushes the Cube Batch to the CubeRenderer.
	 */
	public void flush() {
		CuRender.begin(matrixStack, origin);
		for(Cube cube : buffer) {
			CuRender.cube(cube);
		}
		CuRender.end();
		buffer.clear();
	}
	/**
	 * Stops and flushes the CubeBatch.
	 */
	public void end() {
		flush();
		buffer = null;
		origin = null;
	}
	
	/**
	 * Renders this cube to the world when flushed.
	 * @param cube
	 */
	public void draw(Cube cube) {
		if(!cube.isVisible()) return;
		buffer.add(cube.clone());
	}
	
	/**
	 * Renders a blend of the two cubes to the world when flushed.
	 * @param cube1
	 * @param cube2
	 * @param blend - A number between 0 and 1 (0 - Only Cube1, 1 - Only Cube2)
	 */
	public void blend(Cube cube1, Cube cube2, float blend) {
		if(blend < 0) blend = 0;
		else if(blend > 1) blend = 1;
		
		Cube c1 = cube1.clone();
		Cube c2 = cube2.clone();
		c1.scaleOpacity(1 - blend);
		c2.scaleOpacity(blend);
		
		buffer.add(c1);
		buffer.add(c2);
	}
}

 

Rendering Process

public final class CuRender {
	private static boolean rendering = false;
	private static MatrixStack matrixStack;
	
	/**
	 * Sets up the OpenGL environment for rendering in world space.
	 * @param origin - Origin of the camera (typically player's eye position).
	 */
	public static void begin(MatrixStack matrixStack, Vec3d origin) {
		if(rendering) throw new IllegalStateException("Cannot begin while rendering.");
		rendering = true;
		CuRender.matrixStack = matrixStack;
		
		matrixStack.push();
		matrixStack.translate(0.5 - origin.x, 0.5 - origin.y, 0.5 - origin.z);
		RenderSystem.disableDepthTest();
		RenderSystem.disableTexture();
		RenderSystem.disableLighting();
		RenderSystem.enableBlend();
		GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
	}
	/**
	 * Returns the OpenGL environment back to normal.
	 */
	public static void end() {
		if(!rendering) return;
		
		RenderSystem.disableBlend();
		RenderSystem.enableLighting();
		RenderSystem.enableTexture();
		RenderSystem.enableDepthTest();
		matrixStack.pop();
		
		rendering = false;
	}
	
	/**
	 * Renders the cube in world space.
	 * @param cube
	 */
	public static void cube(Cube cube) {
		matrixStack.push();
		// Position
		matrixStack.translate(-cube.getX(), -cube.getY(), -cube.getZ());
		// Rotate
//		GlStateManager.translated(cube.getOriginX() / 2, cube.getOriginY() / 2, cube.getOriginZ() / 2);
//		GlStateManager.rotatef(-cube.getYaw(), 0, 1, 0);
//		GlStateManager.rotatef(cube.getPitch(), 1, 0, 0);
//		GlStateManager.scaled(cube.getScaleX(), cube.getScaleY(), cube.getScaleZ()); // Scale
//		GlStateManager.translated(-cube.getOriginX() / 2, -cube.getOriginY() / 2, -cube.getOriginZ() / 2);
		matrixStack.scale(0.5f, 0.5f, 0.5f); // Normalize
		
		if(cube.isWired()) {
			// Wire Cube
			renderEdges(cube.getWireColor(), null);
		}
		else if(cube.isSolid()) {
			// Solid Cube
			for(int i = 0; i < UnitCube.FACE_COUNT; i++) {
				Face face = UnitCube.FACES[i];
				quad(cube.getFaceColor(i), face.v1, face.v2, face.v3, face.v4);
			}
		}
		else {
			// Mixed Cube
			boolean[] removedEdge = new boolean[UnitCube.EDGE_COUNT];
			for(int i = 0; i < UnitCube.FACE_COUNT; i++) {
				if(!cube.isFaceSolid(i)) continue;
				
				Face face = UnitCube.FACES[i];
				quad(cube.getFaceColor(i), face.v1, face.v2, face.v3, face.v4);
				quad(cube.getFaceColor(i), face.v1, face.v4, face.v3, face.v2);
				
				for(Edge edge : face.edges) {
					int j = UnitCube.getEdgeIndex(edge);
					removedEdge[j] = true;
				}
			}
			renderEdges(cube.getWireColor(), removedEdge);
		}
		
		matrixStack.pop();
	}
	private static void renderEdges(Color4f color, boolean[] removedEdges) {
	    glColor4f(color);
		GL11.glBegin(GL11.GL_LINES);
		for(int i = 0; i < UnitCube.EDGE_COUNT; i++) {
			if(removedEdges != null && removedEdges[i]) continue;
			
			Edge edge = UnitCube.EDGES[i];
			glVertex3d(edge.v1);
			glVertex3d(edge.v2);
		}
		GL11.glEnd();
	}
	
	/**
	 * Renders a quad with the specified vertices. OpenGL must be in GL_QUADS mode to work.
	 * @param v1
	 * @param v2
	 * @param v3
	 * @param v4
	 */
	public static void quad(Color4f color, Vec3d v1, Vec3d v2, Vec3d v3, Vec3d v4) {
		glColor4f(color);
		GL11.glBegin(GL11.GL_QUADS);
	    glVertex3d(v1);
	    glVertex3d(v2);
	    glVertex3d(v3);
	    glVertex3d(v4);
		GL11.glEnd();
	}
	private static void glVertex3d(Vec3d v) {
		GL11.glVertex3d(v.x, v.y, v.z);
	}
	private static void glColor4f(Color4f c) {
		GL11.glColor4f(c.r, c.g, c.b, c.a);
	}
}

 

Sample Cube Scene

public class DebugScene extends CubeScene {
	public static final Cube CUBE_TEMPLATE = new Cube().wire().setColor(1f, 0f, 0f, 0.5f);
	
	@Override
	public void render(CubeBatch batch, ClientPlayerEntity player, float partialTicks) {
		World world = player.getEntityWorld();
		int px = (int) player.lastTickPosX;
		int pz = (int) player.lastTickPosZ;
		
		// Loop through all chunks in the chunk render distance.
		for(int x = px - 50; x <= px + 50; x++) {
			for(int z = pz - 50; z <= pz + 50; z++) {
				int maxY = world.getHeight(Type.WORLD_SURFACE, x, z);
				for(int y = 0; y <= maxY; y++) {
					BlockState state = world.getBlockState(new BlockPos(x, y, z));
					if(state.getBlock() instanceof OreBlock) {
						batch.draw(CUBE_TEMPLATE.clone().setPosition(x, y, z));
					}
				}
			}
		}
	}
}

 

 

Any direct help or even resources to how the new rendering system works is greatly appreciated. If anymore information is needed please don't hesitate to ask.

Edited by xChris6041x
Solution was found.
Link to comment
Share on other sites

3 hours ago, desht said:

I'd recommend looking at McJty's tutorials here, especially parts 13 - 15 for 1.15.x rendering topics.

I checked out his tutorials, but I don't think they will work in my case. The cubes that I am rendering are not custom TileEntities as they need to be rendered in any possible position. Using the RenderWorldLastEvent#getMatrixStack doesn't seem to have a matrix stack I can manipulate to get what I want. I ended up finding a solution which works, but uses the now deprecated GlStateManager methods.

 

Render Entry

@SubscribeEvent
public static void onWorldRender(RenderWorldLastEvent event) {
	// Grab Minecraft instance and check if player exists (in world).
	Minecraft mc = Minecraft.getInstance();
	ClientPlayerEntity player = mc.player;
	if(player == null) return;
	
	ActiveRenderInfo info = mc.gameRenderer.getActiveRenderInfo();
	CubeBatch batch = new CubeBatch();
	batch.begin(info.getProjectedView(), info.getPitch(), info.getYaw());
	for(ICubeScene scene : scenes) {
		if(!scene.isVisible()) continue;
		scene.render(batch, player, event.getPartialTicks());
	}
	batch.end();
}

 

Rendering Process

@SuppressWarnings("deprecation")
public final class CuRender {
	private static boolean rendering = false;
	
	/**
	 * Sets up the OpenGL environment for rendering in world space.
	 * @param origin - Origin of the camera (typically player's eye position).
	 */
	public static void begin(Vec3d origin, Vec2f angle) {
		if(rendering) throw new IllegalStateException("Cannot begin while rendering.");
		rendering = true;
		
		GlStateManager.pushMatrix();
		GlStateManager.rotatef(angle.x, 1, 0, 0); // Fixes camera rotation.
		GlStateManager.rotatef(angle.y + 180, 0, 1, 0); // Fixes camera rotation.
		GlStateManager.translated(0.5 - origin.x, 0.5 - origin.y, 0.5 - origin.z);
		GlStateManager.disableDepthTest();
		GlStateManager.disableTexture();
		GlStateManager.disableLighting();
		GlStateManager.enableBlend();
		GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
	}
	/**
	 * Returns the OpenGL environment back to normal.
	 */
	public static void end() {
		if(!rendering) return;
		
		GlStateManager.disableBlend();
		GlStateManager.enableLighting();
		GlStateManager.enableTexture();
		GlStateManager.enableDepthTest();
		GlStateManager.popMatrix();
		
		rendering = false;
	}
	
	/**
	 * Renders the cube in world space.
	 * @param cube
	 */
	public static void cube(Cube cube) {
		GlStateManager.pushMatrix();
		// Position
		GlStateManager.translated(cube.getX(), cube.getY(), cube.getZ());
		// Rotate
		GlStateManager.translated(cube.getOriginX() / 2, cube.getOriginY() / 2, cube.getOriginZ() / 2);
		GlStateManager.rotatef(-cube.getYaw(), 0, 1, 0);
		GlStateManager.rotatef(cube.getPitch(), 1, 0, 0);
		GlStateManager.scaled(cube.getScaleX(), cube.getScaleY(), cube.getScaleZ()); // Scale
		GlStateManager.translated(-cube.getOriginX() / 2, -cube.getOriginY() / 2, -cube.getOriginZ() / 2);
		GlStateManager.scaled(0.5, 0.5, 0.5); // Normalize
		
		if(cube.isWired()) {
			// Wire Cube
			renderEdges(cube.getWireColor(), null);
		}
		else if(cube.isSolid()) {
			// Solid Cube
			for(int i = 0; i < UnitCube.FACE_COUNT; i++) {
				Face face = UnitCube.FACES[i];
				quad(cube.getFaceColor(i), face.v1, face.v2, face.v3, face.v4);
			}
		}
		else {
			// Mixed Cube
			boolean[] removedEdge = new boolean[UnitCube.EDGE_COUNT];
			for(int i = 0; i < UnitCube.FACE_COUNT; i++) {
				if(!cube.isFaceSolid(i)) continue;
				
				Face face = UnitCube.FACES[i];
				quad(cube.getFaceColor(i), face.v1, face.v2, face.v3, face.v4);
				quad(cube.getFaceColor(i), face.v1, face.v4, face.v3, face.v2);
				
				for(Edge edge : face.edges) {
					int j = UnitCube.getEdgeIndex(edge);
					removedEdge[j] = true;
				}
			}
			renderEdges(cube.getWireColor(), removedEdge);
		}
		
		GlStateManager.popMatrix();
	}
	private static void renderEdges(Color4f color, boolean[] removedEdges) {
	    glColor4f(color);
		GL11.glBegin(GL11.GL_LINES);
		for(int i = 0; i < UnitCube.EDGE_COUNT; i++) {
			if(removedEdges != null && removedEdges[i]) continue;
			
			Edge edge = UnitCube.EDGES[i];
			glVertex3d(edge.v1);
			glVertex3d(edge.v2);
		}
		GL11.glEnd();
	}
	
	/**
	 * Renders a quad with the specified vertices. OpenGL must be in GL_QUADS mode to work.
	 * @param v1
	 * @param v2
	 * @param v3
	 * @param v4
	 */
	public static void quad(Color4f color, Vec3d v1, Vec3d v2, Vec3d v3, Vec3d v4) {
		glColor4f(color);
		GL11.glBegin(GL11.GL_QUADS);
	    glVertex3d(v1);
	    glVertex3d(v2);
	    glVertex3d(v3);
	    glVertex3d(v4);
		GL11.glEnd();
	}
	private static void glVertex3d(Vec3d v) {
		GL11.glVertex3d(v.x, v.y, v.z);
	}
	private static void glColor4f(Color4f c) {
		GL11.glColor4f(c.r, c.g, c.b, c.a);
	}
}

 

This code is mostly 1.12 code, but 1.15 didn't maintain the player head rotation in the matrix. Passing in the pitch and yaw I was able to rotate the matrix to have the illusion of world space rendering.

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.

Guest
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.

 Share



  • Recently Browsing

    No registered users viewing this page.

  • Posts

    • Hello everyone, like the title suggest, I've a problem running dedicated server for my mod "emomod, Emotion's Mod", I understand that the problem is caused by my containers because of invalid dist and I understand the concept of side but I really struggle to fix it, for the lore I'm developing this mod since 5 or 6 years from now so it's a huge one, I have like 281 block textures, 167 item textures, biomes, game mechanics, dimensions, entities etc.. I love it but I kept it private for the moment (I may send it public soon) and I use to get back on it sometimes when I want to update the version (I also rewrite everything once because I suck to do so for the version 1.8 to 1.12 / 1.14) or add stuff for example, here is the log of the server :   I'm registering Biome, Block, ContainerType, TileEntityType etc.. In differents class that I'm calling in my main one called "MainRegistry" with the method init().   Firstly, the classe where I'm registering ContainerType is modestly named "ContainerTypeRegistry" (this is my convention), I've currently three type of container, "CRAFTER" wich is a complex automatic crafting machine, "BAG" is a bag item storing stuff using "ItemStackHandler" and finally Nightstand is a basic chest with less slots (4) using different color GUIs based on the wood used to craft, here is the code :   @Mod.EventBusSubscriber(modid = MainRegistry.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD) public class ContainerTypeRegistry { private static final List<ContainerType<?>> containerTypeList = new ArrayList<ContainerType<?>>(); public static final ContainerType<CrafterContainer> CRAFTER = IForgeContainerType.create((windowId, inv, data) -> { BlockPos pos = data.readBlockPos(); return new CrafterContainer(windowId, MainRegistry.proxy.getClientWorld(), pos, MainRegistry.proxy.getClientPlayer()); }); public static final ContainerType<BagContainer> BAG = IForgeContainerType.create((windowId, inv, data) -> { return new BagContainer(windowId, inv); }); public static final ContainerType<NightstandContainer> NIGHTSTAND = IForgeContainerType.create((windowId, inv, data) -> { BlockPos pos = data.readBlockPos(); return new NightstandContainer(windowId, inv.player.getEntityWorld(), pos, inv); }); public static void init() { addContainerType(CRAFTER, "crafter"); addContainerType(BAG, "bag"); addContainerType(NIGHTSTAND, "nightstand"); } public static void addContainerType(ContainerType<?> tet, String name) { containerTypeList.add(tet.setRegistryName(name)); } @SubscribeEvent public static void registerContainerType(final RegistryEvent.Register<ContainerType<?>> e) { for (ContainerType<?> tet : containerTypeList) { e.getRegistry().register(tet); } } } Secondly, I'm using the same technique to register TileEntityType and I'm calling all those init methods but also ScreenManager.registerFactory() like I said in the main class just here :   @Mod(MainRegistry.MOD_ID) public class MainRegistry { public static final String MOD_ID = "emomod"; public static final Logger LOGGER = LogManager.getLogger(MOD_ID); public static IProxy proxy = DistExecutor.runForDist(() -> () -> new ClientProxy(), () -> () -> new ServerProxy()); public static MainRegistry instance; public static WorldType PARCEL_TYPE = new ParcelWorldType(); public static WorldType DREAM_TYPE = new DreamWorldType(); public MainRegistry() { ItemRegistry.init(); BlockRegistry.init(); TileEntityTypeRegistry.init(); EntityTypeRegistry.init(); SurfaceBuilderRegistry.init(); PlacementRegistry.init(); FeatureRegistry.init(); FluidRegistry.init(); ContainerTypeRegistry.init(); DispenserBlock.registerDispenseBehavior(PotionUtils.addPotionToItemStack(new ItemStack(Items.POTION), Potions.WATER).getItem(), new IInteractBehavior()); DispenserBlock.registerDispenseBehavior(Items.WHEAT_SEEDS, new IPlaceBehavior(Blocks.WHEAT, Blocks.FARMLAND)); DispenserBlock.registerDispenseBehavior(Items.PUMPKIN_SEEDS, new IPlaceBehavior(Blocks.PUMPKIN_STEM, Blocks.FARMLAND)); DispenserBlock.registerDispenseBehavior(Items.MELON_SEEDS, new IPlaceBehavior(Blocks.MELON_STEM, Blocks.FARMLAND)); DispenserBlock.registerDispenseBehavior(Items.BEETROOT_SEEDS, new IPlaceBehavior(Blocks.BEETROOTS, Blocks.FARMLAND)); DispenserBlock.registerDispenseBehavior(Items.CARROT, new IPlaceBehavior(Blocks.CARROTS, Blocks.FARMLAND)); DispenserBlock.registerDispenseBehavior(Items.POTATO, new IPlaceBehavior(Blocks.POTATOES, Blocks.FARMLAND)); DispenserBlock.registerDispenseBehavior(Items.OAK_SAPLING, new IPlaceBehavior(Blocks.OAK_SAPLING, Blocks.GRASS_BLOCK, Blocks.DIRT, Blocks.COARSE_DIRT, Blocks.PODZOL)); DispenserBlock.registerDispenseBehavior(Items.ACACIA_SAPLING, new IPlaceBehavior(Blocks.ACACIA_SAPLING, Blocks.GRASS_BLOCK, Blocks.DIRT, Blocks.COARSE_DIRT, Blocks.PODZOL)); DispenserBlock.registerDispenseBehavior(Items.BIRCH_SAPLING, new IPlaceBehavior(Blocks.BIRCH_SAPLING, Blocks.GRASS_BLOCK, Blocks.DIRT, Blocks.COARSE_DIRT, Blocks.PODZOL)); DispenserBlock.registerDispenseBehavior(Items.DARK_OAK_SAPLING, new IPlaceBehavior(Blocks.DARK_OAK_SAPLING, Blocks.GRASS_BLOCK, Blocks.DIRT, Blocks.COARSE_DIRT, Blocks.PODZOL)); DispenserBlock.registerDispenseBehavior(Items.JUNGLE_SAPLING, new IPlaceBehavior(Blocks.JUNGLE_SAPLING, Blocks.GRASS_BLOCK, Blocks.DIRT, Blocks.COARSE_DIRT, Blocks.PODZOL)); DispenserBlock.registerDispenseBehavior(Items.SPRUCE_SAPLING, new IPlaceBehavior(Blocks.SPRUCE_SAPLING, Blocks.GRASS_BLOCK, Blocks.DIRT, Blocks.COARSE_DIRT, Blocks.PODZOL)); DispenserBlock.registerDispenseBehavior(Items.BAMBOO, new IPlaceBehavior(Blocks.BAMBOO_SAPLING, Blocks.GRASS_BLOCK, Blocks.DIRT, Blocks.COARSE_DIRT, Blocks.PODZOL)); DispenserBlock.registerDispenseBehavior(Items.NETHER_WART, new IPlaceBehavior(Blocks.NETHER_WART, Blocks.SOUL_SAND, Blocks.DIRT, Blocks.COARSE_DIRT, Blocks.PODZOL)); FMLJavaModLoadingContext.get().getModEventBus().addListener(this::setup); FMLJavaModLoadingContext.get().getModEventBus().addListener(this::clientSetup); FMLJavaModLoadingContext.get().getModEventBus().addListener(this::serverSetup); MinecraftForge.EVENT_BUS.register(new EmotionOverlayEvent()); MinecraftForge.EVENT_BUS.register(new EmotionLivingEvent()); ClientRegistry.bindTileEntitySpecialRenderer(TileEntitySign.class, new TileEntitySignRenderer()); ClientRegistry.bindTileEntitySpecialRenderer(TileEntityCrafter.class, new TileEntityCrafterRenderer()); ClientRegistry.bindTileEntitySpecialRenderer(TileEntityPot.class, new TileEntityPotRenderer()); LootConditionManager.registerCondition(new HarvestLevelCondition.Serializer()); EmomodPacketHandler.registerMessages(); } private void setup(final FMLCommonSetupEvent e) { proxy.init(); RenderingRegistry.registerEntityRenderingHandler(OrbSpellEntity.class, render -> new SpriteRenderer<OrbSpellEntity>(render, Minecraft.getInstance().getItemRenderer())); RenderingRegistry.registerEntityRenderingHandler(EntityButterfly.class, render -> new RendererButterfly(render)); RenderingRegistry.registerEntityRenderingHandler(EntityBeetle.class, render -> new RendererBasic<EntityBeetle, ModelBeetle>(render, new ModelBeetle(), 0.175f, new ResourceLocation(MainRegistry.MOD_ID, "textures/entity/beetle.png"))); RenderingRegistry.registerEntityRenderingHandler(EntityLightningBug.class, render -> new RendererBasic<EntityLightningBug, ModelLightningBug>(render, new ModelLightningBug(), 0.0f, new ResourceLocation(MainRegistry.MOD_ID, "textures/entity/lightning_bug.png"))); RenderingRegistry.registerEntityRenderingHandler(EntityBoat.class, RendererBoat::new); RenderingRegistry.registerEntityRenderingHandler(EntityChubby.class, render -> new RendererBasic<EntityChubby, ModelChubby>(render, new ModelChubby(), .2f, new ResourceLocation(MainRegistry.MOD_ID, "textures/entity/chubby.png"))); RenderingRegistry.registerEntityRenderingHandler(EntityMouse.class, render -> new RendererMouse(render, new ModelMouse(), 0.1f)); RenderingRegistry.registerEntityRenderingHandler(EntityOrchardSpider.class, render -> new RendererOrchardSpider<EntityOrchardSpider>(render)); EmoOreGeneration.setupOreGeneration(); // RecipeRegistry.init(); } private void clientSetup(final FMLClientSetupEvent e) { EmoStaff staff = (EmoStaff) ItemRegistry.PURPURA_STAFF; Minecraft.getInstance().getItemColors().register((item, tintIndex) -> { return staff.getColor(new ItemStack(staff), tintIndex); }, staff); Minecraft.getInstance().getItemColors().register((item, tintIndex) -> { return GrassColors.get(0.5D, 1.0D); }, BlockRegistry.FLOWER_TALLGRASS); Minecraft.getInstance().getItemColors().register((item, tintIndex) -> { BlockState blockstate = ((BlockItem) item.getItem()).getBlock().getDefaultState(); return Minecraft.getInstance().getBlockColors().getColor(blockstate, (IEnviromentBlockReader) null, (BlockPos) null, tintIndex); }, BlockRegistry.LEAVES_CHERRY, BlockRegistry.LEAVES_PEAR, BlockRegistry.LEAVES_ORANGE, BlockRegistry.LEAVES_ATLAS, BlockRegistry.LEAVES_PINE, BlockRegistry.LEAVES_COCO, BlockRegistry.LEAVES_DREAM); Minecraft.getInstance().getBlockColors().register((state, reader, pos, color) -> { return reader != null && pos != null ? BiomeColors.getGrassColor(reader, pos) : GrassColors.get(0.5D, 1.0D); }, BlockRegistry.FLOWER_TALLGRASS); Minecraft.getInstance().getBlockColors().register((state, reader, pos, color) -> { return reader != null && pos != null ? BiomeColors.getFoliageColor(reader, pos) : FoliageColors.getDefault(); }, BlockRegistry.LEAVES_PINE, BlockRegistry.LEAVES_COCO, BlockRegistry.LEAVES_DREAM); Minecraft.getInstance().getBlockColors().register((state, reader, pos, color) -> { return 0xac73af; }, BlockRegistry.LEAVES_CHERRY); Minecraft.getInstance().getBlockColors().register((state, reader, pos, color) -> { return 0x487748; }, BlockRegistry.LEAVES_PEAR); Minecraft.getInstance().getBlockColors().register((state, reader, pos, color) -> { return 0x45a14a; }, BlockRegistry.LEAVES_ORANGE); Minecraft.getInstance().getBlockColors().register((state, reader, pos, color) -> { return 0x4496c4; }, BlockRegistry.LEAVES_ATLAS); ScreenManager.<CrafterContainer, CrafterScreen>registerFactory(ContainerTypeRegistry.CRAFTER, (container, playerInventory, title) -> { return new CrafterScreen(container, playerInventory, title); }); ScreenManager.<BagContainer, BagScreen>registerFactory(ContainerTypeRegistry.BAG, (container, playerInventory, title) -> { return new BagScreen(container, playerInventory, title); }); ScreenManager.<NightstandContainer, NightstandScreen>registerFactory(ContainerTypeRegistry.NIGHTSTAND, (container, playerInventory, title) -> { return new NightstandScreen(container, playerInventory, title, container.getTileEntity().getColor()); }); } private void serverSetup(final FMLDedicatedServerSetupEvent e) { } } Finally for the specific class I'm only gonna send the Nightstand one in random way :   - Block class :   public class EmoNightstand extends Block { private static final DirectionProperty FACING = HorizontalBlock.HORIZONTAL_FACING; private static final VoxelShape NIGHTSTAND_SHAPE = Block.makeCuboidShape(1.0D, 0.0D, 1.0D, 15.0D, 15.0D, 15.0D); private float[] color; public EmoNightstand(Properties properties, float[] color) { super(properties); this.getDefaultState().with(FACING, Direction.NORTH); this.color = color; } @Override public VoxelShape getCollisionShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) { return NIGHTSTAND_SHAPE; } @Override public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) { return NIGHTSTAND_SHAPE; } @Override public boolean onBlockActivated(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand handIn, BlockRayTraceResult hit) { if (!worldIn.isRemote) { TileEntity tileEntity = worldIn.getTileEntity(pos); if (tileEntity instanceof INamedContainerProvider) { NetworkHooks.openGui((ServerPlayerEntity) player, (INamedContainerProvider) tileEntity, tileEntity.getPos()); } } return true; } public BlockState getStateForPlacement(BlockItemUseContext context) { return this.getDefaultState().with(FACING, context.getPlacementHorizontalFacing().getOpposite()); } protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder) { builder.add(FACING); } @Override public boolean hasTileEntity(BlockState state) { return true; } @Override public TileEntity createTileEntity(BlockState state, IBlockReader world) { return new TileEntityNightstand(this.color); } } - The ContainerScreen class :   public class NightstandScreen extends ContainerScreen<NightstandContainer> { private static final ResourceLocation NIGHTSTAND_GUI_SCREEN = new ResourceLocation(MainRegistry.MOD_ID, "textures/gui/container/nightstand.png"); private float[] color; public NightstandScreen(NightstandContainer screenContainer, PlayerInventory playerInventory, ITextComponent titleIn, float[] color) { super(screenContainer, playerInventory, titleIn); this.xSize = 176; this.ySize = 127; this.color = color; } protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { this.font.drawString(this.getTitle().getFormattedText(), 8, 4, 0); this.font.drawString(this.playerInventory.getDisplayName().getFormattedText(), 8.0F, (float) (this.ySize - 96 + 2), 0); } @Override protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY) { int xPos = (this.width - this.xSize) / 2; int yPos = (this.height - this.ySize) / 2; GlStateManager.color4f(1.0f, 1.0f, 1.0f, 1.0f); this.minecraft.getTextureManager().bindTexture(NIGHTSTAND_GUI_SCREEN); this.blit(xPos, yPos, 0, 0, this.xSize, this.ySize); GlStateManager.color4f(color[0] / 255, color[1] / 255, color[2] / 255, 1.0f); this.blit(xPos, yPos, 0, 0, this.xSize, this.ySize); GlStateManager.disableTexture(); GlStateManager.enableBlend(); GlStateManager.disableAlphaTest(); GlStateManager.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); GlStateManager.shadeModel(7425); Tessellator tessellator = Tessellator.getInstance(); BufferBuilder bufferbuilder = tessellator.getBuffer(); bufferbuilder.begin(7, DefaultVertexFormats.POSITION_COLOR); bufferbuilder.pos((double) xPos + this.xSize, (double) yPos, (double) this.blitOffset).color(0, 0, 0, 0).endVertex(); bufferbuilder.pos((double) xPos, (double) yPos, (double) this.blitOffset).color(0, 0, 0, 0).endVertex(); bufferbuilder.pos((double) xPos, (double) yPos + this.ySize, (double) this.blitOffset).color(0, 0, 0, 255 / 2).endVertex(); bufferbuilder.pos((double) xPos + this.xSize, (double) yPos + this.ySize, (double) this.blitOffset).color(0, 0, 0, 255 / 2).endVertex(); tessellator.draw(); GlStateManager.shadeModel(7424); GlStateManager.disableBlend(); GlStateManager.enableAlphaTest(); GlStateManager.enableTexture(); } } The Container class :   public class NightstandContainer extends Container { private TileEntity tileEntity; private int containerSlots = 0; public NightstandContainer(int id, World world, BlockPos pos, PlayerInventory playerInventory) { super(ContainerTypeRegistry.NIGHTSTAND, id); this.tileEntity = world.getTileEntity(pos); tileEntity.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY).ifPresent(h -> { containerSlots = h.getSlots(); for (int i = 0; i < h.getSlots(); i++) { addSlot(new SlotItemHandler(h, i, 44 + (i * 18) + (i > 1 ? 18 : 0), 14)); } }); for (int y = 0; y < 3; ++y) { for (int x = 0; x < 9; ++x) { this.addSlot(new Slot(playerInventory, x + y * 9 + 9, 8 + (x * 18), 45 + (y * 18))); } } for (int k = 0; k < 9; ++k) { this.addSlot(new Slot(playerInventory, k, 8 + k * 18, 103)); } } @Override public ItemStack transferStackInSlot(PlayerEntity playerIn, int index) { Slot slot = this.getSlot(index); if (!slot.canTakeStack(playerIn)) return slot.getStack(); if (!slot.getHasStack()) return ItemStack.EMPTY; ItemStack stack = slot.getStack(); ItemStack newStack = stack.copy(); if (index < containerSlots) { if (!this.mergeItemStack(stack, containerSlots, this.inventorySlots.size(), true)) return ItemStack.EMPTY; slot.onSlotChanged(); } else if (!this.mergeItemStack(stack, 0, containerSlots, false)) return ItemStack.EMPTY; if (stack.isEmpty()) slot.putStack(ItemStack.EMPTY); else slot.onSlotChanged(); return slot.onTake(playerIn, newStack); } @Override public boolean canInteractWith(PlayerEntity playerIn) { return this.isUsable(playerIn); } protected boolean isUsable(PlayerEntity playerIn) { return IWorldPosCallable.of(tileEntity.getWorld(), tileEntity.getPos()).applyOrElse((block, pos) -> { return !(block.getBlockState(pos).getBlock() instanceof EmoNightstand) ? false : playerIn.getDistanceSq((double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D) <= 64.0D; }, true); } @Nullable public TileEntityNightstand getTileEntity() { if (this.tileEntity instanceof TileEntityNightstand) return (TileEntityNightstand) this.tileEntity; else return null; } } The TileEntity class :   public class TileEntityNightstand extends TileEntity implements INamedContainerProvider { private LazyOptional<IItemHandler> handler = LazyOptional.of(this::createHandler); private float[] color = new float[] { 0.0f, 255.0f, 0.0f}; public TileEntityNightstand(float[] color) { this(); this.color = color; } public TileEntityNightstand() { super(TileEntityTypeRegistry.NIGHTSTAND); } @SuppressWarnings("unchecked") @Override public void read(CompoundNBT compound) { CompoundNBT inventory = compound.getCompound("Inventory"); handler.ifPresent(h -> ((INBTSerializable<CompoundNBT>) h).deserializeNBT(inventory)); super.read(compound); } @SuppressWarnings("unchecked") @Override public CompoundNBT write(CompoundNBT compound) { handler.ifPresent(h -> { CompoundNBT nbt = ((INBTSerializable<CompoundNBT>) h).serializeNBT(); compound.put("Inventory", nbt); }); return super.write(compound); } private IItemHandler createHandler() { return new ItemStackHandler(4) { @Override protected void onContentsChanged(int slot) { markDirty(); } }; } @Override public <T> LazyOptional<T> getCapability(Capability<T> cap, Direction side) { if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) return handler.cast(); return super.getCapability(cap, side); } @Override public ITextComponent getDisplayName() { return new TranslationTextComponent("container.emomod.nightstand"); } @Override public Container createMenu(int windowId, PlayerInventory playerInventory, PlayerEntity player) { return new NightstandContainer(windowId, this.getWorld(), this.getPos(), playerInventory); } public float[] getColor() { return this.color; } } And voilà, I think that everything is here and I will really appreciate some help, this mod is very important for me and I've put so many efforts in it, I've to update it soon to the latest version (I may also want some paid help for that if I can apply some sort of dev recrutment on this forum) and I will stop adding stuff but polish everything up to finally set it public. Thanks again for giving me some of your time, I can send the WIP version of the mod jar as demo when this will be fixed if some of you want it, and also if I find a way to protect my textures from being copied / reused or modified.
    • https://mcforge.readthedocs.io/en/latest/concepts/sides/#writing-one-sided-mods
    • What?! Just use RegisterCommandsEvent. FMLServerStartingEvent is not involved with registering commands at all.
    • Only ModelRegistryEvent is necessary. Call ModelLoader.addSpecialModel in there and the model will be baked as normal.
    • Really old Minecraft versions are no longer supported on this forum. Please update to a modern version of Minecraft to receive support.
  • Topics

  • Who's Online (See full list)

×
×
  • Create New...

Important Information

By using this site, you agree to our Privacy Policy.