mmb.engine.block.BlockEntry Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of multimachinebuilder Show documentation
Show all versions of multimachinebuilder Show documentation
Dependency for the MultiMachineBuilder, a voxel game about building an industrial empire in a finite world.
THIS RELEASE IS NOT PLAYABLE. To play the game, donwload from >ITCH.IO LINK HERE< or >GH releases link here<
/**
*
*/
package mmb.engine.block;
import java.awt.Graphics;
import org.joml.Vector2d;
import mmb.NN;
import mmb.Nil;
import mmb.beans.Saver;
import mmb.content.electric.Electricity;
import mmb.content.ppipe.PipeTunnelEntry;
import mmb.engine.inv.Inventory;
import mmb.engine.inv.NoSuchInventory;
import mmb.engine.inv.io.InventoryReader;
import mmb.engine.inv.io.InventoryWriter;
import mmb.engine.rotate.Chiral;
import mmb.engine.rotate.ChiralRotation;
import mmb.engine.rotate.Chirality;
import mmb.engine.rotate.Rotable;
import mmb.engine.rotate.Rotation;
import mmb.engine.rotate.Side;
import mmb.engine.texture.BlockDrawer;
import mmb.engine.worlds.world.Player;
import mmb.engine.worlds.world.World;
/**
* @author oskar
* The following methods can be overridden:
* provideSignal -
*/
public interface BlockEntry extends Saver, Rotable, Chiral {
/** @return the block type */
@NN public BlockType type();
/**
* @param type block type to check
* @return does given type match actual type?
*/
public default boolean typeof(BlockType type) {
return type == type();
}
//Block I/O
/**
* Gets the electrical connection on this block
* @param s
* @return the electrical connection on given side.
*/
@Nil public default Electricity getElectricalConnection(Side s) {
return null;
}
/**
* @param s side, from which to get signal
* @return the WireWorld signal
*/
public default boolean provideSignal(Side s) {
return false;
}
/**
* @param s side, from which to get inventory
* @return inventory at given side
*/
@NN public default Inventory getInventory(Side s) {
return NoSuchInventory.INSTANCE;
}
/**
* @param s side, from which to get output
* @return inventory reader at given side
*/
@NN public default InventoryReader getOutput(Side s) {
return getInventory(s).createReader();
}
/**
* @param s side, from which to get input
* @return inventory writer at given side
*/
@NN public default InventoryWriter getInput(Side s) {
return getInventory(s).createWriter();
}
//Block events
/**
* Moves this block to a new map
* @param map new map (can be the same, or null if block goes off map)
* @param x X coordinate on a new map
* @param y Y coordinate on a new map
* @throws IllegalStateException if given map/position combination is not surface
*/
public void resetMap(@Nil World map, int x, int y); //should only be called by World
/**
* Called when world is initialized
*
Exception handling: If exception is thrown by this method, the block is not properly initialized
* @param map world, which is initialized
* @param x X coordinate of the block
* @param y Y coordinate of the block
*/
public default void onStartup(World map, int x, int y) {
//optional
}
/**
* Called just after world is initialized
*
Exception handling: If exception is thrown by this method, the block is not properly initialized
* @param map world, which is initialized
* @param x X coordinate of the block
* @param y Y coordinate of the block
*/
public default void postLoad(World map, int x, int y) {
//optional
}
/**
* Called when block is placed
*
Exception handling: If exception is thrown by this method, the block is not placed
* @param map world, in which the block is placed
* @param x X coordinate of the block
* @param y Y cordinate of the block
*/
public default void onPlace(World map, int x, int y) {
//optional
}
/**
* Called when block is broken
*
Exception handling: If exception is thrown by this method, the block is not broken
* @param map world, in which block is broken
* @param x X coordinate of the block
* @param y Y cordinate of the block
*/
public default void onBreak(World map, int x, int y) {
//optional
}
/**
* Called when world is closed
*
Exception handling: If exception is thrown by this method, the block is not properly closed
* @param map world, which is shutting down
*/
public default void onShutdown(World map) {
//optional
}
/**
* Renders a block
* @param x left X coordinate
* @param y upper Y coordinate
* @param g graphics context
* @param side side size
*/
public default void render(int x, int y, Graphics g, int side) {
BlockDrawer drawer = type().getTexture();
drawer.draw(this, x, y, g, side);
}
/**
* Prints debug information for use in debug menu
* @param sb string builder
*/
public default void debug(StringBuilder sb) {
//unused
}
/**
* Creates a block-wise copy of this block entry.
* The returned block entry may have position data attached,
* or it may be identical.
* @return a copy of this block
* @implSpec This method must not throw any exceptions
* @apiNote Used to copy blocks by world editing tools
*/
@NN public BlockEntry blockCopy();
//Rotations - rotary
/**
* Checks if given block supports rotations
* @return is given block rotable?
*/
public default boolean isRotary() {
return false;
}
@Override
default void setRotation(Rotation rotation) {
//does nothing
}
@Override
@NN default Rotation getRotation() {
return Rotation.N;
}
/** Rotates the block clockwise */
public default void wrenchCW() {
setRotation(getRotation().cw());
}
/** Rotates the block counter-clockwise */
public default void wrenchCCW() {
setRotation(getRotation().cw());
}
/**
* Wrenches the block in chirality's "right" direction
* @param chiral chirality to use
*/
public default void wrenchRight(Chirality chiral) {
setRotation(chiral.right(getRotation()));
}
/**
* Wrenches the block in chirality's "left" direction
* @param chiral chirality to use
*/
public default void wrenchLeft(Chirality chiral) {
setRotation(chiral.left(getRotation()));
}
//Rotations - chiral
/**
* Checks if given block is chiral
* @return is given block chiral?
*/
public default boolean isChiral() {
return false;
}
@Override
@NN default Chirality getChirality() {
return Chirality.R;
}
@Override
default void setChirality(Chirality chirality) {
//does nothing
}
/**
* Reverses the chirality of this block
*/
default void flip() {
setChirality(getChirality().reverse());
}
//Rotation - chirotation
default void setChirotation(ChiralRotation rotation) {
setRotation(rotation.rotation);
setChirality(rotation.chirality);
}
/** @return chirality and rotation of this block together */
@NN default ChiralRotation getChirotation() {
return ChiralRotation.of(getRotation(), getChirality());
}
/** Flips on | plane */
public default void flipH() {
setChirotation(getChirotation().flipH());
}
/** Flips on ― plane */
public default void flipV() {
setChirotation(getChirotation().flipV());
}
/** Flips on / plane */
public default void flipNE() {
setChirotation(getChirotation().flipNE());
}
/** Flips on \ plane*/
public default void flipNW() {
setChirotation(getChirotation().flipNW());
}
//Player collision
int FLAGS_COLLIDE_LEFT = 1;
int FLAGS_COLLIDE_RIGHT = 2;
int FLAGS_COLLIDE_UP = 4;
int FLAGS_COLLIDE_DOWN = 8;
int NO_COLLISION = 0;
int COLLIDE_ALL = 15;
/**
* Runs on player collision
* @param blockX the block's X position
* @param blockY the block's Y position
* @param world the world, in which the player resides
* @param player the player which collides with the block
*/
public default void onPlayerCollide(int blockX, int blockY, World world, Player player) {
if(!isSurface())
displaceFrom(blockX, blockY, blockX+1.0, blockY+1.0, player, true);
}
/**
* @return is this block entry surface?
*/
public default boolean isSurface() {
return type().isSurface();
}
/**
* @param x1
* @param y1
* @param x2
* @param y2
* @param player player to displace
* @param move TODO should player be moved
* @return rectangle collision: 0 if none, 1 if horizontal, 2 if vertical
*/
static int displaceFrom(double x1, double y1, double x2, double y2, Player player, boolean move) {
//Displace on X axis
double px1 = player.pos.x-0.3;
double py1 = player.pos.y-0.3;
double px2 = player.pos.x+0.3;
double py2 = player.pos.y+0.3;
Vector2d offset = new Vector2d();
int coll = displace(x1, y1, x2, y2, px1, py1, px2, py2, offset);
if(move) {
player.pos.add(offset);
if(coll == 1) {
player.speed.x = 0;
}
if(coll == 2) {
player.speed.y = 0;
}
}
return coll;
}
/**
* @param cx1 first X coordinate of the stationary rectangle
* @param cy1 first Y coordinate of the stationary rectangle
* @param cx2 second X coordinate of the stationary rectangle
* @param cy2 second Y coordinate of the stationary rectangle
* @param px1 first X coordinate of the movable rectangle
* @param py1 first Y coordinate of the movable rectangle
* @param px2 second X coordinate of the movable rectangle
* @param py2 second Y coordinate of the movable rectangle
* @param out the vector, which stores offset
* @return rectangle collision: 0 if none, 1 if horizontal, 2 if vertical
*/
static int displace(double cx1, double cy1, double cx2, double cy2, double px1, double py1, double px2, double py2, Vector2d out) {
double radCX = (cx2-cx1)/2;
double centerCX = (cx2+cx1)/2;
double radPX = (px2-px1)/2;
double centerPX = (px2+px1)/2;
double distX = Math.abs(centerPX-centerCX);
double infringeX = (radPX+radCX) - distX;
boolean colx = infringeX > 0;
double radCY = (cy2-cy1)/2;
double centerCY = (cy2+cy1)/2;
double radPY = (py2-py1)/2;
double centerPY = (py2+py1)/2;
double distY = Math.abs(centerPY-centerCY);
double infringeY = (radPY+radCY) - distY;
boolean coly = infringeY > 0;
boolean collide = colx && coly;
if(!collide)
return 0;
if(infringeX < infringeY) {
//displace horizontally
if(centerPX > centerCX) {
//displace right
out.x = infringeX;
}else{
//displace left
out.x = -infringeX;
}
return 1; //not working as expected
}
//displace vertically
if(centerPY > centerCY) {
//displace down
out.y = infringeY;
}else{
//displace up
out.y = -infringeY;
}
return 2;
}
//Pipe tunnels
/**
* Gets the pipe tunnel at given side
* @param s the side from which pipe enters
* @return the pipe tunnel entry for this pipe, or null if none
*/
public default PipeTunnelEntry getPipeTunnel(Side s) {
return null;
}
}