Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Portal Mechanics (Closes #130) #1024

Open
wants to merge 30 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
ad96125
First commit on this
heisluft Feb 7, 2019
f3db1db
Fixed imports
heisluft Feb 7, 2019
ab2915e
Renamed generic Portal variables to 'ender portal' in BlockEnderPorta…
VaiTon Feb 7, 2019
8c98b9c
Merge branch 'nether-portal' of https://github.com/VaiTon/Glowstone i…
heisluft Feb 7, 2019
6b442c0
Added proper portal checking
heisluft Feb 13, 2019
518999d
Merge branch 'dev' of https://github.com/GlowstoneMC/Glowstone into c…
heisluft Feb 13, 2019
c5ee5ba
Implement findOrCreate
Pr0methean Feb 15, 2019
5f0b8f0
Update NetherTravelAgent.java
Pr0methean Feb 15, 2019
c3d961f
Lombokify
Pr0methean Feb 15, 2019
7a6eec2
Bug fix
Pr0methean Feb 15, 2019
8f7da12
Fix the placing of portal blocks
heisluft Feb 16, 2019
2960c9f
Fixed compile error (Bukkit getCanCreatePortal vs. Lombok generated
heisluft Feb 16, 2019
08b584b
Dwelete debugging print statements
heisluft Feb 17, 2019
2a9d771
Fixed Logic for portal creation
heisluft Feb 17, 2019
7417ac4
Implement PortalCreateEvent
heisluft Feb 17, 2019
bdde48d
Implement Zombie Pigmen spawn and the destroying of portals
heisluft Feb 17, 2019
347eb38
Fix checkstyle errors
heisluft Feb 17, 2019
70713fd
Changed pigman spawn rate to vanilla value
heisluft Feb 17, 2019
97b12d8
implement portal creation by linking
heisluft Feb 21, 2019
ac789f8
Fix checkstyle video
heisluft Feb 22, 2019
ee11102
Renamed NetherTravelAgent to TravelAgentImpl as it will also be used
heisluft Feb 22, 2019
aa5dd7e
wired up travelagentimpl (now called GlowTravelAgent)
heisluft Feb 23, 2019
4a3463b
Fix checkstyle errors
mastercoms Apr 12, 2019
0f03af4
Merge branch 'dev' of https://github.com/GlowstoneMC/Glowstone into c…
heisluft Apr 28, 2019
517f540
Implement teleport to the nether and back
heisluft Apr 28, 2019
abb1290
Implement BoundingBox based portal entrance; Bugfix: Fire EnterEvent …
heisluft Apr 29, 2019
6af92fa
Fixed Checkstyle errors
heisluft Apr 29, 2019
69a4bb0
Applied suggestions
heisluft Apr 30, 2019
d31d8a0
Merge remote-tracking branch 'upstream/dev' into create-portal-event
heisluft Jan 9, 2020
8accf54
Applied suggestions
heisluft Jan 9, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/main/java/net/glowstone/GlowWorld.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
import net.glowstone.net.message.play.player.ServerDifficultyMessage;
import net.glowstone.util.BlockStateDelegate;
import net.glowstone.util.GameRuleManager;
import net.glowstone.util.GlowTravelAgent;
import net.glowstone.util.RayUtil;
import net.glowstone.util.TickUtil;
import net.glowstone.util.collection.ConcurrentSet;
Expand Down Expand Up @@ -376,6 +377,11 @@ public LightningStrike strikeLightningEffect(Location loc, boolean isSilent) {
*/
@Getter
private boolean initialized;
/**
* The TravelAgent of this world. Currently is null when this world is a THE_END world.
*/
@Getter
private GlowTravelAgent travelAgent;

/**
* Creates a new world from the options in the given WorldCreator.
Expand All @@ -391,6 +397,10 @@ public GlowWorld(GlowServer server, WorldCreator creator,
// set up values from WorldCreator
name = creator.name();
environment = creator.environment();
// end portals are not implemented yet
if (environment != Environment.THE_END) {
travelAgent = new GlowTravelAgent(this);
}
worldType = creator.type();
generateStructures = creator.generateStructures();

Expand Down
2 changes: 2 additions & 0 deletions src/main/java/net/glowstone/block/ItemTable.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
import net.glowstone.block.blocktype.BlockObserver;
import net.glowstone.block.blocktype.BlockOre;
import net.glowstone.block.blocktype.BlockPiston;
import net.glowstone.block.blocktype.BlockPortal;
import net.glowstone.block.blocktype.BlockPotato;
import net.glowstone.block.blocktype.BlockPumpkin;
import net.glowstone.block.blocktype.BlockPumpkinBase;
Expand Down Expand Up @@ -273,6 +274,7 @@ private void registerBuiltins() {
reg(Material.WEB, new BlockWeb());
reg(Material.FIRE, new BlockFire());
reg(Material.ENDER_PORTAL_FRAME, new BlockEnderPortalFrame());
reg(Material.PORTAL, new BlockPortal());
reg(Material.FENCE_GATE, new BlockFenceGate());
reg(Material.ACACIA_FENCE_GATE, new BlockFenceGate());
reg(Material.BIRCH_FENCE_GATE, new BlockFenceGate());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public boolean blockInteract(GlowPlayer player, GlowBlock block, BlockFace face,

block.setData((byte) (block.getData() | 0x4));
if (block.getWorld().getEnvironment() != Environment.THE_END) {
searchForCompletedPortal(player, block);
searchForCompletedEnderPortal(player, block);
}
return true;
}
Expand All @@ -65,13 +65,13 @@ public boolean blockInteract(GlowPlayer player, GlowBlock block, BlockFace face,
/**
* Checks for a completed portal at all relevant positions.
*/
private void searchForCompletedPortal(GlowPlayer player, GlowBlock changed) {
private void searchForCompletedEnderPortal(GlowPlayer player, GlowBlock changed) {
for (int i = 0; i < 4; i++) {
for (int j = -1; j <= 1; j++) {
GlowBlock center = changed.getRelative(SIDES[i], 2)
.getRelative(SIDES[(i + 1) % 4], j);
if (isCompletedPortal(center)) {
createPortal(player, center);
if (isCompletedEnderPortal(center)) {
createEnderPortal(player, center);
return;
}
}
Expand All @@ -81,7 +81,7 @@ private void searchForCompletedPortal(GlowPlayer player, GlowBlock changed) {
/**
* Check whether there is a completed portal with the specified center.
*/
private boolean isCompletedPortal(GlowBlock center) {
private boolean isCompletedEnderPortal(GlowBlock center) {
for (int i = 0; i < 4; i++) {
for (int j = -1; j <= 1; j++) {
GlowBlock block = center.getRelative(SIDES[i], 2)
Expand All @@ -98,7 +98,7 @@ private boolean isCompletedPortal(GlowBlock center) {
/**
* Spawn the portal and call the {@link EntityCreatePortalEvent}.
*/
private void createPortal(GlowPlayer player, GlowBlock center) {
private void createEnderPortal(GlowPlayer player, GlowBlock center) {
List<BlockState> blocks = new ArrayList<>(9);
for (int i = -1; i <= 1; i++) {
for (int j = -1; j <= 1; j++) {
Expand Down
87 changes: 87 additions & 0 deletions src/main/java/net/glowstone/block/blocktype/BlockPortal.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package net.glowstone.block.blocktype;

import java.util.concurrent.ThreadLocalRandom;
import net.glowstone.GlowServer;
import net.glowstone.GlowWorld;
import net.glowstone.block.GlowBlock;
import net.glowstone.entity.monster.GlowPigZombie;
import net.glowstone.entity.physics.BoundingBox;
import net.glowstone.util.pattern.PortalShape;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.BlockFace;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.util.Vector;

public class BlockPortal extends BlockType {

@Override
public void onNearBlockChanged(final GlowBlock block, BlockFace face, GlowBlock changedBlock,
Material oldType, byte oldData, Material newType, byte newData) {
if (newType == oldType || (oldType != Material.PORTAL && oldType != Material.OBSIDIAN)) {
return;
}
BlockFace left = getFace(block.getData());
if (left == null) {
return;
}
PortalShape shape = new PortalShape(block.getLocation(), left);
if (shape.validate()
&& shape.getPortalBlockCount() == shape.getHeight() * shape.getWidth()) {
return;
}
block.setType(Material.AIR);
}

public static BoundingBox getBoundingBox(GlowBlock block) {
heisluft marked this conversation as resolved.
Show resolved Hide resolved
boolean north = getFace(block.getData()) == BlockFace.NORTH;
Vector base = new Vector(north ? .375 : 0, 0, north ? 0 : .375);
Vector size = new Vector(north ? .25 : 1, 1, north ? 1 : .25);
return BoundingBox.fromPositionAndSize(block.getLocation().toVector().add(base), size);
}

private static BlockFace getFace(int blockData) {
int faceData = blockData & 3;
return faceData == 1 ? BlockFace.WEST : faceData == 2 ? BlockFace.NORTH : null;
}

@Override
public void updateBlock(GlowBlock block) {
// remove invalid portal blocks
if ((block.getData() & 3) == 0) {
block.setType(Material.AIR);
System.out.println(block.getLocation());
return;
}
GlowWorld world = block.getWorld();
GlowServer server = world.getServer();
// No pigman spawns without nether
if (!server.getAllowNether()
// Pigmen only spawn in overworld
|| world.getEnvironment() != World.Environment.NORMAL
// Pigmen spawning explicitly disabled
// TODO: Uncomment after implementing Spigot config
//|| !server.spigot().getSpigotConfig().
//getBoolean("enable-zombie-pigmen-portal-spawns")
// Increasing spawn chance with increasing difficulty.
// If random * 2000 is 0, it is still not bigger than the ordinal of peaceful (0)
|| ThreadLocalRandom.current().nextInt(2000) > world.getDifficulty().ordinal()
) {
return;
}

Location location = block.getLocation();
//move down to the bottom of the portal
while (location.getBlock().getType() == Material.PORTAL && location.getY() > 0) {
location.subtract(0, 1, 0);
}
world.spawn(location.add(.5, 2.1, .5), GlowPigZombie.class,
CreatureSpawnEvent.SpawnReason.NETHER_PORTAL);
}

@Override
public boolean canTickRandomly() {
return true;
}
}
55 changes: 36 additions & 19 deletions src/main/java/net/glowstone/block/itemtype/ItemFlintAndSteel.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import net.glowstone.block.ItemTable;
import net.glowstone.block.blocktype.BlockTnt;
import net.glowstone.entity.GlowPlayer;
import net.glowstone.util.pattern.PortalShape;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.event.block.BlockIgniteEvent;
Expand All @@ -13,6 +15,7 @@
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;


heisluft marked this conversation as resolved.
Show resolved Hide resolved
public class ItemFlintAndSteel extends ItemTool {

public ItemFlintAndSteel() {
Expand All @@ -21,60 +24,74 @@ public ItemFlintAndSteel() {

@Override
public boolean onToolRightClick(GlowPlayer player, GlowBlock target, BlockFace face,
ItemStack holding, Vector clickedLoc, EquipmentSlot hand) {
if (target.getType() == Material.OBSIDIAN) {
fireNetherPortal(target, face);
return true;
}
ItemStack holding, Vector clickedLoc, EquipmentSlot hand) {
if (target.getType() == Material.TNT) {
fireTnt(target, player);
return true;
}

if (tryFireNetherPortal(target, face)) {
return true;
}

if (target.isFlammable() || target.getType().isOccluding()) {
setBlockOnFire(player, target, face, holding, clickedLoc, hand);
return true;
}
return false;
}

private void fireNetherPortal(GlowBlock target, BlockFace face) {
if (face == BlockFace.UP || face == BlockFace.DOWN) {
target = target.getRelative(face);
int limit = 0;
while (target.getType() == Material.AIR && limit < 23) {
target.setType(Material.PORTAL);
target = target.getRelative(face);
limit++;
/**
* Try to fire a nether portal at the given position.
*
* @param target the target block
* @param face the face from which the block was fired
* @return whether a portal could be fired
*/
private boolean tryFireNetherPortal(GlowBlock target, BlockFace face) {
// Where fire would be placed if this is not a portal
Location fireLocation =
target.getLocation().add(face.getModX(), face.getModY(), face.getModZ());

PortalShape shape = new PortalShape(fireLocation, BlockFace.WEST);
if (!shape.validate() || shape.getPortalBlockCount() != 0) {
shape = new PortalShape(fireLocation, BlockFace.NORTH);
if (!shape.validate() || shape.getPortalBlockCount() != 0) {
return false;
}
shape.placePortalBlocks();
return true;
}
shape.placePortalBlocks();
return true;
}

private void fireTnt(GlowBlock tnt,GlowPlayer player) {
private void fireTnt(GlowBlock tnt, GlowPlayer player) {
BlockTnt.igniteBlock(tnt, false, player);
}

private boolean setBlockOnFire(GlowPlayer player, GlowBlock clicked, BlockFace face,
ItemStack holding, Vector clickedLoc, EquipmentSlot hand) {
ItemStack holding, Vector clickedLoc, EquipmentSlot hand) {
GlowBlock fireBlock = clicked.getRelative(face);
if (fireBlock.getType() != Material.AIR) {
return true;
}

if (!clicked.isFlammable()
&& clicked.getRelative(BlockFace.DOWN).getType() == Material.AIR) {
&& clicked.getRelative(BlockFace.DOWN).getType() == Material.AIR) {
return true;
}

BlockIgniteEvent event = EventFactory.getInstance()
.callEvent(new BlockIgniteEvent(fireBlock, IgniteCause.FLINT_AND_STEEL, player, null));
BlockIgniteEvent event = EventFactory.getInstance().callEvent(
new BlockIgniteEvent(fireBlock, IgniteCause.FLINT_AND_STEEL, player, null));
if (event.isCancelled()) {
player.setItemInHand(holding);
return false;
}

// clone holding to avoid decreasing of the item's amount
ItemTable.instance().getBlock(Material.FIRE)
.rightClickBlock(player, clicked, face, holding.clone(), clickedLoc, hand);
.rightClickBlock(player, clicked, face, holding.clone(), clickedLoc, hand);

return true;
}
Expand Down
44 changes: 44 additions & 0 deletions src/main/java/net/glowstone/entity/GlowEntity.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import net.glowstone.EventFactory;
import net.glowstone.GlowServer;
import net.glowstone.GlowWorld;
import net.glowstone.block.GlowBlock;
import net.glowstone.block.blocktype.BlockPortal;
import net.glowstone.chunk.GlowChunk;
import net.glowstone.entity.meta.MetadataIndex;
import net.glowstone.entity.meta.MetadataIndex.StatusFlags;
Expand Down Expand Up @@ -50,6 +52,7 @@
import org.bukkit.EntityEffect;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.TravelAgent;
import org.bukkit.World;
import org.bukkit.World.Environment;
import org.bukkit.block.Block;
Expand Down Expand Up @@ -291,6 +294,10 @@ public abstract class GlowEntity implements Entity {
@Getter
@Setter
private int portalCooldown;

@Getter
private boolean isInPortal;

/**
* Whether this entity has operator permissions.
*/
Expand Down Expand Up @@ -560,6 +567,9 @@ public void pulse() {
if (fireTicks > 0) {
--fireTicks;
}
if (portalCooldown > 0) {
--portalCooldown;
}
metadata.setBit(MetadataIndex.STATUS, StatusFlags.ON_FIRE, fireTicks > 0);

// resend position if it's been a while, causes ItemFrames to disappear and GlowPaintings
Expand Down Expand Up @@ -605,6 +615,40 @@ public void pulse() {
}
}
}
GlowBlock block = world.getBlockAt(location);
if (block.getType().equals(Material.PORTAL)
&& BlockPortal.getBoundingBox(block).intersects(boundingBox)) {
if (!isInPortal) {
heisluft marked this conversation as resolved.
Show resolved Hide resolved
EventFactory.getInstance().callEvent(
new EntityPortalEnterEvent(this, block.getLocation()));
isInPortal = true;
}
if (server.getAllowNether() && portalCooldown <= 0) {
GlowWorld w = getWorld().getEnvironment().equals(Environment.NETHER)
? server.getWorld("world") : server.getWorld("world_nether");
TravelAgent agent = w.getTravelAgent();
boolean destIsNether = w.getEnvironment().equals(Environment.NETHER);
int destX = destIsNether ? location.getBlockX() / 8 : location.getBlockX() * 8;
int destY = destIsNether ? location.getBlockY() / 8 : location.getBlockY() * 8;
int destZ = destIsNether ? location.getBlockZ() / 8 : location.getBlockZ() * 8;
Location requested = new Location(w, destX, destY, destZ);
if (agent.getCanCreatePortal() || agent.findPortal(requested) != null) {
Location teleportLocation = agent.findOrCreate(requested);
EntityPortalEvent p = EventFactory.getInstance().callEvent(
heisluft marked this conversation as resolved.
Show resolved Hide resolved
new EntityPortalEvent(this,
location.clone(), teleportLocation.clone(), agent));
if (!p.isCancelled()) {
teleport(p.getTo());
setPortalCooldown(300);
setVelocity(EventFactory.getInstance().callEvent(
new EntityPortalExitEvent(this, previousLocation,
location.clone(), velocity.clone(), new Vector())).getAfter());
}
}
}
} else {
isInPortal = false;
}

if (leashHolderUniqueId != null && ticksLived < 2) {
Optional<GlowEntity> any = world.getEntityManager().getAll().stream()
Expand Down