Skip to content

Commit d51e94e

Browse files
committed
Improved placement of Field Projectors
Changed the basic logic how the rotation of a field projector is determined. It is now using the hitpos on the block you are building on, which makes it possible to place FPs facing any direction independent of the player position. Fixes #345
1 parent 1cf4622 commit d51e94e

File tree

3 files changed

+220
-2
lines changed

3 files changed

+220
-2
lines changed

src/main/java/org/dave/compactmachines3/block/BlockFieldProjector.java

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,15 @@
1313
import net.minecraft.entity.EntityLivingBase;
1414
import net.minecraft.entity.player.EntityPlayer;
1515
import net.minecraft.entity.player.EntityPlayerMP;
16+
import net.minecraft.init.Blocks;
1617
import net.minecraft.item.Item;
1718
import net.minecraft.item.ItemStack;
1819
import net.minecraft.tileentity.TileEntity;
1920
import net.minecraft.util.EnumFacing;
2021
import net.minecraft.util.EnumHand;
2122
import net.minecraft.util.math.BlockPos;
23+
import net.minecraft.util.math.RayTraceResult;
24+
import net.minecraft.util.math.Vec3d;
2225
import net.minecraft.util.text.TextComponentTranslation;
2326
import net.minecraft.world.IBlockAccess;
2427
import net.minecraft.world.World;
@@ -30,6 +33,7 @@
3033
import org.dave.compactmachines3.miniaturization.MultiblockRecipe;
3134
import org.dave.compactmachines3.miniaturization.MultiblockRecipes;
3235
import org.dave.compactmachines3.misc.CreativeTabCompactMachines3;
36+
import org.dave.compactmachines3.misc.RotationTools;
3337
import org.dave.compactmachines3.network.MessageParticleBlockMarker;
3438
import org.dave.compactmachines3.network.PackageHandler;
3539
import org.dave.compactmachines3.render.TESRFieldProjector;
@@ -180,15 +184,29 @@ public boolean isOpaqueCube(IBlockState state) {
180184

181185
@Override
182186
public void onBlockPlacedBy(World world, BlockPos pos, IBlockState state, EntityLivingBase placer, ItemStack stack) {
183-
world.setBlockState(pos, state.withProperty(FACING, getFacingFromEntity(pos, placer)), 2);
187+
// Make sure the block is rotated properly
188+
world.setBlockState(pos, Blocks.AIR.getDefaultState());
189+
float blockReachDistance = 6.0F;
184190

191+
Vec3d posVec = placer.getPositionEyes(1.0f);
192+
Vec3d lookVec = placer.getLook(1.0f);
193+
Vec3d endVec = posVec.add(lookVec.scale(blockReachDistance));
194+
RayTraceResult trace = world.rayTraceBlocks(posVec, endVec);
195+
196+
Vec3d hitPosition = trace.hitVec;
197+
hitPosition = hitPosition.subtract(new Vec3d(trace.getBlockPos()));
198+
hitPosition = hitPosition.subtract(0.5d, 0.5d, 0.5d);
199+
200+
world.setBlockState(pos, state.withProperty(FACING, RotationTools.getFacingByTriangle(hitPosition)), 2);
201+
202+
// Then copy tile entity data to the block
185203
if(!(world.getTileEntity(pos) instanceof TileEntityFieldProjector)) {
186204
return;
187205
}
188206

189207
TileEntityFieldProjector teProjector = (TileEntityFieldProjector) world.getTileEntity(pos);
190208
if(stack.hasTagCompound()) {
191-
if(stack.getTagCompound().hasKey("owner")) {
209+
if(stack.getTagCompound().hasKey("ownerLeast") && stack.getTagCompound().hasKey("ownerMost")) {
192210
teProjector.setOwner(stack.getTagCompound().getUniqueId("owner"));
193211
}
194212
}

src/main/java/org/dave/compactmachines3/misc/PlayerEventHandler.java

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,29 @@
11
package org.dave.compactmachines3.misc;
22

3+
import net.minecraft.client.Minecraft;
34
import net.minecraft.entity.player.EntityPlayer;
45
import net.minecraft.entity.player.EntityPlayerMP;
6+
import net.minecraft.item.ItemBlock;
7+
import net.minecraft.item.ItemStack;
58
import net.minecraft.potion.Potion;
69
import net.minecraft.potion.PotionEffect;
10+
import net.minecraft.util.EnumFacing;
11+
import net.minecraft.util.EnumHand;
712
import net.minecraft.util.math.AxisAlignedBB;
813
import net.minecraft.util.math.BlockPos;
14+
import net.minecraft.util.math.RayTraceResult;
915
import net.minecraft.util.math.Vec3d;
1016
import net.minecraft.util.text.TextComponentTranslation;
1117
import net.minecraftforge.client.event.GuiOpenEvent;
18+
import net.minecraftforge.client.event.RenderWorldLastEvent;
1219
import net.minecraftforge.event.entity.player.PlayerSleepInBedEvent;
1320
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
1421
import net.minecraftforge.fml.common.gameevent.PlayerEvent;
1522
import net.minecraftforge.fml.common.gameevent.TickEvent;
1623
import net.minecraftforge.fml.relauncher.Side;
1724
import net.minecraftforge.fml.relauncher.SideOnly;
1825
import org.dave.compactmachines3.gui.machine.GuiMachineData;
26+
import org.dave.compactmachines3.init.Blockss;
1927
import org.dave.compactmachines3.reference.EnumMachineSize;
2028
import org.dave.compactmachines3.world.WorldSavedDataMachines;
2129
import org.dave.compactmachines3.world.tools.StructureTools;
@@ -71,6 +79,50 @@ public static void onGuiClose(GuiOpenEvent event) {
7179
}
7280
}
7381

82+
@SubscribeEvent
83+
@SideOnly(Side.CLIENT)
84+
public static void renderRotationIndicator(RenderWorldLastEvent event) {
85+
if(!Minecraft.isGuiEnabled() || Minecraft.getMinecraft().player == null) {
86+
return;
87+
}
88+
89+
EntityPlayer player = Minecraft.getMinecraft().player;
90+
ItemStack heldItem = player.getHeldItem(EnumHand.MAIN_HAND);
91+
if(heldItem.isEmpty()) {
92+
return;
93+
}
94+
95+
if(!(heldItem.getItem() instanceof ItemBlock && ((ItemBlock) heldItem.getItem()).getBlock() == Blockss.fieldProjector)) {
96+
return;
97+
}
98+
99+
RayTraceResult trace = Minecraft.getMinecraft().objectMouseOver;
100+
if(trace == null || trace.hitVec == null || trace.typeOfHit != RayTraceResult.Type.BLOCK) {
101+
return;
102+
}
103+
104+
if(trace.sideHit != EnumFacing.UP) {
105+
return;
106+
}
107+
108+
// Get a interpolated clientPosition so we don't get flickering when moving
109+
Vec3d cameraPosition = new Vec3d(
110+
player.lastTickPosX + (player.posX - player.lastTickPosX) * event.getPartialTicks(),
111+
player.lastTickPosY + (player.posY - player.lastTickPosY) * event.getPartialTicks(),
112+
player.lastTickPosZ + (player.posZ - player.lastTickPosZ) * event.getPartialTicks()
113+
);
114+
115+
// Get the position on the top face of the block the player is looking at, between -0.5 and +0.5 on both axis
116+
Vec3d hitPosition = trace.hitVec;
117+
hitPosition = hitPosition.subtract(new Vec3d(trace.getBlockPos()));
118+
hitPosition = hitPosition.subtract(0.5d, 0.5d, 0.5d);
119+
120+
// Move the drawing area to one block above the block we are looking at
121+
BlockPos drawPosition = trace.getBlockPos().up();
122+
123+
RotationTools.renderArrowOnGround(cameraPosition, hitPosition, drawPosition);
124+
}
125+
74126
@SubscribeEvent
75127
public static void onPlayerTick(TickEvent.PlayerTickEvent event) {
76128
if(event.player.world.isRemote) {
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
package org.dave.compactmachines3.misc;
2+
3+
import net.minecraft.client.Minecraft;
4+
import net.minecraft.client.renderer.BufferBuilder;
5+
import net.minecraft.client.renderer.GlStateManager;
6+
import net.minecraft.client.renderer.Tessellator;
7+
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
8+
import net.minecraft.util.EnumFacing;
9+
import net.minecraft.util.ResourceLocation;
10+
import net.minecraft.util.Tuple;
11+
import net.minecraft.util.math.BlockPos;
12+
import net.minecraft.util.math.Vec3d;
13+
import net.minecraftforge.fml.relauncher.Side;
14+
import net.minecraftforge.fml.relauncher.SideOnly;
15+
import org.dave.compactmachines3.CompactMachines3;
16+
17+
import java.util.ArrayList;
18+
19+
public class RotationTools {
20+
@SideOnly(Side.CLIENT)
21+
private static ResourceLocation arrowImage;
22+
23+
@SideOnly(Side.CLIENT)
24+
public static void renderArrowOnGround(Vec3d cameraPosition, Vec3d hitPosition, BlockPos drawPosition) {
25+
EnumFacing facing = RotationTools.getFacingByTriangle(hitPosition);
26+
27+
RotationTools.TextureRotationList rotList = new RotationTools.TextureRotationList();
28+
switch (facing) {
29+
case SOUTH:
30+
break;
31+
case WEST:
32+
rotList.rotateFromStart();
33+
break;
34+
case NORTH:
35+
rotList.rotateFromStart();
36+
rotList.rotateFromStart();
37+
break;
38+
case EAST:
39+
rotList.rotateFromStart();
40+
rotList.rotateFromStart();
41+
rotList.rotateFromStart();
42+
break;
43+
}
44+
45+
if(arrowImage == null) {
46+
arrowImage = new ResourceLocation(CompactMachines3.MODID, "textures/particles/blockmarker.png");
47+
}
48+
Minecraft.getMinecraft().getTextureManager().bindTexture(arrowImage);
49+
50+
GlStateManager.pushMatrix();
51+
52+
GlStateManager.translate(-cameraPosition.x, -cameraPosition.y, -cameraPosition.z);
53+
GlStateManager.translate(drawPosition.getX(), drawPosition.getY(), drawPosition.getZ());
54+
55+
// Draw with 50% transparency
56+
GlStateManager.color(1.0F, 1.0F, 1.0F, 0.5F);
57+
58+
// Actually draw
59+
Tessellator tessellator = Tessellator.getInstance();
60+
BufferBuilder bufferbuilder = tessellator.getBuffer();
61+
bufferbuilder.begin(7, DefaultVertexFormats.POSITION_TEX);
62+
63+
rotList.fillBufferBuilder(bufferbuilder, 0.0005d);
64+
65+
tessellator.draw();
66+
67+
GlStateManager.popMatrix();
68+
}
69+
70+
public static EnumFacing getFacingByTriangle(Vec3d vec) {
71+
if(vec.z > 0) {
72+
if(vec.x < 0) {
73+
// Quadrant 1
74+
if(Math.abs(vec.x) < Math.abs(vec.z)) {
75+
// Bottom
76+
return EnumFacing.SOUTH;
77+
} else {
78+
// Left
79+
return EnumFacing.WEST;
80+
}
81+
} else {
82+
// Quadrant 2
83+
if(Math.abs(vec.x) > Math.abs(vec.z)) {
84+
// Right
85+
return EnumFacing.EAST;
86+
} else {
87+
// Bottom
88+
return EnumFacing.SOUTH;
89+
}
90+
}
91+
} else {
92+
if(vec.x < 0) {
93+
// Quadrant 3
94+
if(Math.abs(vec.x) < Math.abs(vec.z)) {
95+
// Top
96+
return EnumFacing.NORTH;
97+
} else {
98+
// Left
99+
return EnumFacing.WEST;
100+
}
101+
102+
} else {
103+
// Quadrant 4
104+
if(Math.abs(vec.x) > Math.abs(vec.z)) {
105+
// Right
106+
return EnumFacing.EAST;
107+
} else {
108+
// Top
109+
return EnumFacing.NORTH;
110+
}
111+
}
112+
}
113+
}
114+
115+
@SideOnly(Side.CLIENT)
116+
public static class TextureRotationList extends RotatingList<Tuple<Integer, Integer>> {
117+
public TextureRotationList() {
118+
this.add(new Tuple<>(0, 1));
119+
this.add(new Tuple<>(1, 1));
120+
this.add(new Tuple<>(1, 0));
121+
this.add(new Tuple<>(0, 0));
122+
}
123+
124+
public void fillBufferBuilder(BufferBuilder buffer, double yLevel) {
125+
buffer.pos(0, yLevel, 1).tex(this.get(0).getFirst(), this.get(0).getSecond()).endVertex();
126+
buffer.pos(1, yLevel, 1).tex(this.get(1).getFirst(), this.get(1).getSecond()).endVertex();
127+
buffer.pos(1, yLevel, 0).tex(this.get(2).getFirst(), this.get(2).getSecond()).endVertex();
128+
buffer.pos(0, yLevel, 0).tex(this.get(3).getFirst(), this.get(3).getSecond()).endVertex();
129+
130+
}
131+
}
132+
133+
134+
public static class RotatingList<T> extends ArrayList<T> {
135+
public void rotateFromStart() {
136+
T firstElement = this.get(0);
137+
this.remove(0);
138+
139+
this.add(firstElement);
140+
}
141+
142+
public void rotateFromEnd() {
143+
T lastElement = this.get(this.size()-1);
144+
this.remove(this.size()-1);
145+
this.add(0, lastElement);
146+
}
147+
}
148+
}

0 commit comments

Comments
 (0)