NoCheatPlus/NCPCompatNonFree/NCPCompatCBDev/src/main/java/fr/neatmonster/nocheatplus/compat/cbdev/MCAccessCBDev.java

279 lines
11 KiB
Java

/*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.neatmonster.nocheatplus.compat.cbdev;
import java.lang.reflect.Method;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.command.CommandMap;
import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import fr.neatmonster.nocheatplus.compat.AlmostBoolean;
import fr.neatmonster.nocheatplus.compat.MCAccess;
import fr.neatmonster.nocheatplus.utilities.ReflectionUtil;
import fr.neatmonster.nocheatplus.utilities.location.LocUtil;
import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
import net.minecraft.server.v1_12_R1.AxisAlignedBB;
import net.minecraft.server.v1_12_R1.Block;
import net.minecraft.server.v1_12_R1.BlockPosition;
import net.minecraft.server.v1_12_R1.DamageSource;
import net.minecraft.server.v1_12_R1.EntityComplexPart;
import net.minecraft.server.v1_12_R1.EntityPlayer;
import net.minecraft.server.v1_12_R1.IBlockAccess;
import net.minecraft.server.v1_12_R1.IBlockData;
import net.minecraft.server.v1_12_R1.MobEffectList;
public class MCAccessCBDev implements MCAccess {
private final MobEffectList JUMP;
private final MobEffectList FASTER_MOVEMENT;
/**
* Test for availability in constructor.
*/
public MCAccessCBDev() {
// try {
getCommandMap();
Method blockGetAABB = ReflectionUtil.getMethod(Block.class, "b", IBlockData.class, IBlockAccess.class, BlockPosition.class);
if (blockGetAABB.getReturnType() != AxisAlignedBB.class
|| !blockGetAABB.isAnnotationPresent(Deprecated.class)) {
throw new RuntimeException();
}
if (ReflectionUtil.getConstructor(BlockPosition.class, int.class, int.class, int.class) == null) {
throw new RuntimeException();
}
ReflectionUtil.checkMethodReturnTypesNoArgs(net.minecraft.server.v1_12_R1.EntityLiving.class,
new String[]{"getHeadHeight"}, float.class);
ReflectionUtil.checkMethodReturnTypesNoArgs(net.minecraft.server.v1_12_R1.EntityPlayer.class,
new String[]{"getHealth"}, float.class);
ReflectionUtil.checkMembers(net.minecraft.server.v1_12_R1.AxisAlignedBB.class, double.class,
"a", "b", "c", "d", "e", "f");
ReflectionUtil.checkMethodReturnTypesNoArgs(net.minecraft.server.v1_12_R1.AttributeInstance.class,
new String[]{"b"}, double.class);
ReflectionUtil.checkMethodReturnTypesNoArgs(net.minecraft.server.v1_12_R1.AttributeModifier.class,
new String[]{"c"}, int.class);
ReflectionUtil.checkMethodReturnTypesNoArgs(net.minecraft.server.v1_12_R1.AttributeModifier.class,
new String[]{"d"}, double.class);
ReflectionUtil.checkMethodReturnTypesNoArgs(net.minecraft.server.v1_12_R1.Material.class,
new String[]{"isSolid", "isLiquid"}, boolean.class);
// TODO: Confine the following by types as well.
ReflectionUtil.checkMembers("net.minecraft.server.v1_12_R1.",
new String[] {"Entity" , "length", "width", "locY"});
ReflectionUtil.checkMembers("net.minecraft.server.v1_12_R1.",
new String[] {"EntityPlayer" , "dead", "deathTicks", "invulnerableTicks"});
// obc: getHandle() for CraftWorld, CraftPlayer, CraftEntity.
// nms: Several: AxisAlignedBB, WorldServer
// nms: Block.getById(int), BlockPosition(int, int, int), WorldServer.getEntities(Entity, AxisAlignedBB)
// nms: AttributeInstance.a(UUID), EntityComplexPart, EntityPlayer.getAttributeInstance(IAttribute).
// } catch(Throwable t) {
// NCPAPIProvider.getNoCheatPlusAPI().getLogManager().severe(Streams.INIT, t);
// throw new RuntimeException("NO WERK");
// }
JUMP = MobEffectList.getByName("jump_boost");
if (JUMP == null) {
throw new RuntimeException();
}
FASTER_MOVEMENT = MobEffectList.getByName("speed");
if (FASTER_MOVEMENT == null) {
throw new RuntimeException();
}
}
@Override
public String getMCVersion() {
// 1.12 (1_12_R1)
return "1.12-1.12.2";
}
@Override
public String getServerVersionTag() {
return "Spigot-CB-1.12_R1";
}
@Override
public CommandMap getCommandMap() {
return ((CraftServer) Bukkit.getServer()).getCommandMap();
}
@Override
public BlockCache getBlockCache() {
return getBlockCache(null);
}
@Override
public BlockCache getBlockCache(final World world) {
return new BlockCacheCBDev(world);
}
@Override
public double getHeight(final Entity entity) {
// (entity.getHeight() returns the length field, but we access nms anyway.)
final net.minecraft.server.v1_12_R1.Entity mcEntity = ((CraftEntity) entity).getHandle();
final AxisAlignedBB boundingBox = mcEntity.getBoundingBox();
final double entityHeight = Math.max(mcEntity.length, Math.max(mcEntity.getHeadHeight(), boundingBox.e - boundingBox.b));
if (entity instanceof LivingEntity) {
return Math.max(((LivingEntity) entity).getEyeHeight(), entityHeight);
} else {
return entityHeight;
}
}
private net.minecraft.server.v1_12_R1.Material getMaterial(int blockId) {
final Block block = Block.getById(blockId);
if (block == null) {
return null;
}
// (Currently no update state, since we don't have any position.)
return block.getBlockData().getMaterial();
}
@Override
public AlmostBoolean isBlockSolid(final Material id) {
@SuppressWarnings("deprecation")
final net.minecraft.server.v1_12_R1.Material material = getMaterial(id.getId());
if (material == null) {
return AlmostBoolean.MAYBE;
}
else {
return AlmostBoolean.match(material.isSolid());
}
}
@Override
public AlmostBoolean isBlockLiquid(final Material id) {
@SuppressWarnings("deprecation")
final net.minecraft.server.v1_12_R1.Material material = getMaterial(id.getId());
if (material == null) {
return AlmostBoolean.MAYBE;
}
else {
return AlmostBoolean.match(material.isLiquid());
}
}
@Override
public double getWidth(final Entity entity) {
return ((CraftEntity) entity).getHandle().width;
}
@Override
public AlmostBoolean isIllegalBounds(final Player player) {
final EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
if (entityPlayer.dead) {
return AlmostBoolean.NO;
}
// TODO: Does this need a method call for the "real" box? Might be no problem during moving events, though.
final AxisAlignedBB box = entityPlayer.getBoundingBox();
if (LocUtil.isBadCoordinate(box.a, box.b, box.c, box.d, box.e, box.f)) {
return AlmostBoolean.YES;
}
if (!entityPlayer.isSleeping()) {
// This can not really test stance but height of bounding box.
final double dY = Math.abs(box.e - box.b);
if (dY > 1.8) {
return AlmostBoolean.YES; // dY > 1.65D ||
}
if (dY < 0.1D && entityPlayer.length >= 0.1) {
return AlmostBoolean.YES;
}
}
return AlmostBoolean.MAYBE;
}
@Override
public double getJumpAmplifier(final Player player) {
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
if (mcPlayer.hasEffect(JUMP)) {
return mcPlayer.getEffect(JUMP).getAmplifier();
}
else {
return Double.NEGATIVE_INFINITY;
}
}
@Override
public double getFasterMovementAmplifier(final Player player) {
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
if (mcPlayer.hasEffect(FASTER_MOVEMENT)) {
return mcPlayer.getEffect(FASTER_MOVEMENT).getAmplifier();
}
else {
return Double.NEGATIVE_INFINITY;
}
}
@Override
public int getInvulnerableTicks(final Player player) {
return ((CraftPlayer) player).getHandle().invulnerableTicks;
}
@Override
public void setInvulnerableTicks(final Player player, final int ticks) {
((CraftPlayer) player).getHandle().invulnerableTicks = ticks;
}
@Override
public void dealFallDamage(final Player player, final double damage) {
((CraftPlayer) player).getHandle().damageEntity(DamageSource.FALL, (float) damage);
}
@Override
public boolean isComplexPart(final Entity entity) {
return ((CraftEntity) entity).getHandle() instanceof EntityComplexPart;
}
@Override
public boolean shouldBeZombie(final Player player) {
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
return !mcPlayer.dead && mcPlayer.getHealth() <= 0.0f ;
}
@Override
public void setDead(final Player player, final int deathTicks) {
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
mcPlayer.deathTicks = deathTicks;
mcPlayer.dead = true;
}
@Override
public boolean hasGravity(final Material mat) {
return mat.hasGravity();
}
@Override
public AlmostBoolean dealFallDamageFiresAnEvent() {
return AlmostBoolean.YES;
}
// @Override
// public void correctDirection(final Player player) {
// final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
// // Main direction.
// mcPlayer.yaw = LocUtil.correctYaw(mcPlayer.yaw);
// mcPlayer.pitch = LocUtil.correctPitch(mcPlayer.pitch);
// // Consider setting the lastYaw here too.
// }
}