Проблемы Синхронизации Столкновения Мобов На Сервере

Версия Minecraft
1.12.2
API
Forge
7
1
0
Проблема проявляется только с серверными сущностями на клиенте всё работает коректно.
сама суть проблемы я использую TileEntity + ITickable для обновления состояни коллзии в методе update
я делаю --> 1759852705990.png
при помощи нжекта к Entity#move()
1759852901215.png
я переопределяю движения на основе позиции столкновения
в CollisionHandler#handleCollision() и получаю списко коллзий при помощи OBBCollisionUtillity#getWorldOB() 1759852863530.pngи вроде бы на клиенте рендер + позиция столкновения полностью коректна
1759853190194.png но сущности на пример ArmorStand (использовал его так как он не может ходить) входит в OBB на силу её поворота в данном случаии 1 и даже я бы сказал сталкивается с её версией которая была актуальна 1 тик назад.
1759853160817.png
При тесте с 2 игроками ситуация ещё странне так как у каждого игрока своя коректная версия OBB но при столкновении у 1 игрока игрок может как входить в OBB а у друго сталкиватся с OBB с зазором и я даже сохраняю NBT данные поворота позиции и размера 1759853254226.png но и это не помогает также делал попытку синхронизации обновления через ситевые пакеты и это не помогло, пытался впихнуть в моба и заменить мобу его AABB на OBB тоже не помогло так как возникала этаже самая проблема с столкновениями перепробывал уйму вариантов и пока ни чего не помгло. (пытаюсь это исправить на протяжении 3 дней +- 8дней так как забивал на это и писал дргуие механики для OBB).
P.S - мод делается не для проекта если в друг это для вас сильно важно =)
 
Java:
package com.arcollision.collision.obb;

import com.arcollision.collision.obb.base.OBBBase;
import com.arcollision.utillity.Matrix3d;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.Vec3d;

public class OBB extends OBBBase {
    private final Vec3d[] rotatedVertices = new Vec3d[8];
    private AxisAlignedBB enclosingAABB;

    public Vec3d center;
    public Vec3d halfSize;

    public double rotX, rotY, rotZ;
    public double lastRotX, lastRotY, lastRotZ;

    public Vec3d position;
    public Vec3d lastPosition;

    public Vec3d velocity = Vec3d.ZERO;

    public boolean isDynamic;

    public OBB(Vec3d min, Vec3d max, Vec3d position, Vec3d rot, boolean isSlope) {
        super(min, max, isSlope);

        this.rotX = rot.x;
        this.rotY = rot.y;
        this.rotZ = rot.z;

        this.lastRotX = rotX;
        this.lastRotY = rotY;
        this.lastRotZ = rotZ;

        // Центр и половинный размер в локальных координатах
        this.center = position.add(new Vec3d(0.5F, 0, 0.5F));
        this.halfSize = max.subtract(min).scale(0.5);
        this.position = position;

        this.lastPosition = this.position;

        this.isDynamic = false;

        // Создаём матрицу поворота из yaw, pitch, roll (в радианах)
        double rotXRad = Math.toRadians(rotX);
        double rotYRad = Math.toRadians(rotY);
        double rotZRad = Math.toRadians(rotZ);

        Matrix3d rotation = Matrix3d
                .rotationY(rotXRad)
                .multiply(Matrix3d.rotationX(rotYRad))
                .multiply(Matrix3d.rotationZ(rotZRad));

        Vec3d localCenter = getCenter();

        // Инициализация для вычисления огибающего AABB
        double minX = Double.POSITIVE_INFINITY;
        double minY = Double.POSITIVE_INFINITY;
        double minZ = Double.POSITIVE_INFINITY;
        double maxX = Double.NEGATIVE_INFINITY;
        double maxY = Double.NEGATIVE_INFINITY;
        double maxZ = Double.NEGATIVE_INFINITY;

        // Вращаем 8 вершин локального AABB и смещаем по позиции
        for (int i = 0; i < 8; i++) {
            Vec3d localVertex = getLocalVertices()[i];
            Vec3d translated = localVertex.subtract(localCenter); // Центрируем относительно центра AABB
            Vec3d rotated = rotation.transform(translated).add(localCenter).add(position); // Поворот + позиция
            rotatedVertices[i] = rotated;

            // Обновляем минимальные и максимальные координаты огибающего AABB
            if (rotated.x < minX) minX = rotated.x;
            if (rotated.y < minY) minY = rotated.y;
            if (rotated.z < minZ) minZ = rotated.z;
            if (rotated.x > maxX) maxX = rotated.x;
            if (rotated.y > maxY) maxY = rotated.y;
            if (rotated.z > maxZ) maxZ = rotated.z;
        }

        enclosingAABB = new AxisAlignedBB(minX, minY, minZ, maxX, maxY, maxZ);
    }

    public void setDynamicState(boolean dynamic) {
        this.isDynamic = dynamic;
    }

