Files
StructureLib/src/main/java/com/gtnewhorizon/structurelib/ClientProxy.java
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

660 lines
27 KiB
Java
Raw Normal View History

2022-08-08 17:40:12 +08:00
package com.gtnewhorizon.structurelib;
2022-08-24 12:22:02 +08:00
import static com.gtnewhorizon.structurelib.StructureLib.RANDOM;
2024-07-06 12:13:22 -07:00
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
2021-05-29 14:27:54 +08:00
import net.minecraft.client.gui.GuiNewChat;
import net.minecraft.client.particle.EntityFX;
import net.minecraft.client.renderer.Tessellator;
2022-08-25 16:07:42 +08:00
import net.minecraft.client.renderer.culling.Frustrum;
import net.minecraft.client.renderer.texture.TextureMap;
2022-08-25 16:07:42 +08:00
import net.minecraft.entity.Entity;
2021-05-29 14:27:54 +08:00
import net.minecraft.entity.player.EntityPlayer;
2022-08-08 17:40:12 +08:00
import net.minecraft.entity.player.EntityPlayerMP;
2022-08-23 12:29:59 +08:00
import net.minecraft.item.ItemStack;
2022-08-25 14:24:27 +08:00
import net.minecraft.profiler.Profiler;
2021-05-29 14:27:54 +08:00
import net.minecraft.util.ChatComponentText;
2022-09-02 15:45:13 +08:00
import net.minecraft.util.IChatComponent;
import net.minecraft.util.IIcon;
import net.minecraft.util.MathHelper;
import net.minecraft.util.Vec3;
import net.minecraft.world.World;
import net.minecraftforge.client.event.RenderWorldLastEvent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.util.ForgeDirection;
import net.minecraftforge.event.world.WorldEvent;
import org.lwjgl.opengl.GL11;
2024-07-15 17:52:57 -07:00
import com.gtnewhorizon.structurelib.client.nei.IMCForNEI;
import com.gtnewhorizon.structurelib.client.nei.InputHandler;
import com.gtnewhorizon.structurelib.client.renderer.RenderStructureGlobal;
import com.gtnewhorizon.structurelib.client.world.StructureWorld;
import com.gtnewhorizon.structurelib.entity.fx.WeightlessParticleFX;
2022-08-23 12:29:59 +08:00
import com.gtnewhorizon.structurelib.net.SetChannelDataMessage;
2024-07-15 17:52:57 -07:00
import codechicken.nei.guihook.GuiContainerManager;
import cpw.mods.fml.common.FMLCommonHandler;
2024-07-15 17:52:57 -07:00
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import cpw.mods.fml.common.gameevent.TickEvent.ClientTickEvent;
import cpw.mods.fml.common.gameevent.TickEvent.Phase;
2022-08-08 17:40:12 +08:00
public class ClientProxy extends CommonProxy {
// Structure Renderer
private static final Minecraft minecraft = Minecraft.getMinecraft();
private static StructureWorld structureWorld = null;
private static final ThreadLocal<RenderStructureGlobal> renderStructureGlobal = ThreadLocal
.withInitial(RenderStructureGlobal::new);
// End Structure Renderer
private static final short[] RGBA_NO_TINT = { 255, 255, 255, 255 };
2022-08-24 12:22:02 +08:00
private static final short[] RGBA_RED_TINT = { 255, 128, 128, 0 };
private static final Map<HintParticleInfo, HintGroup> allHints = new HashMap<>();
/**
* All batches of hints.
*/
private static final List<HintGroup> allGroups = new ArrayList<>();
2022-08-24 12:22:02 +08:00
/**
* Current batch of hints. Belongs to the same logical multiblock.
*/
private static HintGroup currentHints;
/**
* Collection of all hints. Sorted from farthest (index 0) to nearest (index size - 1)
* <p>
* 10k should be more than enough, if not a bit wasteful
*/
private static final List<HintParticleInfo> allHintsForRender = new ArrayList<>(10000);
/**
* If the diff to current player position is too great sort the allHints. Initial value is very far off below y=0
* but not huge enough to make a NaN.
* <p>
* We are using this supposedly immutable object as a mutable object here. So be aware.
*/
private static final Vec3 lastPlayerPos = Vec3.createVectorHelper(0, -1e30, 0);
/**
* if true rebuild the allHints list from all hintOwners (and sort it)
*/
private static boolean allHintsDirty = false;
2022-08-24 19:43:10 +08:00
/**
* counter keeping track of how many renderThrough hint particle we have. enable optimization if no renderThrough
*/
private static int renderThrough;
2022-09-02 15:45:13 +08:00
/**
* A throttle map for local player. Integrated server will use the throttle map in super class instead.
*/
private static final Map<Object, Long> localThrottleMap = new HashMap<>();
public static StructureWorld getStructureWorld() {
return structureWorld;
}
public static void setStructureWorld(StructureWorld structureWorld) {
ClientProxy.structureWorld = structureWorld;
}
@Override
public void hintParticleTinted(World w, int x, int y, int z, IIcon[] icons, short[] RGBa) {
ensureHinting();
2022-08-25 16:07:42 +08:00
HintParticleInfo info = new HintParticleInfo(w, x, y, z, icons, RGBa);
// check and remove colliding holograms
if (ConfigurationHandler.INSTANCE.isRemoveCollidingHologram()) {
HintGroup dupe = allHints.get(info);
if (dupe != null && dupe != currentHints) {
allGroups.remove(dupe);
removeGroup(dupe);
}
}
allHints.put(info, currentHints);
currentHints.getHints().add(info);
allHintsDirty = true;
2022-08-24 12:22:02 +08:00
EntityFX particle = new WeightlessParticleFX(
w,
x + RANDOM.nextFloat() * 0.5F,
y + RANDOM.nextFloat() * 0.5F,
z + RANDOM.nextFloat() * 0.5F,
0,
0,
0);
particle.setRBGColorF(0, 0.6F * RANDOM.nextFloat(), 0.8f);
Minecraft.getMinecraft().effectRenderer.addEffect(particle);
}
@Override
public void hintParticleTinted(World w, int x, int y, int z, Block block, int meta, short[] RGBa) {
hintParticleTinted(w, x, y, z, createIIconFromBlock(block, meta), RGBa);
}
@Override
public void hintParticle(World w, int x, int y, int z, IIcon[] icons) {
hintParticleTinted(w, x, y, z, icons, RGBA_NO_TINT);
}
@Override
public void hintParticle(World w, int x, int y, int z, Block block, int meta) {
hintParticleTinted(w, x, y, z, createIIconFromBlock(block, meta), RGBA_NO_TINT);
2022-08-08 17:40:12 +08:00
}
@Override
public boolean updateHintParticleTint(EntityPlayer player, World w, int x, int y, int z, short[] rgBa) {
if (player instanceof EntityPlayerMP) return super.updateHintParticleTint(player, w, x, y, z, rgBa);
if (player != getCurrentPlayer()) return false; // how?
2022-08-25 16:07:42 +08:00
HintParticleInfo hint = getHintParticleInfo(w, x, y, z);
2022-08-24 12:22:02 +08:00
if (hint == null) {
return false;
}
hint.setTint(rgBa);
return true;
}
2022-08-25 16:07:42 +08:00
private static HintParticleInfo getHintParticleInfo(World w, int x, int y, int z) {
HintParticleInfo info = new HintParticleInfo(w, x, y, z, null, null);
HintGroup existing = allHints.get(info);
2022-08-08 17:40:12 +08:00
if (existing != null) {
for (HintParticleInfo hint : existing.getHints()) {
2022-08-24 12:22:02 +08:00
if (hint.equals(info)) {
return hint;
}
}
2022-08-08 17:40:12 +08:00
}
2022-08-24 12:22:02 +08:00
return null;
}
@Override
public boolean markHintParticleError(EntityPlayer player, World w, int x, int y, int z) {
if (player instanceof EntityPlayerMP) return super.markHintParticleError(player, w, x, y, z);
if (player != getCurrentPlayer()) return false; // how?
2022-08-25 16:07:42 +08:00
HintParticleInfo hint = getHintParticleInfo(w, x, y, z);
2022-08-24 12:22:02 +08:00
if (hint == null) {
return false;
}
hint.setTint(RGBA_RED_TINT);
2022-08-24 19:43:10 +08:00
hint.setRenderThrough();
2022-08-24 12:22:02 +08:00
return true;
}
2022-09-02 15:45:13 +08:00
@Override
public void addThrottledChat(Object throttleKey, EntityPlayer player, IChatComponent text, short intervalRequired,
boolean forceUpdateLastSend) {
if (player instanceof EntityPlayerMP)
super.addThrottledChat(throttleKey, player, text, intervalRequired, forceUpdateLastSend);
else if (player != null)
addThrottledChat(throttleKey, player, text, intervalRequired, forceUpdateLastSend, localThrottleMap);
}
static void removeGroup(HintGroup group) {
2022-08-24 19:43:10 +08:00
for (HintParticleInfo hintParticleInfo : group.getHints()) {
allHints.remove(hintParticleInfo);
if (hintParticleInfo.renderThrough) renderThrough--;
}
allHintsDirty = true;
}
private static IIcon[] createIIconFromBlock(Block block, int meta) {
IIcon[] ret = new IIcon[6];
for (int i = 0; i < 6; i++) {
ret[i] = block.getIcon(i, meta);
}
return ret;
}
@Override
public void addClientSideChatMessages(String... messages) {
GuiNewChat chat = Minecraft.getMinecraft().ingameGUI.getChatGUI();
for (String s : messages) {
chat.printChatMessage(new ChatComponentText(s));
}
}
@Override
public EntityPlayer getCurrentPlayer() {
return Minecraft.getMinecraft().thePlayer;
}
@Override
public boolean isCurrentPlayer(EntityPlayer player) {
return player == Minecraft.getMinecraft().thePlayer;
}
@Override
public void startHinting(World w) {
2022-08-24 12:22:02 +08:00
if (!w.isRemote) return;
if (currentHints != null) endHinting(w);
currentHints = new HintGroup();
}
private void ensureHinting() {
2022-08-24 12:22:02 +08:00
if (currentHints == null) currentHints = new HintGroup();
}
@Override
public void endHinting(World w) {
2022-08-24 12:22:02 +08:00
if (!w.isRemote || currentHints == null) return;
while (!allGroups.isEmpty() && allGroups.size() >= ConfigurationHandler.INSTANCE.getMaxCoexistingHologram()) {
allGroups.remove(0);
}
2022-08-24 12:22:02 +08:00
if (!currentHints.getHints().isEmpty()) allGroups.add(currentHints);
// we use the player existence time here as some worlds don't really advance the time ticker
currentHints.setCreationTime(getCurrentPlayer().ticksExisted);
currentHints = null;
}
2022-08-08 17:40:12 +08:00
@Override
public long getOverworldTime() {
// there is no overworld, better just hope current world time is ok...
return Minecraft.getMinecraft().theWorld.getTotalWorldTime();
}
2022-08-23 12:29:59 +08:00
@Override
public void uploadChannels(ItemStack trigger) {
StructureLib.net.sendToServer(new SetChannelDataMessage(trigger));
}
@Override
public void preInit(FMLPreInitializationEvent e) {
2024-07-15 17:52:57 -07:00
super.preInit(e);
FMLCommonHandler.instance().bus().register(new FMLEventHandler());
MinecraftForge.EVENT_BUS.register(new ForgeEventHandler());
2024-07-15 17:52:57 -07:00
GuiContainerManager.addInputHandler(new InputHandler());
GuiContainerManager.addTooltipHandler(new InputHandler());
}
@Override
public void init(FMLInitializationEvent e) {
super.init(e);
IMCForNEI.IMCSender();
}
@Override
public void postInit(FMLPostInitializationEvent e) {
super.postInit(e);
MinecraftForge.EVENT_BUS.register(new EventHandler());
}
private static ForgeDirection getOrientation(EntityPlayer player) {
if (player.rotationPitch > 45) {
return ForgeDirection.DOWN;
} else if (player.rotationPitch < -45) {
return ForgeDirection.UP;
} else {
switch (MathHelper.floor_double(player.rotationYaw / 90.0 + 0.5) & 3) {
case 0:
return ForgeDirection.SOUTH;
case 1:
return ForgeDirection.WEST;
case 2:
return ForgeDirection.NORTH;
case 3:
return ForgeDirection.EAST;
}
}
return ForgeDirection.UNKNOWN;
}
2022-08-25 16:09:16 +08:00
static void markTextureUsed(IIcon icon) {
if (StructureLib.COMPAT instanceof IStructureCompat)
((IStructureCompat) StructureLib.COMPAT).markTextureUsed(icon);
}
private static class HintGroup {
private final List<HintParticleInfo> hints = new LinkedList<>();
private int creationTime = -1;
public List<HintParticleInfo> getHints() {
return hints;
}
public void setCreationTime(int creationTime) {
this.creationTime = creationTime;
}
public int getCreationTime() {
return creationTime;
}
}
private static class HintParticleInfo {
2022-08-25 16:07:42 +08:00
private final World w;
// these are the block coordinate for e.g. w.getBlock()
private final int x, y, z;
private final IIcon[] icons;
private short[] tint;
2022-08-24 12:22:02 +08:00
private boolean renderThrough;
private final long creationTime = System.currentTimeMillis(); // use tick time instead maybe
2022-08-25 16:07:42 +08:00
public HintParticleInfo(World w, int x, int y, int z, IIcon[] icons, short[] tint) {
this.w = w;
this.x = x;
this.y = y;
this.z = z;
this.icons = icons;
this.tint = tint;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof HintParticleInfo)) return false;
HintParticleInfo that = (HintParticleInfo) o;
return x == that.x && y == that.y && z == that.z;
}
2022-08-24 12:22:02 +08:00
public void setTint(short[] tint) {
this.tint = tint;
}
2022-08-24 19:43:10 +08:00
public void setRenderThrough() {
if (!this.renderThrough) {
ClientProxy.renderThrough += 1;
allHintsDirty = true;
}
this.renderThrough = true;
2022-08-24 12:22:02 +08:00
}
@Override
public int hashCode() {
int result = x;
result = 31 * result + y;
result = 31 * result + z;
return result;
}
2022-08-25 16:07:42 +08:00
public boolean isInFrustrum(Frustrum frustrum) {
2023-02-27 20:36:44 +08:00
return frustrum.isBoxInFrustum(x + 0.25, y + 0.25, z + 0.25, x + 0.75, y + 0.75, z + 0.75);
2022-08-25 16:07:42 +08:00
}
2023-02-27 20:36:44 +08:00
public void draw(Tessellator tes, double eyeX, double eyeY, double eyeZ, int eyeXint, int eyeYint,
int eyeZint) {
double size = 0.5;
2022-08-25 16:07:42 +08:00
int brightness = w.blockExists(x, 0, z) ? w.getLightBrightnessForSkyBlocks(x, y, z, 0) : 0;
tes.setBrightness(brightness);
tes.setColorRGBA(
(int) (tint[0] * .9F),
(int) (tint[1] * .95F),
(int) (tint[2] * 1F),
ConfigurationHandler.INSTANCE.getHintTransparency());
2023-02-27 19:57:51 +08:00
double X = (x - eyeXint) + 0.25;
double Y = (y - eyeYint) + 0.25;
double Z = (z - eyeZint) + 0.25;
2023-07-14 04:05:35 +08:00
double worldX = x + 0.25;
double worldY = y + 0.25;
double worldZ = z + 0.25;
// this rendering code is independently written by glee8e on July 10th, 2023
// and is released as part of StructureLib under LGPL terms, just like everything else in this project
// cube is a very special model. its facings can be rendered correctly by viewer distance without using
// surface normals and view vector
// here we do a 2 pass render.
// first pass we draw obstructed faces (i.e. faces that are further away from player)
// second pass we draw unobstructed faces
for (int j = 0; j < 2; j++) {
boolean unobstructedPass = j == 1;
for (int i = 0; i < 6; i++) {
if (icons[i] == null) continue;
markTextureUsed(icons[i]);
double u = icons[i].getMinU();
double U = icons[i].getMaxU();
double v = icons[i].getMinV();
double V = icons[i].getMaxV();
2022-09-09 19:48:12 +08:00
switch (i) { // {DOWN, UP, NORTH, SOUTH, WEST, EAST}
case 0:
2023-07-14 04:05:35 +08:00
// all these ifs is in form if ((is face unobstructed) != (is in unobstructred pass))
if ((worldY >= eyeY) != unobstructedPass) continue;
2022-09-09 19:48:12 +08:00
tes.setNormal(0, -1, 0);
tes.addVertexWithUV(X, Y, Z + size, u, V);
tes.addVertexWithUV(X, Y, Z, u, v);
tes.addVertexWithUV(X + size, Y, Z, U, v);
2023-02-27 19:57:51 +08:00
tes.addVertexWithUV(X + size, Y, Z, U, v);
2022-09-09 19:48:12 +08:00
tes.addVertexWithUV(X + size, Y, Z + size, U, V);
2023-02-27 19:57:51 +08:00
tes.addVertexWithUV(X, Y, Z + size, u, V);
2022-09-09 19:48:12 +08:00
break;
case 1:
2023-07-14 04:05:35 +08:00
if ((worldY + size <= eyeY) != unobstructedPass) continue;
2022-09-09 19:48:12 +08:00
tes.setNormal(0, 1, 0);
tes.addVertexWithUV(X, Y + size, Z, u, v);
tes.addVertexWithUV(X, Y + size, Z + size, u, V);
tes.addVertexWithUV(X + size, Y + size, Z + size, U, V);
2023-02-27 19:57:51 +08:00
tes.addVertexWithUV(X + size, Y + size, Z + size, U, V);
2022-09-09 19:48:12 +08:00
tes.addVertexWithUV(X + size, Y + size, Z, U, v);
2023-02-27 19:57:51 +08:00
tes.addVertexWithUV(X, Y + size, Z, u, v);
2022-09-09 19:48:12 +08:00
break;
case 2:
2023-07-14 04:05:35 +08:00
if ((worldZ >= eyeZ) != unobstructedPass) continue;
2022-09-09 19:48:12 +08:00
tes.setNormal(0, 0, -1);
tes.addVertexWithUV(X, Y, Z, U, V);
tes.addVertexWithUV(X, Y + size, Z, U, v);
tes.addVertexWithUV(X + size, Y + size, Z, u, v);
2023-02-27 19:57:51 +08:00
tes.addVertexWithUV(X + size, Y + size, Z, u, v);
2022-09-09 19:48:12 +08:00
tes.addVertexWithUV(X + size, Y, Z, u, V);
2023-02-27 19:57:51 +08:00
tes.addVertexWithUV(X, Y, Z, U, V);
2022-09-09 19:48:12 +08:00
break;
case 3:
2023-07-14 04:05:35 +08:00
if ((worldZ + size <= eyeZ) != unobstructedPass) continue;
2022-09-09 19:48:12 +08:00
tes.setNormal(0, 0, 1);
tes.addVertexWithUV(X + size, Y, Z + size, U, V);
tes.addVertexWithUV(X + size, Y + size, Z + size, U, v);
tes.addVertexWithUV(X, Y + size, Z + size, u, v);
2023-02-27 19:57:51 +08:00
tes.addVertexWithUV(X, Y + size, Z + size, u, v);
2022-09-09 19:48:12 +08:00
tes.addVertexWithUV(X, Y, Z + size, u, V);
2023-02-27 19:57:51 +08:00
tes.addVertexWithUV(X + size, Y, Z + size, U, V);
2022-09-09 19:48:12 +08:00
break;
case 4:
2023-07-14 04:05:35 +08:00
if ((worldX >= eyeX) != unobstructedPass) continue;
2022-09-09 19:48:12 +08:00
tes.setNormal(-1, 0, 0);
tes.addVertexWithUV(X, Y, Z + size, U, V);
tes.addVertexWithUV(X, Y + size, Z + size, U, v);
tes.addVertexWithUV(X, Y + size, Z, u, v);
2023-02-27 19:57:51 +08:00
tes.addVertexWithUV(X, Y + size, Z, u, v);
2022-09-09 19:48:12 +08:00
tes.addVertexWithUV(X, Y, Z, u, V);
2023-02-27 19:57:51 +08:00
tes.addVertexWithUV(X, Y, Z + size, U, V);
2022-09-09 19:48:12 +08:00
break;
case 5:
2023-07-14 04:05:35 +08:00
if ((worldX + size <= eyeX) != unobstructedPass) continue;
2022-09-09 19:48:12 +08:00
tes.setNormal(1, 0, 0);
tes.addVertexWithUV(X + size, Y, Z, U, V);
tes.addVertexWithUV(X + size, Y + size, Z, U, v);
tes.addVertexWithUV(X + size, Y + size, Z + size, u, v);
2023-02-27 19:57:51 +08:00
tes.addVertexWithUV(X + size, Y + size, Z + size, u, v);
2022-09-09 19:48:12 +08:00
tes.addVertexWithUV(X + size, Y, Z + size, u, V);
2023-02-27 19:57:51 +08:00
tes.addVertexWithUV(X + size, Y, Z, U, V);
2022-09-09 19:48:12 +08:00
break;
}
}
}
}
public long getCreationTime() {
return creationTime;
}
public double getSquareDistanceTo(Vec3 point) {
2023-02-27 19:57:51 +08:00
return point.squareDistanceTo(x + 0.5, y + 0.5, z + 0.5);
}
}
public static class FMLEventHandler {
private void resetPlayerLocation() {
lastPlayerPos.xCoord = Minecraft.getMinecraft().thePlayer.posX;
lastPlayerPos.yCoord = Minecraft.getMinecraft().thePlayer.posY;
lastPlayerPos.zCoord = Minecraft.getMinecraft().thePlayer.posZ;
}
@SubscribeEvent
public void onClientTick(ClientTickEvent e) {
if (e.phase == Phase.END && Minecraft.getMinecraft().thePlayer != null) {
Vec3 playerPos = Minecraft.getMinecraft().thePlayer.getPosition(1);
boolean sortRequired = false;
// The allGroups is implicitly sorted by creationTime
// here we exploit this ordering to reduce iteration size
int deadline = Minecraft.getMinecraft().thePlayer.ticksExisted
- ConfigurationHandler.INSTANCE.getHintLifespan();
int i;
for (i = 0; i < allGroups.size(); i++) {
if (allGroups.get(i).getCreationTime() > deadline) {
break;
}
}
if (i != 0) {
sortRequired = true;
// clear this block and go no further
List<HintGroup> toRemove = allGroups.subList(0, i);
toRemove.forEach(ClientProxy::removeGroup);
toRemove.clear();
}
if (allHintsDirty) {
allHintsForRender.clear();
// we need greatly efficient sequential access and mildly efficient sorting
// rebuild is sort of rare, and it's expected to lag anyway
// so no min-heap here
for (HintGroup c : allGroups) allHintsForRender.addAll(c.getHints());
sortRequired = true;
}
2022-09-09 19:48:12 +08:00
if (sortRequired || playerPos.squareDistanceTo(lastPlayerPos) > 1e-2) {
// only redo sort if player moved some distance
2022-08-25 14:24:27 +08:00
// default is 0.1 block
// if there was a full rebuild, go sort it as well
2022-09-09 19:48:12 +08:00
allHintsForRender.sort(Comparator.comparingDouble(info -> -info.getSquareDistanceTo(playerPos)));
resetPlayerLocation();
}
}
}
}
public static class ForgeEventHandler {
@SubscribeEvent
public void onWorldLoad(WorldEvent.Load e) {
if (e.world.isRemote) {
2022-09-02 15:45:13 +08:00
// flush hints. we are in a different world now.
allHintsForRender.clear();
allGroups.clear();
lastPlayerPos.yCoord = -1e30;
2022-08-24 19:43:10 +08:00
renderThrough = 0;
2022-09-02 15:45:13 +08:00
// clear throttles. hopefully a world switch is enough long as a cool down.
localThrottleMap.clear();
}
}
@SubscribeEvent
public void onRenderWorldLast(RenderWorldLastEvent e) {
renderParticlePreview(e);
renderNewPreview(e);
}
private void renderNewPreview(RenderWorldLastEvent e) {
EntityPlayerSP player = minecraft.thePlayer;
if (player == null || structureWorld == null || !structureWorld.isRendering()) return;
final RenderStructureGlobal renderStructureGlobal = ClientProxy.renderStructureGlobal.get();
renderStructureGlobal.setPlayerPosition(
player.lastTickPosX + (player.posX - player.lastTickPosX) * e.partialTicks,
player.lastTickPosY + (player.posY - player.lastTickPosY) * e.partialTicks,
player.lastTickPosZ + (player.posZ - player.lastTickPosZ) * e.partialTicks);
renderStructureGlobal.setOrientation(getOrientation(player));
renderStructureGlobal.setRotationRender(MathHelper.floor_double(player.rotationYaw / 90) & 3);
minecraft.mcProfiler.startSection("structlibRenderPreview");
renderStructureGlobal.render(structureWorld);
minecraft.mcProfiler.endSection();
}
private void renderParticlePreview(RenderWorldLastEvent e) {
2022-08-24 19:43:10 +08:00
if (allHintsForRender.isEmpty()) return;
// seriously, I'm not a OpenGL expert, so I'm probably doing a lot of very stupid stuff here.
2022-08-25 14:24:27 +08:00
// Please consider contributing patches if you find something to optimize.
2022-08-24 19:43:10 +08:00
2022-08-25 14:24:27 +08:00
Profiler p = Minecraft.getMinecraft().mcProfiler;
p.startSection("HintParticle");
p.startSection("Prepare");
2022-08-25 16:07:42 +08:00
Frustrum frustrum = new Frustrum();
Entity entitylivingbase = Minecraft.getMinecraft().renderViewEntity;
double d0 = entitylivingbase.lastTickPosX
+ (entitylivingbase.posX - entitylivingbase.lastTickPosX) * e.partialTicks;
double d1 = entitylivingbase.lastTickPosY
+ (entitylivingbase.posY - entitylivingbase.lastTickPosY) * e.partialTicks;
double d2 = entitylivingbase.lastTickPosZ
+ (entitylivingbase.posZ - entitylivingbase.lastTickPosZ) * e.partialTicks;
2023-02-27 19:57:51 +08:00
int i0 = (int) d0, i1 = (int) d1, i2 = (int) d2;
2022-08-25 16:07:42 +08:00
frustrum.setPosition(d0, d1, d2);
2022-08-24 19:43:10 +08:00
GL11.glPushMatrix();
2022-08-24 12:22:02 +08:00
GL11.glPushAttrib(GL11.GL_ENABLE_BIT | GL11.GL_COLOR_BUFFER_BIT); // TODO figure out original states
2022-08-25 16:07:42 +08:00
// we need the back facing rendered because the thing is transparent
GL11.glDisable(GL11.GL_CULL_FACE);
2022-09-09 19:48:12 +08:00
GL11.glDisable(GL11.GL_ALPHA_TEST);
GL11.glEnable(GL11.GL_BLEND); // enable blend so it is transparent
GL11.glBlendFunc(GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_SRC_ALPHA);
2022-08-24 19:43:10 +08:00
// depth test begin as enabled
boolean renderThrough = false;
Minecraft.getMinecraft().renderEngine.bindTexture(TextureMap.locationBlocksTexture);
2023-02-27 19:57:51 +08:00
GL11.glTranslated(-d0 + i0, -d1 + i1, -d2 + i2);
Tessellator tes = Tessellator.instance;
2023-02-27 19:57:51 +08:00
tes.startDrawing(GL11.GL_TRIANGLES);
for (int i = 0, allHintsForRenderSize = allHintsForRender.size(), cubeDrawn = 0; i
< allHintsForRenderSize; i++, cubeDrawn++) {
2022-08-24 19:43:10 +08:00
HintParticleInfo hint = allHintsForRender.get(i);
2022-08-25 16:07:42 +08:00
if (!hint.isInFrustrum(frustrum)) continue;
2022-08-24 12:22:02 +08:00
if (renderThrough != hint.renderThrough) {
2022-08-24 19:43:10 +08:00
if (i > 0) {
2022-08-25 14:24:27 +08:00
p.endStartSection("Draw");
2022-08-24 19:43:10 +08:00
tes.draw();
2023-02-27 19:57:51 +08:00
tes.startDrawing(GL11.GL_TRIANGLES);
cubeDrawn = 0;
2022-08-25 14:24:27 +08:00
p.endStartSection("Prepare");
2022-08-24 19:43:10 +08:00
}
2022-08-24 12:22:02 +08:00
if (hint.renderThrough) GL11.glDisable(GL11.GL_DEPTH_TEST);
else GL11.glEnable(GL11.GL_DEPTH_TEST);
renderThrough = hint.renderThrough;
}
// Minecraft Tessellator draw in batch of 4096. This plays nicely with quads, but for trigs
// it might occasionally end up with one half in first batch and the other half in later batch.
// so we manually flush the buffer here if that would happen.
// 6 faces per particle, 2 trig per face, 3 vertex per trig
if ((cubeDrawn + 1) >= 4096 / (6 * 2 * 3)) {
tes.draw();
tes.startDrawing(GL11.GL_TRIANGLES);
}
2023-02-27 19:57:51 +08:00
hint.draw(tes, d0, d1, d2, i0, i1, i2);
}
2022-08-25 14:24:27 +08:00
p.endStartSection("Draw");
tes.draw();
2022-08-25 14:24:27 +08:00
p.endSection();
2022-08-24 19:43:10 +08:00
GL11.glPopAttrib();
2022-08-24 19:43:10 +08:00
GL11.glPopMatrix();
2022-08-25 14:24:27 +08:00
p.endSection();
}
}
}