-
Notifications
You must be signed in to change notification settings - Fork 1
/
OceanRuinGenerator.java
298 lines (273 loc) · 14 KB
/
OceanRuinGenerator.java
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
package OceanRuinGenerator;
import com.seedfinding.mcbiome.biome.Biome;
import com.seedfinding.mcbiome.biome.Biomes;
import com.seedfinding.mccore.block.Block;
import com.seedfinding.mccore.block.Blocks;
import com.seedfinding.mccore.rand.ChunkRand;
import com.seedfinding.mccore.util.block.BlockBox;
import com.seedfinding.mccore.util.block.BlockMirror;
import com.seedfinding.mccore.util.block.BlockRotation;
import com.seedfinding.mccore.util.data.Pair;
import com.seedfinding.mccore.util.pos.BPos;
import com.seedfinding.mccore.util.pos.CPos;
import com.seedfinding.mccore.version.MCVersion;
import com.seedfinding.mcfeature.loot.LootContext;
import com.seedfinding.mcfeature.loot.LootTable;
import com.seedfinding.mcfeature.loot.item.ItemStack;
import com.seedfinding.mcterrain.terrain.OverworldTerrainGenerator;
import java.util.*;
public class OceanRuinGenerator {
private static final List<String> WARM_RUINS = Arrays.asList("underwater_ruin/warm_1", "underwater_ruin/warm_2", "underwater_ruin/warm_3", "underwater_ruin/warm_4", "underwater_ruin/warm_5", "underwater_ruin/warm_6", "underwater_ruin/warm_7", "underwater_ruin/warm_8");
private static final List<String> BRICK_RUINS = Arrays.asList("underwater_ruin/brick_1", "underwater_ruin/brick_2", "underwater_ruin/brick_3", "underwater_ruin/brick_4", "underwater_ruin/brick_5", "underwater_ruin/brick_6", "underwater_ruin/brick_7", "underwater_ruin/brick_8");
private static final List<String> CRACKED_RUINS = Arrays.asList("underwater_ruin/cracked_1", "underwater_ruin/cracked_2", "underwater_ruin/cracked_3", "underwater_ruin/cracked_4", "underwater_ruin/cracked_5", "underwater_ruin/cracked_6", "underwater_ruin/cracked_7", "underwater_ruin/cracked_8");
private static final List<String> MOSSY_RUINS = Arrays.asList("underwater_ruin/mossy_1", "underwater_ruin/mossy_2", "underwater_ruin/mossy_3", "underwater_ruin/mossy_4", "underwater_ruin/mossy_5", "underwater_ruin/mossy_6", "underwater_ruin/mossy_7", "underwater_ruin/mossy_8");
private static final List<String> BIG_BRICK_RUINS = Arrays.asList("underwater_ruin/big_brick_1", "underwater_ruin/big_brick_2", "underwater_ruin/big_brick_3", "underwater_ruin/big_brick_8");
private static final List<String> BIG_MOSSY_RUINS = Arrays.asList("underwater_ruin/big_mossy_1", "underwater_ruin/big_mossy_2", "underwater_ruin/big_mossy_3", "underwater_ruin/big_mossy_8");
private static final List<String> BIG_CRACKED_RUINS = Arrays.asList("underwater_ruin/big_cracked_1", "underwater_ruin/big_cracked_2", "underwater_ruin/big_cracked_3", "underwater_ruin/big_cracked_8");
private static final List<String> BIG_WARM_RUINS = Arrays.asList("underwater_ruin/big_warm_4", "underwater_ruin/big_warm_5", "underwater_ruin/big_warm_6", "underwater_ruin/big_warm_7");
private static final List<Integer> WARM_BIOMES = Arrays.asList(Biomes.WARM_OCEAN.getId(), Biomes.LUKEWARM_OCEAN.getId(), Biomes.DEEP_WARM_OCEAN.getId(), Biomes.DEEP_LUKEWARM_OCEAN.getId());
private MCVersion version;
private long worldSeed;
private List<Piece> pieces;
private boolean isLarge;
private boolean isCluster;
public OceanRuinGenerator(MCVersion version) {
this.version = version;
this.pieces = new ArrayList<>();
}
public boolean generate(OverworldTerrainGenerator otg, CPos pos, ChunkRand rand) {
long seed = otg.getWorldSeed();
this.worldSeed = seed;
rand.setCarverSeed(seed, pos.getX(), pos.getZ(), version);
BPos blockPos = new BPos(pos.getX() << 4, 90, pos.getZ() << 4);
BlockRotation startRotation = BlockRotation.getRandom(rand);
Biome biome = otg.getBiomeSource().getBiomeForNoiseGen((pos.getX() << 2) + 2, 0, (pos.getZ() << 2) + 2);
boolean isWarm = WARM_BIOMES.contains(biome.getId());
this.isLarge = rand.nextFloat() <= 0.3F;
float integrity = isLarge ? 0.9F : 0.8F;
addPiece(otg,isWarm,isLarge,rand,blockPos,startRotation,integrity);
this.isCluster = isLarge && rand.nextFloat() <= 0.9F;
if (isCluster) {
int i1 = blockPos.getX();
int j1 = blockPos.getZ();
BPos bPos1 = getTransformedPos(new BPos(15,0,15), startRotation).add(i1,0,j1);
BlockBox box1 = new BlockBox(blockPos,bPos1);
BPos bPos2 = new BPos(Math.min(i1,bPos1.getX()),0,Math.min(j1,bPos1.getZ()));
List<BPos> list = getRoomPositions(rand, bPos2.getX(), bPos2.getZ());
int k = rand.nextInt(5) + 4;
for(int l = 0; l < k; l++) {
if (!list.isEmpty()) {
int i2 = rand.nextInt(list.size());
BPos bPos3 = list.remove(i2);
int j2 = bPos3.getX();
int k2 = bPos3.getZ();
BlockRotation rotation = BlockRotation.getRandom(rand);
BPos bPos4 = getTransformedPos(new BPos(5,0,6), rotation).add(j2,0,k2);
BlockBox box2 = new BlockBox(bPos3,bPos4);
if (!box2.intersects(box1)) {
addPiece(otg,isWarm,false,rand,bPos3,rotation,0.8F);
}
}
}
}
return true;
}
public List<Pair<BPos, List<ItemStack>>> generateLoot() {
List<BPos> allChestPositions = new ArrayList<>();
List<Pair<BPos, LootTable>> chestInformations = new ArrayList<>();
for (Piece piece : pieces) {
LootTable lootTable = OceanRuinStructureData.STRUCTURE_LOOT.get(piece.name);
if (lootTable != null) {
BPos chestPos = getChestPos(piece);
allChestPositions.add(chestPos);
chestInformations.add(new Pair<>(chestPos, lootTable));
}
}
List<BPos> chestPositions = new ArrayList<>();
for (Pair<BPos, LootTable> chestInformation : chestInformations) {
BPos bPos = chestInformation.getFirst();
if (chestPositions.contains(bPos)) {
chestPositions.remove(bPos);
chestPositions.add(bPos);
continue;
}
chestPositions.add(bPos);
}
ChunkRand rand = new ChunkRand();
List<Pair<BPos,List<ItemStack>>> result = new ArrayList<>();
for (BPos chestPosition : chestPositions) {
int num = Collections.frequency(allChestPositions, chestPosition);
CPos chestCPos = chestPosition.toChunkPos();
rand.setDecoratorSeed(worldSeed,chestCPos.getX()<<4,chestCPos.getZ()<<4,40009,version);
if (num > 1) {
for (int i = 0 ; i < num-1 ; i++) {
rand.nextLong();
}
}
LootContext lootContext = new LootContext(rand.nextLong(),version);
int index = allChestPositions.lastIndexOf(chestPosition);
List<ItemStack> items = chestInformations.get(index).getSecond().generate(lootContext);
result.add(new Pair<>(chestPosition,items));
}
return result;
}
public List<Piece> getPieces() {
return this.pieces;
}
public boolean isLarge() {
return this.isLarge;
}
public boolean isCluster() {
return this.isCluster;
}
public static class Piece {
String name;
BPos pos;
BlockBox box;
BlockRotation rotation;
float integrity;
public String getName() {
return this.name;
}
public BPos getPos() {
return this.pos;
}
public BlockBox getBox() {
return this.box;
}
public BlockRotation getRotation() {
return this.rotation;
}
public float getIntegrity() {
return this.integrity;
}
Piece(String name, BPos pos, BlockBox box, BlockRotation rotation, float integrity) {
this.name = name;
this.pos = pos;
this.box = box;
this.rotation = rotation;
this.integrity = integrity;
}
}
void addPiece(OverworldTerrainGenerator otg, boolean isWarm, boolean isLarge, ChunkRand rand, BPos blockPos, BlockRotation rotation, float integrity) {
if (isWarm) {
String template = isLarge ? getType(BIG_WARM_RUINS, rand) : getType(WARM_RUINS, rand);
Piece piece = getPiece(otg,template,blockPos,rotation,integrity);
pieces.add(piece);
}
else {
List<String> templates1 = isLarge ? BIG_BRICK_RUINS : BRICK_RUINS;
List<String> templates2 = isLarge ? BIG_CRACKED_RUINS : CRACKED_RUINS;
List<String> templates3 = isLarge ? BIG_MOSSY_RUINS : MOSSY_RUINS;
int i = rand.nextInt(templates1.size());
String template1 = templates1.get(i);
Piece piece1 = getPiece(otg,template1,blockPos,rotation,integrity);
String template2 = templates2.get(i);
Piece piece2 = getPiece(otg,template2,blockPos,rotation,0.7F);
String template3 = templates3.get(i);
Piece piece3 = getPiece(otg,template3,blockPos,rotation,0.5F);
pieces.add(piece1);
pieces.add(piece2);
pieces.add(piece3);
}
}
Piece getPiece(OverworldTerrainGenerator otg, String template, BPos templatePos, BlockRotation rotation, float integrity) {
BPos size = OceanRuinStructureData.STRUCTURE_SIZE.get(template);
BlockBox box = BlockBox.getBoundingBox(templatePos, rotation, BPos.ORIGIN, BlockMirror.NONE, size);
templatePos = new BPos(templatePos.getX(),otg.getHeightOnGround(templatePos.getX(), templatePos.getZ()), templatePos.getZ());
BPos bPos = getTransformedPos(new BPos(size.getX()-1,0,size.getZ()-1),rotation).add(templatePos);
templatePos = new BPos(templatePos.getX(),getYforPiece(otg,templatePos,bPos),templatePos.getZ());
return new Piece(template,bPos,box,rotation,integrity);
}
List<BPos> getRoomPositions(ChunkRand rand, int x, int z) {
List<BPos> list = new ArrayList<>();
list.add(new BPos(x - 15 + rand.nextInt(8), 90, z + 17 + rand.nextInt(7)));
list.add(new BPos(x - 15 + rand.nextInt(8), 90, z + 1 + rand.nextInt(7)));
list.add(new BPos(x - 15 + rand.nextInt(8), 90, z - 12 + rand.nextInt(5)));
list.add(new BPos(x + 1 + rand.nextInt(7), 90, z + 17 + rand.nextInt(7)));
list.add(new BPos(x + 1 + rand.nextInt(7), 90, z - 12 + rand.nextInt(3)));
list.add(new BPos(x + 17 + rand.nextInt(7), 90, z + 19 + rand.nextInt(6)));
list.add(new BPos(x + 17 + rand.nextInt(7), 90, z + 1 + rand.nextInt(7)));
list.add(new BPos(x + 17 + rand.nextInt(7), 90, z - 12 + rand.nextInt(5)));
return list;
}
BPos getTransformedPos(BPos targetPos, BlockRotation rotationIn) {
int i = targetPos.getX();
int j = targetPos.getY();
int k = targetPos.getZ();
switch(rotationIn) {
case COUNTERCLOCKWISE_90:
return new BPos(k,j, -i);
case CLOCKWISE_90:
return new BPos(-k,j, +i);
case CLOCKWISE_180:
return new BPos(-i, j, -k);
default:
return targetPos;
}
}
int getYforPiece(OverworldTerrainGenerator otg,BPos templatePos,BPos templateTransformedPos) {
int i1 = templatePos.getY();
int j1 = 512;
int k1 = i1 - 1;
int l1 = 0;
for (BPos bPos : getAllInBoxMutable(templatePos,templateTransformedPos)) {
int i2 = bPos.getX();
int j2 = bPos.getZ();
int k2 = templatePos.getY() - 1;
BPos mutable = new BPos(i2,j2,k2);
Block block = otg.getBlockAt(mutable).orElse(Blocks.AIR);
for(Block b = otg.getBlockAt(mutable).orElse(Blocks.AIR); (block.equals(Blocks.AIR) || b.equals(Blocks.WATER)) && k2 > 1; b = otg.getBlockAt(mutable).orElse(Blocks.AIR)) {
--k2;
mutable = new BPos(i2,j2,k2);
block = otg.getBlockAt(mutable).orElse(Blocks.AIR);
}
j1 = Math.min(j1, k2);
if (k2 < k1 - 2) {
++l1;
}
}
int l2 = Math.abs(templatePos.getX() - templateTransformedPos.getX());
if (k1 - j1 > 2 && l1 > l2 - 2) {
i1 = j1 + 1;
}
return i1;
}
List<BPos> getAllInBoxMutable(BPos firstPos, BPos secondPos) {
int x1 = Math.min(firstPos.getX(),secondPos.getX());
int y1 = Math.min(firstPos.getY(),secondPos.getY());
int z1 = Math.min(firstPos.getZ(),secondPos.getZ());
int x2 = Math.max(firstPos.getX(),secondPos.getX());
int y2 = Math.max(firstPos.getY(),secondPos.getY());
int z2 = Math.max(firstPos.getZ(),secondPos.getZ());
int i = x2 - x1 + 1;
int j = y2 - y1 + 1;
int k = z2 - z1 + 1;
int l = i * j * k;
List<BPos> bPosList = new ArrayList<>();
for (int h = 0; h < l; h++) {
int i1 = h % i;
int j1 = h / i;
int k1 = j1 % j;
int l1 = j1 / j;
bPosList.add(new BPos(x1 + i1, y1 + k1, z1 + l1));
}
return bPosList;
}
BPos getChestPos(Piece piece) {
CPos cPos = piece.pos.toChunkPos();
switch (piece.rotation) {
case COUNTERCLOCKWISE_90:
cPos = new CPos(cPos.getX(),cPos.getZ()+1);
case CLOCKWISE_90:
cPos = new CPos(cPos.getX()+1,cPos.getZ());
case CLOCKWISE_180:
cPos = new CPos(cPos.getX()+1,cPos.getZ()+1);
}
BPos offset = getTransformedPos(OceanRuinStructureData.STRUCTURE_LOOT_OFFSETS.get(piece.name),piece.rotation);
return cPos.toBlockPos(piece.pos.getY()).add(offset);
}
String getType(List<String> list, ChunkRand rand) {
return list.get(rand.nextInt(list.size()));
}
}