    public boolean getDynamicOBB(){
        return isDynamic;
    }

    public Vec3d[] getRotatedVertices() {
        return rotatedVertices;
    }

    public AxisAlignedBB getAABB() {
        return enclosingAABB;
    }

    public Vec3d[] getAxes() {
        Vec3d[] verts = getRotatedVertices();

        int[][] faces = {
                {0,1,2,3}, // down
                {4,5,6,7}, // up
                {0,1,5,4}, // front
                {1,2,6,5}, // right
                {2,3,7,6}, // back
                {3,0,4,7}  // left
        };

        java.util.List<Vec3d> axes = new java.util.ArrayList<>();
        for (int[] f : faces) {
            Vec3d v0 = verts[f[0]];
            Vec3d v1 = verts[f[1]];
            Vec3d v2 = verts[f[2]];

            Vec3d edge1 = v1.subtract(v0);
            Vec3d edge2 = v2.subtract(v0);

            Vec3d normal = edge1.crossProduct(edge2);
            double lenSq = normal.lengthSquared();
            if (lenSq < 1e-8) continue;

            normal = normal.scale(1.0 / Math.sqrt(lenSq));

            boolean found = false;
            for (Vec3d a : axes) {
                if (Math.abs(a.dotProduct(normal)) > 1.0 - 1e-6) { found = true; break; }
            }
            if (!found) axes.add(normal);
        }

        return axes.toArray(new Vec3d[0]);
    }

    public Vec3d[] getInterpolatedVertices(float partialTicks) {
        Vec3d interpolatedPos = getInterpolatedPosition(partialTicks);

        double rotXInterp = getInterpolatedRotX(partialTicks);
        double rotYInterp = getInterpolatedRotY(partialTicks);
        double rotZInterp = getInterpolatedRotZ(partialTicks);

        Matrix3d rotation = Matrix3d
                .rotationY(Math.toRadians(rotXInterp))
                .multiply(Matrix3d.rotationX(Math.toRadians(rotYInterp)))
                .multiply(Matrix3d.rotationZ(Math.toRadians(rotZInterp)));

        Vec3d[] result = new Vec3d[8];
        Vec3d localCenter = getCenter();

        for (int i = 0; i < 8; i++) {
            Vec3d localVertex = getLocalVertices()[i];
            Vec3d translated = localVertex.subtract(localCenter);
            Vec3d rotated = rotation.transform(translated).add(localCenter).add(interpolatedPos);
            result[i] = rotated;
        }

        return result;
    }

    public Vec3d getInterpolatedPosition(float partialTicks) {
        if (lastPosition == null) return position;
        double x = lastPosition.x + (position.x - lastPosition.x) * partialTicks;
        double y = lastPosition.y + (position.y - lastPosition.y) * partialTicks;
        double z = lastPosition.z + (position.z - lastPosition.z) * partialTicks;
        return new Vec3d(x, y, z);
    }

    public double getInterpolatedRotX(float partialTicks) {
        return lastRotX + (rotX - lastRotX) * partialTicks;
    }

    public double getInterpolatedRotY(float partialTicks) {
        return lastRotY + (rotY - lastRotY) * partialTicks;
    }

    public double getInterpolatedRotZ(float partialTicks) {
        return lastRotZ + (rotZ - lastRotZ) * partialTicks;
    }

    public OBB rot(Vec3d rot) {
        this.rotX += rot.x;
        this.rotY += rot.y;
        this.rotZ += rot.z;

        return new OBB(this.min, this.max, this.position, new Vec3d(rotX, rotY, rotZ), isSlope);
    }

    public OBB pos(Vec3d pos) {
        return new OBB(this.min, this.max, this.position.add(pos), new Vec3d(rotX, rotY, rotZ), this.isSlope);
    }
}


Java:
package com.arcollision.client.tileentity;

import com.ar2t1e.ARLibs;
import com.arcollision.collision.obb.OBB;
import com.arcollision.common.network.packet.PacketUpdateNBTTagTileEntity;
import com.arcollision.utillity.BlockPosHelper;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.play.server.SPacketUpdateTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ITickable;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.Vec3d;

import java.util.Collections;
import java.util.List;

public class TileEntityOBB extends TileEntity implements ITileEntityOBB, ITickable {
    public Vec3d min;
    public Vec3d max;
    public Vec3d rot;

    private boolean isSlope;

    public OBB obb;

    public TileEntityOBB() {
        this.rot = new Vec3d(0, 0, 0);
        this.isSlope = false;

        this.min = new Vec3d(-3, 0, 0);
        this.max = new Vec3d(3, 2, 1);

        this.writeToNBT(new NBTTagCompound());
        this.readFromNBT(this.writeToNBT(new NBTTagCompound()));
    }

