component, Direction direction) {
+ if (componentProvider.components instanceof SidedComponentMap) {
+ return ((SidedComponentMap) componentProvider.components).getOp(component, direction);
+ } else {
+ return componentProvider.components.getOp(component);
+ }
+ }
+}
diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/capability/forward/NovaCapabilityProvider.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/capability/forward/NovaCapabilityProvider.java
new file mode 100644
index 000000000..01b42ecec
--- /dev/null
+++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/capability/forward/NovaCapabilityProvider.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2017 NOVA, All rights reserved.
+ * This library is free software, licensed under GNU Lesser General Public License version 3
+ *
+ * This file is part of NOVA.
+ *
+ * NOVA is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * NOVA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with NOVA. If not, see .
+ */
+
+package nova.core.wrapper.mc.forge.v1_11_2.wrapper.capability.forward;
+
+import net.minecraft.util.EnumFacing;
+import net.minecraftforge.common.capabilities.Capability;
+import net.minecraftforge.common.capabilities.ICapabilityProvider;
+import nova.core.util.Direction;
+import nova.core.util.EnumSelector;
+import nova.core.wrapper.mc.forge.v1_11_2.wrapper.DirectionConverter;
+
+import java.util.Optional;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+/**
+ * @author ExE Boss
+ */
+public interface NovaCapabilityProvider extends ICapabilityProvider {
+
+ /**
+ * Determines if this object has support for the capability in question on the specific side.
+ * The return value of this might change during runtime if this object gains or looses support
+ * for a capability.
+ *
+ * Example:
+ * A Pipe getting a cover placed on one side causing it lose the
+ * {@link nova.core.component.inventory.Inventory} attachment function for that side.
+ *
+ * @param capability The capability to check.
+ * @param direction The Side to check from: @link nova.core.util.Direction.UNKNOWN UNKNOWN}
+ * is defined to represent 'internal' or 'self' or used for cases where side doesn't matter.
+ * @return True if this object supports the capability for this side.
+ */
+ boolean hasCapability(@Nonnull Capability> capability, @Nonnull Direction direction);
+
+ @Override
+ default boolean hasCapability(@Nonnull Capability> capability, @Nullable EnumFacing facing) {
+ return hasCapability(capability, DirectionConverter.instance().toNova(facing));
+ }
+
+ /**
+ * Retrieves the handler for the capability requested on the specific side.
+ * The return value is {@link Optional#empty()} when the object does not support the capability for the direction.
+ * The return value can be the same for multiple faces.
+ *
+ * @param capability The capability to check.
+ * @param direction The Side to check from: @link nova.core.util.Direction.UNKNOWN UNKNOWN}
+ * is defined to represent 'internal' or 'self' or used for cases where side doesn't matter.
+ * @param The capability type to check.
+ * @return The requested capability. Returns an empty optional when
+ * {@link #hasCapability(Capability, EnumFacing)} would return false.
+ */
+ @Nonnull
+ Optional getCapability(@Nonnull Capability capability, @Nonnull Direction direction);
+
+ @Override
+ @Nullable
+ default T getCapability(@Nonnull Capability capability, @Nullable EnumFacing facing) {
+ return getCapability(capability, DirectionConverter.instance().toNova(facing)).orElse(null);
+ }
+}
diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/cuboid/CuboidConverter.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/cuboid/CuboidConverter.java
new file mode 100644
index 000000000..864a99fc7
--- /dev/null
+++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/cuboid/CuboidConverter.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015 NOVA, All rights reserved.
+ * This library is free software, licensed under GNU Lesser General Public License version 3
+ *
+ * This file is part of NOVA.
+ *
+ * NOVA is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * NOVA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with NOVA. If not, see .
+ */
+
+package nova.core.wrapper.mc.forge.v1_11_2.wrapper.cuboid;
+
+import net.minecraft.util.math.AxisAlignedBB;
+import nova.core.nativewrapper.NativeConverter;
+import nova.core.util.shape.Cuboid;
+import nova.internal.core.Game;
+import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
+
+/**
+ * @author Calclavia
+ */
+public class CuboidConverter implements NativeConverter {
+
+ public static CuboidConverter instance() {
+ return Game.natives().getNative(Cuboid.class, AxisAlignedBB.class);
+ }
+
+ @Override
+ public Class getNovaSide() {
+ return Cuboid.class;
+ }
+
+ @Override
+ public Class getNativeSide() {
+ return AxisAlignedBB.class;
+ }
+
+ @Override
+ public Cuboid toNova(AxisAlignedBB aabb) {
+ return new Cuboid(new Vector3D(aabb.minX, aabb.minY, aabb.minZ), new Vector3D(aabb.maxX, aabb.maxY, aabb.maxZ));
+ }
+
+ @Override
+ public AxisAlignedBB toNative(Cuboid cuboid) {
+ return new AxisAlignedBB(cuboid.min.getX(), cuboid.min.getY(), cuboid.min.getZ(), cuboid.max.getX(), cuboid.max.getY(), cuboid.max.getZ());
+ }
+}
diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/data/DataConverter.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/data/DataConverter.java
new file mode 100644
index 000000000..6a66fc7f2
--- /dev/null
+++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/data/DataConverter.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2015 NOVA, All rights reserved.
+ * This library is free software, licensed under GNU Lesser General Public License version 3
+ *
+ * This file is part of NOVA.
+ *
+ * NOVA is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * NOVA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with NOVA. If not, see .
+ */
+
+package nova.core.wrapper.mc.forge.v1_11_2.wrapper.data;
+
+import net.minecraft.nbt.NBTBase;
+import net.minecraft.nbt.NBTTagByte;
+import net.minecraft.nbt.NBTTagByteArray;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.nbt.NBTTagDouble;
+import net.minecraft.nbt.NBTTagFloat;
+import net.minecraft.nbt.NBTTagInt;
+import net.minecraft.nbt.NBTTagIntArray;
+import net.minecraft.nbt.NBTTagLong;
+import net.minecraft.nbt.NBTTagShort;
+import net.minecraft.nbt.NBTTagString;
+import nova.core.nativewrapper.NativeConverter;
+import nova.core.retention.Data;
+import nova.internal.core.Game;
+
+import java.util.Optional;
+import java.util.Set;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+/**
+ * Utility that manages common NBT queueSave and load methods
+ * @author Calclavia
+ */
+public class DataConverter implements NativeConverter {
+
+ public static DataConverter instance() {
+ return Game.natives().getNative(Data.class, NBTTagCompound.class);
+ }
+
+ @Override
+ public Class getNovaSide() {
+ return Data.class;
+ }
+
+ @Override
+ public Class getNativeSide() {
+ return NBTTagCompound.class;
+ }
+
+ @Override
+ @Nonnull
+ public Data toNova(@Nullable NBTTagCompound nbt) {
+ Data data = new Data();
+ if (nbt != null) {
+ data.className = nbt.getString("class");
+ Set keys = nbt.getKeySet();
+ keys.stream()
+ .filter(k -> k != null && !"class".equals(k))
+ .filter(Data.ILLEGAL_SUFFIX.asPredicate().negate())
+ .forEach(k -> Optional.ofNullable(load(nbt, k)).ifPresent(v -> data.put(k, v)));
+ }
+ return data;
+ }
+
+ @Override
+ @Nullable
+ public NBTTagCompound toNative(@Nullable Data data) {
+ if (data == null) {
+ return null;
+ }
+
+ return toNative(new NBTTagCompound(), data);
+ }
+
+ @Nonnull
+ public NBTTagCompound toNative(@Nonnull NBTTagCompound nbt, @Nonnull Data data) {
+ if (data.className != null) {
+ nbt.setString("class", data.className);
+ }
+ data.forEach((k, v) -> save(nbt, k, v));
+ return nbt;
+ }
+
+ /**
+ * Saves an unknown object to NBT
+ * @param tag - NBTTagCompound to queueSave the tag too
+ * @param key - name to queueSave the object as
+ * @param value - the actual object
+ * @return the tag when done saving too i
+ */
+ @Nonnull
+ public NBTTagCompound save(@Nonnull NBTTagCompound tag, @Nonnull String key, @Nullable Object value) {
+ if (value instanceof Boolean) {
+ tag.setBoolean("isBoolean", true);
+ tag.setBoolean(key, (boolean) value);
+ } else if (value instanceof Byte) {
+ tag.setBoolean("isBoolean", false);
+ tag.setByte(key, (byte) value);
+ } else if (value instanceof Short) {
+ tag.setShort(key, (short) value);
+ } else if (value instanceof Integer) {
+ tag.setInteger(key, (int) value);
+ } else if (value instanceof Long) {
+ tag.setLong(key, (long) value);
+ } else if (value instanceof Character) {
+ tag.setInteger(key, (Character) value);
+ } else if (value instanceof Float) {
+ tag.setFloat(key, (float) value);
+ } else if (value instanceof Double) {
+ tag.setDouble(key, (double) value);
+ } else if (value instanceof String) {
+ tag.setString(key, (String) value);
+ } else if (value instanceof Data) {
+ NBTTagCompound innerTag = new NBTTagCompound();
+ toNative(innerTag, (Data) value);
+ tag.setTag(key, innerTag);
+ }
+ return tag;
+ }
+
+ /**
+ * Reads an unknown object withPriority a known name from NBT
+ * @param tag - tag to read the value from
+ * @param key - name of the value
+ * @return object or suggestionValue if nothing is found
+ */
+ @Nullable
+ public Object load(@Nullable NBTTagCompound tag, @Nullable String key) {
+ if (tag != null && key != null) {
+ NBTBase saveTag = tag.getTag(key);
+
+ if (saveTag instanceof NBTTagFloat) {
+ return tag.getFloat(key);
+ } else if (saveTag instanceof NBTTagDouble) {
+ return tag.getDouble(key);
+ } else if (saveTag instanceof NBTTagInt) {
+ return tag.getInteger(key);
+ } else if (saveTag instanceof NBTTagString) {
+ return tag.getString(key);
+ } else if (saveTag instanceof NBTTagShort) {
+ return tag.getShort(key);
+ } else if (saveTag instanceof NBTTagByte) {
+ if (tag.getBoolean("isBoolean")) {
+ return tag.getBoolean(key);
+ } else {
+ return tag.getByte(key);
+ }
+ } else if (saveTag instanceof NBTTagLong) {
+ return tag.getLong(key);
+ } else if (saveTag instanceof NBTTagByteArray) {
+ return tag.getByteArray(key);
+ } else if (saveTag instanceof NBTTagIntArray) {
+ return tag.getIntArray(key);
+ } else if (saveTag instanceof NBTTagCompound) {
+ NBTTagCompound innerTag = tag.getCompoundTag(key);
+ return toNova(innerTag);
+ }
+ }
+ return null;
+ }
+}
diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/data/NBTStorable.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/data/NBTStorable.java
new file mode 100644
index 000000000..5df63de31
--- /dev/null
+++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/data/NBTStorable.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2017 NOVA, All rights reserved.
+ * This library is free software, licensed under GNU Lesser General Public License version 3
+ *
+ * This file is part of NOVA.
+ *
+ * NOVA is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * NOVA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with NOVA. If not, see .
+ */
+
+package nova.core.wrapper.mc.forge.v1_11_2.wrapper.data;
+
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraftforge.common.util.INBTSerializable;
+import nova.core.retention.Data;
+import nova.core.retention.Storable;
+
+/**
+ * @author ExE Boss
+ */
+public interface NBTStorable extends Storable, INBTSerializable {
+
+ @Override
+ default NBTTagCompound serializeNBT() {
+ Data data = new Data();
+ save(data);
+ return DataConverter.instance().toNative(data);
+ }
+
+ @Override
+ default void deserializeNBT(NBTTagCompound nbt) {
+ load(DataConverter.instance().toNova(nbt));
+ }
+}
diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/entity/EntityConverter.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/entity/EntityConverter.java
new file mode 100644
index 000000000..a08eac203
--- /dev/null
+++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/entity/EntityConverter.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2015 NOVA, All rights reserved.
+ * This library is free software, licensed under GNU Lesser General Public License version 3
+ *
+ * This file is part of NOVA.
+ *
+ * NOVA is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * NOVA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with NOVA. If not, see .
+ */
+
+package nova.core.wrapper.mc.forge.v1_11_2.wrapper.entity;
+
+import net.minecraft.util.EnumParticleTypes;
+import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
+import net.minecraftforge.fml.relauncher.Side;
+import net.minecraftforge.fml.relauncher.SideOnly;
+import nova.core.entity.Entity;
+import nova.core.entity.EntityFactory;
+import nova.core.nativewrapper.NativeConverter;
+import nova.core.wrapper.mc.forge.v1_11_2.launcher.ForgeLoadable;
+import nova.core.wrapper.mc.forge.v1_11_2.wrapper.entity.backward.BWEntity;
+import nova.core.wrapper.mc.forge.v1_11_2.wrapper.entity.forward.FWEntity;
+import nova.core.wrapper.mc.forge.v1_11_2.wrapper.entity.forward.MCEntityTransform;
+import nova.core.wrapper.mc.forge.v1_11_2.wrapper.particle.backward.BWParticle;
+import nova.internal.core.Game;
+
+import java.util.Optional;
+
+public class EntityConverter implements NativeConverter, ForgeLoadable {
+
+ public static EntityConverter instance() {
+ return Game.natives().getNative(Entity.class, net.minecraft.entity.Entity.class);
+ }
+
+ @Override
+ public Class getNovaSide() {
+ return Entity.class;
+ }
+
+ @Override
+ public Class getNativeSide() {
+ return net.minecraft.entity.Entity.class;
+ }
+
+ @Override
+ public Entity toNova(net.minecraft.entity.Entity mcEntity) {
+ //Prevents dual wrapping
+ if (mcEntity instanceof FWEntity) {
+ return ((FWEntity) mcEntity).getWrapped();
+ }
+
+ //TODO: Make this BWRegistry non-lazy
+ //Lazy registry
+ String id = mcEntity.getClass().getName();
+ Optional entityFactory = Game.entities().get(id);
+
+ if (entityFactory.isPresent()) {
+ return entityFactory.get().build();
+ } else {
+ return Game.entities().register(id, () -> new BWEntity(mcEntity)).build();
+ }
+ }
+
+ @Override
+ public net.minecraft.entity.Entity toNative(Entity novaObj) {
+ MCEntityTransform transform = novaObj.components.get(MCEntityTransform.class);
+
+ if (transform.wrapper instanceof FWEntity) {
+ return transform.wrapper;
+ }
+
+ throw new IllegalArgumentException("Entity wrapper is invalid (where did this object come from?)");
+ }
+
+ @Override
+ @SideOnly(Side.CLIENT)
+ public void preInit(FMLPreInitializationEvent evt) {
+ /**
+ * Backward register all particle effects
+ */
+ //Look up for particle factory and pass it into BWParticle
+ for (EnumParticleTypes type : EnumParticleTypes.values()) {
+ Game.entities().register(Game.info().name + ":" + type.getParticleName(), () -> new BWParticle(type.getParticleID()));
+ }
+ }
+}
\ No newline at end of file
diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/entity/backward/BWEntity.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/entity/backward/BWEntity.java
new file mode 100644
index 000000000..230601d04
--- /dev/null
+++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/entity/backward/BWEntity.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2015 NOVA, All rights reserved.
+ * This library is free software, licensed under GNU Lesser General Public License version 3
+ *
+ * This file is part of NOVA.
+ *
+ * NOVA is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * NOVA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with NOVA. If not, see .
+ */
+
+package nova.core.wrapper.mc.forge.v1_11_2.wrapper.entity.backward;
+
+import net.minecraft.entity.EntityLivingBase;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.util.DamageSource;
+import nova.core.component.inventory.InventoryPlayer;
+import nova.core.component.misc.Damageable;
+import nova.core.entity.Entity;
+import nova.core.entity.component.Living;
+import nova.core.entity.component.Player;
+import nova.core.wrapper.mc.forge.v1_11_2.util.WrapperEvent;
+import nova.core.wrapper.mc.forge.v1_11_2.wrapper.entity.forward.MCEntityTransform;
+import nova.core.wrapper.mc.forge.v1_11_2.wrapper.inventory.BWInventory;
+import nova.internal.core.Game;
+import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
+
+/**
+ * A Minecraft to NOVA Entity wrapper
+ * @author Calclavia
+ */
+//TODO: Incomplete. Add more components!
+public class BWEntity extends Entity {
+
+ public net.minecraft.entity.Entity entity;
+
+ public BWEntity(net.minecraft.entity.Entity entity) {
+ this.entity = entity;
+
+ components.add(new MCEntityTransform(entity));
+ components.add(new Damageable() {
+ @Override
+ public void damage(double amount, DamageType type) {
+ if (type == DamageType.generic) {
+ entity.attackEntityFrom(DamageSource.GENERIC, (float) amount);
+ }
+ // TODO: Apply other damage source wrappers?
+ }
+ });
+
+ if (entity instanceof EntityLivingBase) {
+ if (entity instanceof EntityPlayer) {
+ MCPlayer player = components.add(new MCPlayer(this));
+ player.faceDisplacement = () -> Vector3D.PLUS_J.scalarMultiply(entity.getEyeHeight());
+ } else {
+ Living living = components.add(new Living());
+ living.faceDisplacement = () -> Vector3D.PLUS_J.scalarMultiply(entity.getEyeHeight());
+ }
+ }
+
+ WrapperEvent.BWEntityCreate event = new WrapperEvent.BWEntityCreate(this, entity);
+ Game.events().publish(event);
+ }
+
+ public static class MCPlayer extends Player {
+ public final BWEntity bwEntity;
+ public final EntityPlayer entity;
+ public final BWInventoryPlayer inventory;
+
+ public MCPlayer(BWEntity bwEntity) {
+ this.bwEntity = bwEntity;
+ this.entity = (EntityPlayer) bwEntity.entity;
+ this.inventory = new BWInventoryPlayer(entity);
+ }
+
+ @Override
+ public Entity entity() {
+ return bwEntity;
+ }
+
+ @Override
+ public String getUniqueID() {
+ return entity.getGameProfile().getId().toString();
+ }
+
+ @Override
+ public InventoryPlayer getInventory() {
+ return inventory;
+ }
+
+ @Override
+ public String getUsername() {
+ return entity.getGameProfile().getName();
+ }
+
+ @Override
+ public String getDisplayName() {
+ return entity.getDisplayName().getUnformattedText();
+ }
+ }
+
+ public static class BWInventoryPlayer extends BWInventory implements InventoryPlayer {
+ public final EntityPlayer entity;
+
+ public BWInventoryPlayer(EntityPlayer entity) {
+ super(entity.inventory);
+ this.entity = entity;
+ }
+
+ @Override
+ public int getHeldSlot() {
+ return entity.inventory.currentItem;
+ }
+ }
+}
diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/entity/forward/BWRigidBody.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/entity/forward/BWRigidBody.java
new file mode 100644
index 000000000..9a74e0df4
--- /dev/null
+++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/entity/forward/BWRigidBody.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2015 NOVA, All rights reserved.
+ * This library is free software, licensed under GNU Lesser General Public License version 3
+ *
+ * This file is part of NOVA.
+ *
+ * NOVA is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * NOVA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with NOVA. If not, see .
+ */
+
+package nova.core.wrapper.mc.forge.v1_11_2.wrapper.entity.forward;
+
+import net.minecraft.entity.MoverType;
+import nova.core.entity.Entity;
+import nova.core.entity.component.RigidBody;
+import nova.core.util.math.RotationUtil;
+import nova.core.util.math.Vector3DUtil;
+import org.apache.commons.math3.geometry.euclidean.threed.Rotation;
+import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
+
+/**
+ * Based on the Euler Integration because Minecraft stores the following values:
+ *
+ * Position
+ * Velocity
+ * @author Calclavia
+ */
+public class BWRigidBody extends RigidBody {
+ private double mass = 1;
+
+ /**
+ * Translation
+ */
+ private double drag = 0;
+
+ private Vector3D gravity = new Vector3D(0, -9.81, 0);
+
+ /**
+ * Rotation
+ */
+ private double angularDrag = 0;
+ private Rotation angularVelocity = Rotation.IDENTITY;
+
+ /**
+ * Translation
+ */
+ private Vector3D netForce = Vector3D.ZERO;
+
+ /**
+ * Rotation
+ */
+ private Vector3D netTorque = Vector3D.ZERO;
+
+ private net.minecraft.entity.Entity mcEntity() {
+ return getProvider().components.get(MCEntityTransform.class).wrapper;
+ }
+
+ private Entity entity() {
+ return (Entity) getProvider();
+ }
+
+ @Override
+ public void update(double deltaTime) {
+ updateTranslation(deltaTime);
+ updateRotation(deltaTime);
+ }
+
+ void updateTranslation(double deltaTime) {
+ //Integrate velocity to displacement
+ Vector3D displacement = velocity().scalarMultiply(deltaTime);
+ mcEntity().move(MoverType.SELF, displacement.getX(), displacement.getY(), displacement.getZ());
+
+ //Integrate netForce to velocity
+ setVelocity(velocity().add(netForce.scalarMultiply(1 / mass()).scalarMultiply(deltaTime)));
+
+ //Clear net force
+ netForce = Vector3D.ZERO;
+
+ //Apply drag
+ addForce(velocity().negate().scalarMultiply(drag()));
+ if (!mcEntity().onGround) {
+ //Apply gravity
+ addForce(gravity().scalarMultiply(mass()));
+ }
+ }
+
+ void updateRotation(double deltaTime) {
+
+ //Integrate angular velocity to angular displacement
+ Rotation angularVel = angularVelocity();
+ Rotation deltaRotation = RotationUtil.slerp(Rotation.IDENTITY, angularVel, deltaTime);
+ entity().transform().setRotation(entity().rotation().applyTo(deltaRotation));
+
+ //Integrate torque to angular velocity
+ Vector3D torque = netTorque.scalarMultiply(deltaTime);
+ if (!Vector3D.ZERO.equals(torque)) {
+ setAngularVelocity(angularVelocity().applyTo(new Rotation(Vector3DUtil.FORWARD, torque)));
+ }
+
+ //Clear net torque
+ netTorque = Vector3D.ZERO;
+
+ //Apply drag
+ Vector3D eulerAngularVel = angularVelocity().applyInverseTo(Vector3DUtil.FORWARD);
+ addTorque(eulerAngularVel.negate().scalarMultiply(angularDrag()));
+ }
+
+ @Override
+ public Vector3D getVelocity() {
+ return new Vector3D(mcEntity().motionX, mcEntity().motionY, mcEntity().motionZ);
+ }
+
+ @Override
+ public void setVelocity(Vector3D velocity) {
+ mcEntity().motionX = velocity.getX();
+ mcEntity().motionY = velocity.getY();
+ mcEntity().motionZ = velocity.getZ();
+ }
+
+ @Override
+ public void addForce(Vector3D force, Vector3D position) {
+ //TODO: implement
+ }
+
+ @Override
+ public void addTorque(Vector3D torque) {
+ //TODO: implement
+ }
+
+ @Override
+ public void addForce(Vector3D force) {
+ netForce = netForce.add(force.scalarMultiply(1 / mass()));
+ }
+
+ /**
+ * Mass in kilograms. Default is 1 kg.
+ */
+ @Override
+ public double getMass() {
+ return mass;
+ }
+
+ @Override
+ public void setMass(double mass) {
+ this.mass = mass;
+ }
+
+ @Override
+ public double getDrag() {
+ return drag;
+ }
+
+ @Override
+ public void setDrag(double drag) {
+ this.drag = drag;
+ }
+
+ /**
+ * Gravity is an acceleration.
+ */
+ @Override
+ public Vector3D getGravity() {
+ return gravity;
+ }
+
+ @Override
+ public void setGravity(Vector3D gravity) {
+ this.gravity = gravity;
+ }
+
+ /**
+ * Rotation Methods
+ */
+ @Override
+ public double getAngularDrag() {
+ return angularDrag;
+ }
+
+ @Override
+ public void setAngularDrag(double angularDrag) {
+ this.angularDrag = angularDrag;
+ }
+
+ @Override
+ public Rotation getAngularVelocity() {
+ return angularVelocity;
+ }
+
+ @Override
+ public void setAngularVelocity(Rotation angularVelocity) {
+ this.angularVelocity = angularVelocity;
+ }
+}
diff --git a/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/entity/forward/FWEntity.java b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/entity/forward/FWEntity.java
new file mode 100644
index 000000000..fd8cebded
--- /dev/null
+++ b/minecraft/1.11.2/src/main/java/nova/core/wrapper/mc/forge/v1_11_2/wrapper/entity/forward/FWEntity.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2015 NOVA, All rights reserved.
+ * This library is free software, licensed under GNU Lesser General Public License version 3
+ *
+ * This file is part of NOVA.
+ *
+ * NOVA is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * NOVA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with NOVA. If not, see .
+ */
+
+package nova.core.wrapper.mc.forge.v1_11_2.wrapper.entity.forward;
+
+import io.netty.buffer.ByteBuf;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.util.EnumFacing;
+import net.minecraft.world.World;
+import net.minecraftforge.common.capabilities.Capability;
+import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
+import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData;
+import net.minecraftforge.items.CapabilityItemHandler;
+import nova.core.block.Stateful;
+import nova.core.component.Updater;
+import nova.core.component.misc.Collider;
+import nova.core.component.transform.EntityTransform;
+import nova.core.entity.Entity;
+import nova.core.entity.EntityFactory;
+import nova.core.retention.Data;
+import nova.core.retention.Storable;
+import nova.core.util.Direction;
+import nova.core.util.shape.Cuboid;
+import nova.core.wrapper.mc.forge.v1_11_2.util.WrapperEvent;
+import nova.core.wrapper.mc.forge.v1_11_2.wrapper.DirectionConverter;
+import nova.core.wrapper.mc.forge.v1_11_2.wrapper.capability.forward.NovaCapabilityProvider;
+import nova.core.wrapper.mc.forge.v1_11_2.wrapper.cuboid.CuboidConverter;
+import nova.core.wrapper.mc.forge.v1_11_2.wrapper.data.DataConverter;
+import nova.internal.core.Game;
+
+import java.util.Optional;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+/**
+ * Entity wrapper
+ * @author Calclavia
+ */
+public class FWEntity extends net.minecraft.entity.Entity implements IEntityAdditionalSpawnData, NovaCapabilityProvider {
+
+ protected final EntityTransform transform;
+ protected Entity wrapped;
+ boolean firstTick = true;
+
+ public FWEntity(World worldIn) {
+ super(worldIn);
+ this.transform = new MCEntityTransform(this);
+ }
+
+ public FWEntity(World world, EntityFactory factory) {
+ this(world);
+ setWrapped(factory.build());
+ entityInit();
+ }
+
+ @Override
+ protected void readEntityFromNBT(NBTTagCompound nbt) {
+ if (wrapped instanceof Storable) {
+ ((Storable) wrapped).load(DataConverter.instance().toNova(nbt));
+ }
+ if (wrapped == null) {
+ //This entity was saved to disk.
+ setWrapped(Game.entities().get(nbt.getString("novaID")).get().build());
+ }
+ }
+
+ @Override
+ protected void writeEntityToNBT(NBTTagCompound nbt) {
+ if (wrapped instanceof Storable) {
+ Data data = new Data();
+ ((Storable) wrapped).save(data);
+ DataConverter.instance().toNative(nbt, data);
+ }
+ nbt.setString("novaID", wrapped.getID());
+ }
+
+ @Override
+ public void writeSpawnData(ByteBuf buffer) {
+ //Write the ID of the entity to client
+ String id = wrapped.getID();
+ char[] chars = id.toCharArray();
+ buffer.writeInt(chars.length);
+
+ for (char c : chars)
+ buffer.writeChar(c);
+ }
+
+ @Override
+ public void readSpawnData(ByteBuf buffer) {
+ //Load the client ID
+ String id = "";
+ int length = buffer.readInt();
+ for (int i = 0; i < length; i++)
+ id += buffer.readChar();
+
+ setWrapped(Game.entities().get(id).get().build());
+ }
+
+ public Entity getWrapped() {
+ return wrapped;
+ }
+
+ private void setWrapped(Entity wrapped) {
+ this.wrapped = wrapped;
+ wrapped.components.add(transform);
+ }
+
+ public EntityTransform getTransform() {
+ return transform;
+ }
+
+ /**
+ * All methods below here are exactly the same between FWEntity and FWEntityFX.
+ * *****************************************************************************
+ */
+ @Override
+ protected void entityInit() {
+ //MC calls entityInit() before we finish wrapping, so this variable is required to check if wrapped exists.
+ if (wrapped != null) {
+ wrapped.events.publish(new Stateful.LoadEvent());
+ updateCollider();
+ WrapperEvent.FWEntityCreate event = new WrapperEvent.FWEntityCreate(wrapped, this);
+ Game.events().publish(event);
+ }
+ }
+
+ @Override
+ public void onUpdate() {
+ if (wrapped != null) {
+ if (firstTick) {
+ prevPosX = posX;
+ prevPosY = posY;
+ prevPosZ = posZ;
+ setPosition(posX, posY, posZ);
+ firstTick = false;
+ }
+
+ //onEntityUpdate();
+
+ double deltaTime = 0.05;
+
+ if (wrapped instanceof Updater) {
+ ((Updater) wrapped).update(deltaTime);
+ }
+
+ updateCollider();
+
+ /**
+ * Update all components in the entity.
+ */
+ wrapped.components()
+ .stream()
+ .filter(component -> component instanceof Updater)
+ .forEach(component -> ((Updater) component).update(deltaTime));
+ } else {
+ Game.logger().error("Ticking entity without wrapped entity object.");
+ }
+ }
+
+ /**
+ * Wraps the entity collider values
+ */
+ public void updateCollider() {
+ //Wrap entity collider
+ if (wrapped.components.has(Collider.class)) {
+ Collider collider = wrapped.components.get(Collider.class);
+
+ //Transform cuboid based on entity.
+ Cuboid size = collider
+ .boundingBox
+ .get();
+ ///.scalarMultiply(transform.scale());
+
+ setBounds(size);
+ }
+ }
+
+ @Override
+ protected void setSize(float width, float height) {
+ if (width != this.width || height != this.height) {
+ this.width = width;
+ this.height = height;
+ setBounds(new Cuboid(-width / 2, -height / 2, -width / 2, width / 2, height / 2, width / 2));
+ }
+ }
+
+ @Override
+ public void setPosition(double x, double y, double z) {
+ this.posX = x;
+ this.posY = y;
+ this.posZ = z;
+ //Reset the bounding box
+ Optional.ofNullable(getCollisionBoundingBox())
+ .map(CuboidConverter.instance()::toNova)
+ .ifPresent(this::setBounds);
+ }
+
+ /**
+ * Sets the bounding box of the entity based on NOVA cuboid bounds
+ * @param bounds NOVA Cuboid bounds
+ */
+ public void setBounds(Cuboid bounds) {
+ //TODO: Fix moveEntity auto-centering
+ Optional.ofNullable(transform)
+ .map(EntityTransform::position)
+ .map(bounds::add)
+ .map(CuboidConverter.instance()::toNative)
+ .ifPresent(this::setEntityBoundingBox);
+ }
+
+ @Override
+ public void setDead() {
+ wrapped.events.publish(new Stateful.UnloadEvent());
+ super.setDead();
+ }
+
+ @Override
+ public boolean hasCapability(Capability> capability, Direction direction) {
+ if (capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) {
+// return
+// wrapped.components.has(FluidProvider.class) ||
+// wrapped.components.has(FluidConsumer.class) ||
+// wrapped.components.has(FluidHandler.class) ||
+// wrapped instanceof SidedTankProvider;
+ } else if (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) {
+ return false; // TODO: implement
+ }
+
+ return false;
+ }
+
+ @Override
+ public boolean hasCapability(@Nonnull Capability> capability, @Nullable EnumFacing facing) {
+ return hasCapability(capability, DirectionConverter.instance().toNova(facing)) || super.hasCapability(capability, facing);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Optional