aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/gregtech/common/misc/GT_ClientPollutionMap.java
blob: d666408807d4cb8ecba357f0ccf6959f916e0786 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package gregtech.common.misc;

import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityClientPlayerMP;
import net.minecraft.util.MathHelper;

public class GT_ClientPollutionMap {
    private static final byte RADIUS = 24;
    private static final byte DISTANCE_RELOAD_MAP = 5; //When player moved x chunks, shift the map to new center.
    private static final byte SIZE = RADIUS*2+1; //Area to keep stored.

    private int x0, z0;
    private int dim;

    private boolean initialized = false;

    private static short[][] chunkMatrix; //short because reasons.


    public GT_ClientPollutionMap(){ }

    public void reset() {
        initialized = false;
    }

    private void initialize(int playerChunkX, int playerChunkZ, int dimension) {
        initialized = true;
        chunkMatrix = new short[SIZE][SIZE];
        x0 = playerChunkX;
        z0 = playerChunkZ;
        dim = dimension;
    }

    public void addChunkPollution(int chunkX, int chunkZ, int pollution) {
        EntityClientPlayerMP player = Minecraft.getMinecraft().thePlayer;
        if (player == null || player.worldObj == null)
            return;

        int playerXChunk = MathHelper.floor_double(player.posX) >> 4;
        int playerZChunk = MathHelper.floor_double(player.posZ) >> 4; //posX/Z seems to be always loaded,

        if (!initialized) {
            initialize(playerXChunk, playerZChunk, player.dimension);
        }

        if (dim != player.dimension) {
            initialize(playerXChunk, playerZChunk, player.dimension);
        }

        if (Math.abs(x0 - playerXChunk) > DISTANCE_RELOAD_MAP || Math.abs(z0 - playerZChunk) > DISTANCE_RELOAD_MAP)
            shiftCenter(playerXChunk, playerZChunk);

        int relX = chunkX - x0 + RADIUS;
        if (relX >= SIZE || relX < 0) //out of bounds
            return;
        int relZ = chunkZ - z0 + RADIUS;
        if (relZ >= SIZE || relZ < 0) //out of bounds
            return;

        pollution = pollution/225;
        if (pollution > Short.MAX_VALUE) //Sanity
            chunkMatrix[relX][relZ] = Short.MAX_VALUE; //Max pollution = 7,3mill
        else if (pollution < 0)
            chunkMatrix[relX][relZ] = 0;
        else
            chunkMatrix[relX][relZ] = (short) (pollution);
    }

    //xy interpolation, between 4 chunks as corners, unknown treated as 0.
    public int getPollution(double fx, double fz) {
        if (!initialized)
            return 0;
        int x = MathHelper.floor_double(fx);
        int z = MathHelper.floor_double(fz);
        int xDiff = ((x-8) >> 4) - x0;
        int zDiff = ((z-8) >> 4) - z0;

        if (xDiff < -RADIUS || zDiff < -RADIUS || xDiff >= RADIUS || zDiff >= RADIUS )
            return 0;

        //coordinates in shifted chunk.
        x = (x-8) % 16;
        z = (z-8) % 16;
        if (x < 0)
            x = 16+x;
        if (z < 0)
            z = 16+z;

        int xi = 15 - x;
        int zi = 15 - z;

        //read pollution in 4 corner chunks
        int offsetX = RADIUS+xDiff;
        int offsetZ = RADIUS+zDiff;

        int c00 = chunkMatrix[offsetX][offsetZ];
        int c10 = chunkMatrix[offsetX+1][offsetZ];
        int c01 = chunkMatrix[offsetX][offsetZ+1];
        int c11 = chunkMatrix[offsetX+1][offsetZ+1];

        //Is divided by 15*15 but is handled when storing chunk data.
        return c00*xi*zi + c10*x*zi + c01*xi*z + c11*x*z;
    }

    //shift the matrix to fit new center
    private void shiftCenter(int chunkX, int chunkZ) {
        int xDiff = chunkX - x0;
        int zDiff = chunkZ - z0;
        boolean[] allEmpty = new boolean[SIZE]; //skip check z row if its empty.
        if (xDiff > 0)
            for (byte x = 0; x < SIZE; x++) {
                int xOff = x + xDiff;
                if (xOff < SIZE) {
                    chunkMatrix[x] = chunkMatrix[xOff].clone();
                } else {
                    chunkMatrix[x] = new short[SIZE];
                    allEmpty[x] = true;
                }
            }
        else if (xDiff < 0)
            for (byte x = SIZE-1; x >= 0; x--) {
                int xOff = x + xDiff;
                if (xOff > 0) {
                    chunkMatrix[x] = chunkMatrix[xOff].clone();
                } else {
                    chunkMatrix[x] = new short[SIZE];
                    allEmpty[x] = true;
                }
            }

        if (zDiff > 0)
            for (byte x = 0; x < SIZE; x++) {
                if (allEmpty[x])
                    continue;
                for (int z = 0; z < SIZE ; z++) {
                    int zOff = z + zDiff;
                    chunkMatrix[x][z] = (zOff < SIZE) ? chunkMatrix[x][zOff] : 0;
                }
            }
        else if (zDiff < 0)
            for (byte x = 0; x < SIZE; x++) {
                if (allEmpty[x])
                    continue;
                for (int z = SIZE-1; z >= 0 ; z--) {
                    int zOff = z+zDiff;
                    chunkMatrix[x][z] = (zOff > 0) ? chunkMatrix[x][zOff] : 0;
                }
            }

        x0 = chunkX;
        z0 = chunkZ;
    }
}