    @Override
    public NBTTagCompound writeToNBT(NBTTagCompound compound) {
        compound.setDouble("rotX", rot.x);
        compound.setDouble("rotY", rot.y);
        compound.setDouble("rotZ", rot.z);

        compound.setDouble("minX", min.x);
        compound.setDouble("minY", min.y);
        compound.setDouble("minZ", min.z);

        compound.setDouble("maxX", max.x);
        compound.setDouble("maxY", max.y);
        compound.setDouble("maxZ", max.z);

        compound.setBoolean("isSlope", isSlope);

        return super.writeToNBT(compound);
    }

    @Override
    public void readFromNBT(NBTTagCompound compound) {
        super.readFromNBT(compound);

        this.rot = new Vec3d(compound.getDouble("rotX"), compound.getDouble("rotY"), compound.getDouble("rotZ"));
        this.min = new Vec3d(compound.getDouble("minX"), compound.getDouble("minY"), compound.getDouble("minZ"));
        this.max = new Vec3d(compound.getDouble("maxX"), compound.getDouble("maxY"), compound.getDouble("maxZ"));
        this.isSlope = compound.getBoolean("isSlope");

        if (obb == null) {
            obb = new OBB(min, max, BlockPosHelper.getPos(pos), rot, isSlope);
        }
    }

    @Override
    public List<OBB> getOBBs() {
        return Collections.singletonList(obb);
    }

    @Override
    public AxisAlignedBB getRenderBoundingBox() {
        return new AxisAlignedBB(getPos()).grow(16);
    }

    @Override
    public SPacketUpdateTileEntity getUpdatePacket() {
        return new SPacketUpdateTileEntity(pos, getBlockMetadata(), getUpdateTag());
    }

    @Override
    public NBTTagCompound getUpdateTag() {
        return writeToNBT(new NBTTagCompound());
    }

    @Override
    public void onDataPacket(NetworkManager net, SPacketUpdateTileEntity pkt) {
        readFromNBT(pkt.getNbtCompound());
    }

    @Override
    public void update() {
        if (!world.isRemote) {
            this.obb = obb.rot(new Vec3d(1, 0, 0));
            
            ARLibs.NETWORK.sendToServer(new PacketUpdateNBTTagTileEntity(pos, serializeNBT()));
        }
    }
}


Java:
package com.arcollision.common.network.packet;

import com.ar2t1e.common.network.base.PacketBase;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.network.ByteBufUtils;

public class PacketUpdateNBTTagTileEntity extends PacketBase {
    private BlockPos pos;
    private NBTTagCompound tagCompound;

    public PacketUpdateNBTTagTileEntity() {}

    public PacketUpdateNBTTagTileEntity(BlockPos pos, NBTTagCompound tagCompound) {
        this.pos = pos;
        this.tagCompound = tagCompound;
    }

    @Override
    public void encodeInto(ChannelHandlerContext ctx, ByteBuf data) {
        data.writeInt(pos.getX());
        data.writeInt(pos.getY());
        data.writeInt(pos.getZ());
        ByteBufUtils.writeTag(data, tagCompound);
    }

    @Override
    public void decodeInto(ChannelHandlerContext ctx, ByteBuf data) {
        int x = data.readInt();
        int y = data.readInt();
        int z = data.readInt();
        pos = new BlockPos(x, y, z);
        tagCompound = ByteBufUtils.readTag(data);
    }

    @Override
    public void handleServerSide(EntityPlayerMP player) {
        World world = player.getEntityWorld();
        TileEntity tileEntity = world.getTileEntity(new BlockPos(pos));

        if (tileEntity != null) {
            tileEntity.deserializeNBT(tagCompound);
            tileEntity.markDirty();
            tileEntity.getUpdatePacket();
            world.notifyBlockUpdate(tileEntity.getPos(), world.getBlockState(tileEntity.getPos()), world.getBlockState(tileEntity.getPos()), 3);
        }
    }

    @Override
    public void handleClientSide(EntityPlayer player) {}
}
 
if на 66 строке в тайле попробуй убрать, во так
Java:
    @Override
    public void readFromNBT(NBTTagCompound compound) {
        super.readFromNBT(compound);

        this.rot = new Vec3d(compound.getDouble("rotX"), compound.getDouble("rotY"), compound.getDouble("rotZ"));
        this.min = new Vec3d(compound.getDouble("minX"), compound.getDouble("minY"), compound.getDouble("minZ"));
        this.max = new Vec3d(compound.getDouble("maxX"), compound.getDouble("maxY"), compound.getDouble("maxZ"));
        this.isSlope = compound.getBoolean("isSlope");

     
        obb = new OBB(min, max, BlockPosHelper.getPos(pos), rot, isSlope);
     
    }
И после того как вызываешь rot в update вызывай this.markDirty() и вот это вот
Java:
        IBlockState state = this.world.getBlockState(this.pos);
        this.world.notifyBlockUpdate(this.pos, state, state, 2);
пакет не нужон
 
Последнее редактирование:
Назад
Сверху