From 798865968c19db1fdc52d856e6d5bf3678805023 Mon Sep 17 00:00:00 2001 From: Hileb <107909747+Ecdcaeb@users.noreply.github.com> Date: Sat, 2 Mar 2024 18:54:31 +0800 Subject: [PATCH 1/6] 1 --- .../minecraft/world/WorldServer.java.patch | 115 ++++++++++-------- .../minecraft/world/chunk/Chunk.java.patch | 25 ++-- .../world/gen/ChunkProviderServer.java.patch | 35 +++++- .../net/minecraftforge/common/ForgeHooks.java | 28 ++++- .../world/structure/IStructureProvider.java | 101 +++++++++++++++ .../structure/SingleStructureProvider.java | 39 ++++++ .../structure/StructureAttachRegistry.java | 43 +++++++ .../world/structure/StructureCollection.java | 67 ++++++++++ .../event/world/StructureAttachEvent.java | 24 ++++ 9 files changed, 406 insertions(+), 71 deletions(-) create mode 100644 src/main/java/net/minecraftforge/common/world/structure/IStructureProvider.java create mode 100644 src/main/java/net/minecraftforge/common/world/structure/SingleStructureProvider.java create mode 100644 src/main/java/net/minecraftforge/common/world/structure/StructureAttachRegistry.java create mode 100644 src/main/java/net/minecraftforge/common/world/structure/StructureCollection.java create mode 100644 src/main/java/net/minecraftforge/event/world/StructureAttachEvent.java diff --git a/patches/minecraft/net/minecraft/world/WorldServer.java.patch b/patches/minecraft/net/minecraft/world/WorldServer.java.patch index 30893f258..3a8676836 100644 --- a/patches/minecraft/net/minecraft/world/WorldServer.java.patch +++ b/patches/minecraft/net/minecraft/world/WorldServer.java.patch @@ -23,7 +23,15 @@ import net.minecraft.village.VillageCollection; import net.minecraft.village.VillageSiege; import net.minecraft.world.biome.Biome; -@@ -87,47 +88,52 @@ +@@ -68,6 +69,7 @@ + import net.minecraft.world.chunk.storage.ExtendedBlockStorage; + import net.minecraft.world.chunk.storage.IChunkLoader; + import net.minecraft.world.gen.ChunkProviderServer; ++import net.minecraft.world.gen.IChunkGenerator; + import net.minecraft.world.gen.feature.WorldGeneratorBonusChest; + import net.minecraft.world.gen.structure.StructureBoundingBox; + import net.minecraft.world.gen.structure.template.TemplateManager; +@@ -87,47 +89,52 @@ private final MinecraftServer field_73061_a; private final EntityTracker field_73062_L; private final PlayerChunkMap field_73063_M; @@ -88,7 +96,7 @@ } else { -@@ -164,10 +170,10 @@ +@@ -164,10 +171,10 @@ this.func_175723_af().func_177750_a(this.field_72986_A.func_176137_E()); } @@ -100,7 +108,7 @@ public void func_72835_b() { super.func_72835_b(); -@@ -183,8 +189,8 @@ +@@ -183,8 +190,8 @@ { if (this.func_82736_K().func_82766_b("doDaylightCycle")) { @@ -111,7 +119,7 @@ } this.func_73053_d(); -@@ -210,7 +216,7 @@ +@@ -210,7 +217,7 @@ if (this.func_82736_K().func_82766_b("doDaylightCycle")) { @@ -120,7 +128,7 @@ } this.field_72984_F.func_76318_c("tickPending"); -@@ -224,6 +230,10 @@ +@@ -224,6 +231,10 @@ this.field_175740_d.func_75528_a(); this.field_72984_F.func_76318_c("portalForcer"); this.field_85177_Q.func_85189_a(this.func_82737_E()); @@ -131,7 +139,7 @@ this.field_72984_F.func_76319_b(); this.func_147488_Z(); } -@@ -232,16 +242,17 @@ +@@ -232,16 +243,17 @@ public Biome.SpawnListEntry func_175734_a(EnumCreatureType p_175734_1_, BlockPos p_175734_2_) { List list = this.func_72863_F().func_177458_a(p_175734_1_, p_175734_2_); @@ -151,7 +159,7 @@ public void func_72854_c() { this.field_73068_P = false; -@@ -284,10 +295,7 @@ +@@ -284,10 +296,7 @@ private void func_73051_P() { @@ -163,7 +171,7 @@ } public boolean func_73056_e() -@@ -311,7 +319,6 @@ +@@ -311,7 +320,6 @@ } @SideOnly(Side.CLIENT) @@ -171,7 +179,7 @@ public void func_72974_f() { if (this.field_72986_A.func_76075_d() <= 0) -@@ -327,8 +334,9 @@ +@@ -327,8 +335,9 @@ { i += this.field_73012_v.nextInt(8) - this.field_73012_v.nextInt(8); j += this.field_73012_v.nextInt(8) - this.field_73012_v.nextInt(8); @@ -182,7 +190,7 @@ { break; } -@@ -338,7 +346,6 @@ +@@ -338,7 +347,6 @@ this.field_72986_A.func_76087_c(j); } @@ -190,7 +198,7 @@ protected boolean func_175680_a(int p_175680_1_, int p_175680_2_, boolean p_175680_3_) { return this.func_72863_F().func_73149_a(p_175680_1_, p_175680_2_); -@@ -361,7 +368,6 @@ +@@ -361,7 +369,6 @@ this.field_72984_F.func_76319_b(); } @@ -198,7 +206,7 @@ protected void func_147456_g() { this.func_184162_i(); -@@ -372,7 +378,7 @@ +@@ -372,7 +379,7 @@ while (iterator1.hasNext()) { @@ -207,7 +215,7 @@ } } else -@@ -382,7 +388,7 @@ +@@ -382,7 +389,7 @@ boolean flag1 = this.func_72911_I(); this.field_72984_F.func_76320_a("pollingChunks"); @@ -216,7 +224,7 @@ { this.field_72984_F.func_76320_a("getChunk"); Chunk chunk = iterator.next(); -@@ -394,7 +400,7 @@ +@@ -394,7 +401,7 @@ chunk.func_150804_b(false); this.field_72984_F.func_76318_c("thunder"); @@ -225,7 +233,7 @@ { this.field_73005_l = this.field_73005_l * 3 + 1013904223; int l = this.field_73005_l >> 2; -@@ -404,39 +410,32 @@ +@@ -404,39 +411,32 @@ { DifficultyInstance difficultyinstance = this.func_175649_E(blockpos); @@ -270,7 +278,7 @@ if (this.func_175662_w(blockpos2)) { this.func_175656_a(blockpos2, Blocks.field_150432_aD.func_176223_P()); -@@ -491,9 +490,8 @@ +@@ -491,9 +491,8 @@ protected BlockPos func_175736_a(BlockPos p_175736_1_) { BlockPos blockpos = this.func_175725_q(p_175736_1_); @@ -282,7 +290,7 @@ { public boolean apply(@Nullable EntityLivingBase p_apply_1_) { -@@ -503,7 +501,7 @@ +@@ -503,7 +502,7 @@ if (!list.isEmpty()) { @@ -291,7 +299,7 @@ } else { -@@ -516,27 +514,23 @@ +@@ -516,27 +515,23 @@ } } @@ -319,7 +327,7 @@ public void func_175654_a(BlockPos p_175654_1_, Block p_175654_2_, int p_175654_3_, int p_175654_4_) { Material material = p_175654_2_.func_176223_P().func_185904_a(); -@@ -545,7 +539,10 @@ +@@ -545,7 +540,10 @@ { if (p_175654_2_.func_149698_L()) { @@ -331,7 +339,7 @@ { IBlockState iblockstate = this.func_180495_p(p_175654_1_); -@@ -579,9 +576,9 @@ +@@ -579,9 +577,9 @@ } } @@ -342,7 +350,7 @@ NextTickListEntry nextticklistentry = new NextTickListEntry(p_180497_1_, p_180497_2_); nextticklistentry.func_82753_a(p_180497_4_); Material material = p_180497_2_.func_176223_P().func_185904_a(); -@@ -598,10 +595,9 @@ +@@ -598,10 +596,9 @@ } } @@ -354,7 +362,7 @@ { if (this.field_80004_Q++ >= 300) { -@@ -617,7 +613,6 @@ +@@ -617,7 +614,6 @@ super.func_72939_s(); } @@ -362,7 +370,7 @@ protected void func_184147_l() { super.func_184147_l(); -@@ -681,7 +676,6 @@ +@@ -681,7 +677,6 @@ this.field_80004_Q = 0; } @@ -370,7 +378,7 @@ public boolean func_72955_a(boolean p_72955_1_) { if (this.field_72986_A.func_76067_t() == WorldType.field_180272_g) -@@ -727,14 +721,16 @@ +@@ -727,14 +722,16 @@ { NextTickListEntry nextticklistentry1 = iterator.next(); iterator.remove(); @@ -389,7 +397,7 @@ { try { -@@ -763,7 +759,6 @@ +@@ -763,7 +760,6 @@ } @Nullable @@ -397,7 +405,7 @@ public List func_72920_a(Chunk p_72920_1_, boolean p_72920_2_) { ChunkPos chunkpos = p_72920_1_.func_76632_l(); -@@ -775,7 +770,6 @@ +@@ -775,7 +771,6 @@ } @Nullable @@ -405,7 +413,7 @@ public List func_175712_a(StructureBoundingBox p_175712_1_, boolean p_175712_2_) { List list = null; -@@ -798,10 +792,7 @@ +@@ -798,10 +793,7 @@ NextTickListEntry nextticklistentry = iterator.next(); BlockPos blockpos = nextticklistentry.field_180282_a; @@ -417,7 +425,7 @@ { if (p_175712_2_) { -@@ -815,7 +806,7 @@ +@@ -815,7 +807,7 @@ if (list == null) { @@ -426,7 +434,7 @@ } list.add(nextticklistentry); -@@ -826,7 +817,6 @@ +@@ -826,7 +818,6 @@ return list; } @@ -434,7 +442,7 @@ public void func_72866_a(Entity p_72866_1_, boolean p_72866_2_) { if (!this.func_175735_ai() && (p_72866_1_ instanceof EntityAnimal || p_72866_1_ instanceof EntityWaterMob)) -@@ -852,20 +842,21 @@ +@@ -852,20 +843,23 @@ return this.field_73061_a.func_71268_U(); } @@ -442,7 +450,10 @@ protected IChunkProvider func_72970_h() { IChunkLoader ichunkloader = this.field_73019_z.func_75763_a(this.field_73011_w); - return new ChunkProviderServer(this, ichunkloader, this.field_73011_w.func_186060_c()); +- return new ChunkProviderServer(this, ichunkloader, this.field_73011_w.func_186060_c()); ++ IChunkGenerator generator = this.field_73011_w.func_186060_c(); ++ net.minecraftforge.common.ForgeHooks.onCreateChunkProvider(this, ichunkloader, this.field_73011_w, generator); ++ return new ChunkProviderServer(this, ichunkloader, generator); } - @Override @@ -459,7 +470,7 @@ public void func_72963_a(WorldSettings p_72963_1_) { if (!this.field_72986_A.func_76070_v()) -@@ -881,16 +872,17 @@ +@@ -881,16 +875,17 @@ super.func_72963_a(p_72963_1_); } @@ -480,7 +491,7 @@ } throw new ReportedException(crashreport); -@@ -927,6 +919,7 @@ +@@ -927,6 +922,7 @@ } else { @@ -488,7 +499,7 @@ this.field_72987_B = true; BiomeProvider biomeprovider = this.field_73011_w.func_177499_m(); List list = biomeprovider.func_76932_a(); -@@ -952,8 +945,9 @@ +@@ -952,8 +948,9 @@ { i += random.nextInt(64) - random.nextInt(64); k += random.nextInt(64) - random.nextInt(64); @@ -499,7 +510,7 @@ { break; } -@@ -1011,6 +1005,7 @@ +@@ -1011,6 +1008,7 @@ } chunkproviderserver.func_186027_a(p_73044_1_); @@ -507,7 +518,7 @@ for (Chunk chunk : Lists.newArrayList(chunkproviderserver.func_189548_a())) { -@@ -1055,20 +1050,19 @@ +@@ -1055,20 +1053,19 @@ this.field_72986_A.func_176135_e(this.func_175723_af().func_177732_i()); this.field_73019_z.func_75755_a(this.field_72986_A, this.field_73061_a.func_184103_al().func_72378_q()); this.field_72988_C.func_75744_a(); @@ -530,7 +541,7 @@ { this.field_72996_f.add(entity); this.func_72923_a(entity); -@@ -1080,7 +1074,7 @@ +@@ -1080,7 +1077,7 @@ { if (p_184165_1_.field_70128_L) { @@ -539,7 +550,7 @@ return false; } else -@@ -1103,7 +1097,7 @@ +@@ -1103,7 +1100,7 @@ return false; } @@ -548,7 +559,7 @@ } this.func_72973_f(entity); -@@ -1113,7 +1107,6 @@ +@@ -1113,7 +1110,6 @@ } } @@ -556,7 +567,7 @@ public void func_72923_a(Entity p_72923_1_) { super.func_72923_a(p_72923_1_); -@@ -1130,7 +1123,6 @@ +@@ -1130,7 +1126,6 @@ } } @@ -564,7 +575,7 @@ public void func_72847_b(Entity p_72847_1_) { super.func_72847_b(p_72847_1_); -@@ -1147,22 +1139,11 @@ +@@ -1147,22 +1142,11 @@ } } @@ -588,7 +599,7 @@ return true; } else -@@ -1171,7 +1152,6 @@ +@@ -1171,7 +1155,6 @@ } } @@ -596,7 +607,7 @@ public void func_72960_a(Entity p_72960_1_, byte p_72960_2_) { this.func_73039_n().func_151248_b(p_72960_1_, new SPacketEntityStatus(p_72960_1_, p_72960_2_)); -@@ -1182,12 +1162,10 @@ +@@ -1182,12 +1165,10 @@ return (ChunkProviderServer)super.func_72863_F(); } @@ -611,7 +622,7 @@ explosion.func_77278_a(); explosion.func_77279_a(false); -@@ -1198,20 +1176,15 @@ +@@ -1198,20 +1179,15 @@ for (EntityPlayer entityplayer : this.field_73010_i) { @@ -634,7 +645,7 @@ public void func_175641_c(BlockPos p_175641_1_, Block p_175641_2_, int p_175641_3_, int p_175641_4_) { BlockEventData blockeventdata = new BlockEventData(p_175641_1_, p_175641_2_, p_175641_3_, p_175641_4_); -@@ -1238,19 +1211,7 @@ +@@ -1238,19 +1214,7 @@ { if (this.func_147485_a(blockeventdata)) { @@ -655,7 +666,7 @@ } } -@@ -1261,9 +1222,7 @@ +@@ -1261,9 +1225,7 @@ private boolean func_147485_a(BlockEventData p_147485_1_) { IBlockState iblockstate = this.func_180495_p(p_147485_1_.func_180328_a()); @@ -666,7 +677,7 @@ } public void func_73041_k() -@@ -1271,7 +1230,6 @@ +@@ -1271,7 +1233,6 @@ this.field_73019_z.func_75759_a(); } @@ -674,7 +685,7 @@ protected void func_72979_l() { boolean flag = this.func_72896_J(); -@@ -1279,36 +1237,35 @@ +@@ -1279,36 +1240,35 @@ if (this.field_73003_n != this.field_73004_o) { @@ -721,7 +732,7 @@ public MinecraftServer func_73046_m() { return this.field_73061_a; -@@ -1334,51 +1291,14 @@ +@@ -1334,51 +1294,14 @@ return this.field_73019_z.func_186340_h(); } @@ -777,7 +788,7 @@ for (int i = 0; i < this.field_73010_i.size(); ++i) { -@@ -1387,45 +1307,18 @@ +@@ -1387,45 +1310,18 @@ } } @@ -827,7 +838,7 @@ { p_184159_1_.field_71135_a.func_147359_a(p_184159_9_); } -@@ -1437,20 +1330,17 @@ +@@ -1437,20 +1333,17 @@ return this.field_175741_N.get(p_175733_1_); } @@ -848,7 +859,7 @@ public BlockPos func_190528_a(String p_190528_1_, BlockPos p_190528_2_, boolean p_190528_3_) { return this.func_72863_F().func_180513_a(this, p_190528_1_, p_190528_2_, p_190528_3_); -@@ -1464,6 +1354,11 @@ +@@ -1464,6 +1357,11 @@ public FunctionManager func_193037_A() { return this.field_193036_D; diff --git a/patches/minecraft/net/minecraft/world/chunk/Chunk.java.patch b/patches/minecraft/net/minecraft/world/chunk/Chunk.java.patch index 05a7141b1..10cd7229d 100644 --- a/patches/minecraft/net/minecraft/world/chunk/Chunk.java.patch +++ b/patches/minecraft/net/minecraft/world/chunk/Chunk.java.patch @@ -398,10 +398,11 @@ if (this.func_177419_t()) { if (p_186034_1_.func_185933_a(this, this.field_76635_g, this.field_76647_h)) -@@ -1012,8 +1017,10 @@ +@@ -1012,8 +1017,11 @@ { this.func_150809_p(); p_186034_1_.func_185931_b(this.field_76635_g, this.field_76647_h); ++ net.minecraftforge.common.ForgeHooks.postPopulateGenerate(p_186034_1_, this.field_76637_e, this.field_76635_g, this.field_76647_h); + net.minecraftforge.fml.common.registry.GameRegistry.generateWorld(this.field_76635_g, this.field_76647_h, this.field_76637_e, p_186034_1_, this.field_76637_e.func_72863_F()); this.func_76630_e(); } @@ -409,7 +410,7 @@ } public BlockPos func_177440_h(BlockPos p_177440_1_) -@@ -1068,7 +1075,7 @@ +@@ -1068,7 +1076,7 @@ { BlockPos blockpos = this.field_177447_w.poll(); @@ -418,7 +419,7 @@ { TileEntity tileentity = this.func_177422_i(blockpos); this.field_76637_e.func_175690_a(blockpos, tileentity); -@@ -1121,7 +1128,7 @@ +@@ -1121,7 +1129,7 @@ { if (this.field_76652_q.length != p_76602_1_.length) { @@ -427,7 +428,7 @@ } else { -@@ -1132,6 +1139,13 @@ +@@ -1132,6 +1140,13 @@ @SideOnly(Side.CLIENT) public void func_186033_a(PacketBuffer p_186033_1_, int p_186033_2_, boolean p_186033_3_) { @@ -441,7 +442,7 @@ boolean flag = this.field_76637_e.field_73011_w.func_191066_m(); for (int i = 0; i < this.field_76652_q.length; ++i) -@@ -1180,10 +1194,16 @@ +@@ -1180,10 +1195,16 @@ this.field_76646_k = true; this.func_76590_a(); @@ -458,7 +459,7 @@ } public Biome func_177411_a(BlockPos p_177411_1_, BiomeProvider p_177411_2_) -@@ -1194,9 +1214,14 @@ +@@ -1194,9 +1215,14 @@ if (k == 255) { @@ -475,7 +476,7 @@ } Biome biome1 = Biome.func_150568_d(k); -@@ -1212,7 +1237,7 @@ +@@ -1212,7 +1238,7 @@ { if (this.field_76651_r.length != p_76616_1_.length) { @@ -484,7 +485,7 @@ } else { -@@ -1248,14 +1273,13 @@ +@@ -1248,14 +1274,13 @@ BlockPos blockpos1 = blockpos.func_177982_a(k, (j << 4) + i1, l); boolean flag = i1 == 0 || i1 == 15 || k == 0 || k == 15 || l == 0 || l == 15; @@ -501,7 +502,7 @@ { this.field_76637_e.func_175664_x(blockpos2); } -@@ -1360,9 +1384,7 @@ +@@ -1360,9 +1385,7 @@ int i = this.func_76625_h(); boolean flag = false; boolean flag1 = false; @@ -512,7 +513,7 @@ for (int j = i + 16 - 1; j > this.field_76637_e.func_181545_F() || j > 0 && !flag1; --j) { -@@ -1388,7 +1410,7 @@ +@@ -1388,7 +1411,7 @@ { blockpos$mutableblockpos.func_181079_c(blockpos$mutableblockpos.func_177958_n(), l, blockpos$mutableblockpos.func_177952_p()); @@ -521,7 +522,7 @@ { this.field_76637_e.func_175664_x(blockpos$mutableblockpos); } -@@ -1422,11 +1444,12 @@ +@@ -1422,11 +1445,12 @@ { if (this.field_76634_f.length != p_177420_1_.length) { @@ -535,7 +536,7 @@ } } -@@ -1495,5 +1518,56 @@ +@@ -1495,5 +1519,56 @@ IMMEDIATE, QUEUED, CHECK; diff --git a/patches/minecraft/net/minecraft/world/gen/ChunkProviderServer.java.patch b/patches/minecraft/net/minecraft/world/gen/ChunkProviderServer.java.patch index 4b110857e..3e4779c26 100644 --- a/patches/minecraft/net/minecraft/world/gen/ChunkProviderServer.java.patch +++ b/patches/minecraft/net/minecraft/world/gen/ChunkProviderServer.java.patch @@ -111,7 +111,14 @@ public Chunk func_186025_d(int p_186025_1_, int p_186025_2_) { Chunk chunk = this.func_186028_c(p_186025_1_, p_186025_2_); -@@ -117,7 +147,7 @@ +@@ -111,13 +141,14 @@ + try + { + chunk = this.field_186029_c.func_185932_a(p_186025_1_, p_186025_2_); ++ net.minecraftforge.common.ForgeHooks.postGenerateChunk(this.field_186029_c, this.field_73251_h, chunk, p_186025_1_, p_186025_2_); + } + catch (Throwable throwable) + { CrashReport crashreport = CrashReport.func_85055_a(throwable, "Exception generating new chunk"); CrashReportCategory crashreportcategory = crashreport.func_85058_a("Chunk to be generated"); crashreportcategory.func_71507_a("Location", String.format("%d,%d", p_186025_1_, p_186025_2_)); @@ -120,7 +127,7 @@ crashreportcategory.func_71507_a("Generator", this.field_186029_c); throw new ReportedException(crashreport); } -@@ -199,8 +229,9 @@ +@@ -199,8 +230,9 @@ { this.func_73242_b(chunk); chunk.func_177427_f(false); @@ -131,7 +138,7 @@ { return false; } -@@ -215,23 +246,28 @@ +@@ -215,23 +247,28 @@ this.field_73247_e.func_75818_b(); } @@ -162,7 +169,7 @@ this.func_73242_b(chunk); this.func_73243_a(chunk); this.field_73244_f.remove(olong); -@@ -240,6 +276,8 @@ +@@ -240,6 +277,8 @@ } } @@ -171,7 +178,7 @@ this.field_73247_e.func_75817_a(); } -@@ -251,7 +289,6 @@ +@@ -251,7 +290,6 @@ return !this.field_73251_h.field_73058_d; } @@ -179,7 +186,23 @@ public String func_73148_d() { return "ServerChunkCache: " + this.field_73244_f.size() + " Drop: " + this.field_73248_b.size(); -@@ -283,7 +320,6 @@ +@@ -265,12 +303,14 @@ + @Nullable + public BlockPos func_180513_a(World p_180513_1_, String p_180513_2_, BlockPos p_180513_3_, boolean p_180513_4_) + { ++ BlockPos pos = net.minecraftforge.common.ForgeHooks.onGetNearestStructurePos(this.field_186029_c, p_180513_1_, p_180513_2_, p_180513_3_, p_180513_4_); ++ if (pos != null) return pos; + return this.field_186029_c.func_180513_a(p_180513_1_, p_180513_2_, p_180513_3_, p_180513_4_); + } + + public boolean func_193413_a(World p_193413_1_, String p_193413_2_, BlockPos p_193413_3_) + { +- return this.field_186029_c.func_193414_a(p_193413_1_, p_193413_2_, p_193413_3_); ++ return net.minecraftforge.common.ForgeHooks.isInsideStructure(this.field_186029_c, p_193413_1_, p_193413_2_, p_193413_3_) || this.field_186029_c.func_193414_a(p_193413_1_, p_193413_2_, p_193413_3_); + } + + public int func_73152_e() +@@ -283,7 +323,6 @@ return this.field_73244_f.containsKey(ChunkPos.func_77272_a(p_73149_1_, p_73149_2_)); } diff --git a/src/main/java/net/minecraftforge/common/ForgeHooks.java b/src/main/java/net/minecraftforge/common/ForgeHooks.java index d3422f3a8..425ade2bd 100644 --- a/src/main/java/net/minecraftforge/common/ForgeHooks.java +++ b/src/main/java/net/minecraftforge/common/ForgeHooks.java @@ -45,7 +45,6 @@ import net.minecraft.advancements.Advancement; import net.minecraft.advancements.AdvancementManager; import net.minecraft.block.Block; -import net.minecraft.block.BlockFarmland; import net.minecraft.block.BlockLiquid; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; @@ -110,8 +109,13 @@ import net.minecraft.util.text.event.ClickEvent; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; +import net.minecraft.world.WorldServer; +import net.minecraft.world.WorldProvider; import net.minecraft.world.EnumDifficulty; import net.minecraft.world.GameType; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.storage.IChunkLoader; +import net.minecraft.world.gen.IChunkGenerator; import net.minecraft.world.storage.loot.LootEntry; import net.minecraft.world.storage.loot.LootTable; import net.minecraft.world.storage.loot.LootTableManager; @@ -119,6 +123,7 @@ import net.minecraftforge.common.crafting.CraftingHelper; import net.minecraftforge.common.crafting.JsonContext; import net.minecraftforge.common.util.BlockSnapshot; +import net.minecraftforge.common.world.structure.StructureAttachRegistry; import net.minecraftforge.event.AnvilUpdateEvent; import net.minecraftforge.event.DifficultyChangeEvent; import net.minecraftforge.event.ForgeEventFactory; @@ -1512,4 +1517,25 @@ public static int getSerializerId(DataSerializer serializer, IntIdentityHashB } return id; } + + public static void postGenerateChunk(IChunkGenerator generator, World world, Chunk chunk, int x, int z){ + StructureAttachRegistry.postGenerateChunk(generator, world, chunk, x, z); + } + + public static void postPopulateGenerate(IChunkGenerator generator, World world, int x, int z){ + StructureAttachRegistry.postPopulate(generator, world, x, z); + } + + public static BlockPos onGetNearestStructurePos(IChunkGenerator generator, World worldIn, String structureName, BlockPos position, boolean findUnexplored) + { + return StructureAttachRegistry.getNearestStructurePos(generator, worldIn, structureName, position, findUnexplored); + } + + public static boolean isInsideStructure(IChunkGenerator generator, World worldIn, String structureName, BlockPos pos){ + return StructureAttachRegistry.isInsideStructure(generator, worldIn, structureName, pos); + } + + public static void onCreateChunkProvider(WorldServer worldServer, IChunkLoader loader ,WorldProvider provider, IChunkGenerator generator){ + StructureAttachRegistry.newStructureCollectionFor(worldServer, generator); + } } diff --git a/src/main/java/net/minecraftforge/common/world/structure/IStructureProvider.java b/src/main/java/net/minecraftforge/common/world/structure/IStructureProvider.java new file mode 100644 index 000000000..2a6583393 --- /dev/null +++ b/src/main/java/net/minecraftforge/common/world/structure/IStructureProvider.java @@ -0,0 +1,101 @@ +package net.minecraftforge.common.world.structure; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.init.Blocks; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.ChunkPrimer; +import net.minecraft.world.gen.IChunkGenerator; + +import javax.annotation.Nullable; +import java.util.Random; + +public interface IStructureProvider { + String getName() ; + + /** + * generate after {@link IChunkGenerator#generateChunk(int, int)} + * usually invoke {@link net.minecraft.world.gen.structure.MapGenStructure#generate(World, int, int, ChunkPrimer)} here. + * + * @param generator the {@link IChunkGenerator} + * @param world the {@link World} + * @param chunk the {@link ChunkReflection}, a special {@link ChunkPrimer} + * @param x the x of a chunk + * @param z the z of a chunk + */ + void generate(IChunkGenerator generator, World world, ChunkPrimer chunk, int x, int z); + + /** + * invoke after {@link IChunkGenerator#generateStructures(Chunk, int, int)} + * usually invoke {@link net.minecraft.world.gen.structure.MapGenStructure#generateStructure(World, Random, ChunkPos)} here + * + * @param generator the {@link IChunkGenerator} + * @param world the {@link World} + * @param random the random + * @param x the x of a chunk + * @param z the z of a chunk + */ + void generateStructure(IChunkGenerator generator, World world, Random random, int x, int z); + + /** + * locate the structure, for /locate command. + * + * @param generator + * @param worldIn + * @param structureName + * @param position + * @param findUnexplored + * @return null if not found. + */ + @Nullable + BlockPos getNearestStructurePos(IChunkGenerator generator,World worldIn, String structureName, BlockPos position, boolean findUnexplored); + + /** + * @param generator + * @param worldIn + * @param structureName + * @param pos + * @return false if not + */ + boolean isInsideStructure(IChunkGenerator generator,World worldIn, String structureName, BlockPos pos); + + class ChunkReflection extends ChunkPrimer { + private static final IBlockState DEFAULT_STATE = Blocks.AIR.getDefaultState(); + private int x; + private int z; + private Chunk chunk; + public ChunkReflection(Chunk chunk, int x, int z){ + this.chunk = chunk; + this.x = x; + this.z = z; + } + + @Override + public void setBlockState(int x, int y, int z, IBlockState state) { + chunk.setBlockState(new BlockPos(x, y, z), state); + } + + @Override + public IBlockState getBlockState(int x, int y, int z) { + return chunk.getBlockState(x, y, z); + } + + @Override + public int findGroundBlockIdx(int x, int z) + { + for (int j = 255; j >= 0; --j) + { + IBlockState iblockstate = getBlockState(x, j, z); + + if (iblockstate != null && iblockstate != DEFAULT_STATE) + { + return j; + } + } + + return 0; + } + } +} diff --git a/src/main/java/net/minecraftforge/common/world/structure/SingleStructureProvider.java b/src/main/java/net/minecraftforge/common/world/structure/SingleStructureProvider.java new file mode 100644 index 000000000..e96419d35 --- /dev/null +++ b/src/main/java/net/minecraftforge/common/world/structure/SingleStructureProvider.java @@ -0,0 +1,39 @@ +package net.minecraftforge.common.world.structure; + +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.ChunkPrimer; +import net.minecraft.world.gen.IChunkGenerator; +import net.minecraft.world.gen.structure.MapGenStructure; + +import javax.annotation.Nullable; +import java.util.Random; + +public record SingleStructureProvider(MapGenStructure structure) implements IStructureProvider { + @Override + public String getName() { + return structure.getStructureName(); + } + + @Override + public void generate(IChunkGenerator generator, World world, ChunkPrimer chunk, int x, int z) { + structure.generate(world, x, z, chunk); + } + + @Override + public void generateStructure(IChunkGenerator generator, World world, Random random, int x, int z) { + structure.generateStructure(world, random, new ChunkPos(x,z)); + } + + @Nullable + @Override + public BlockPos getNearestStructurePos(IChunkGenerator generator, World worldIn, String structureName, BlockPos position, boolean findUnexplored) { + return structure.getNearestStructurePos(worldIn, position, findUnexplored); + } + @Override + public boolean isInsideStructure(IChunkGenerator generator, World worldIn, String structureName, BlockPos pos){ + return structure.isInsideStructure(pos); + } +} diff --git a/src/main/java/net/minecraftforge/common/world/structure/StructureAttachRegistry.java b/src/main/java/net/minecraftforge/common/world/structure/StructureAttachRegistry.java new file mode 100644 index 000000000..37135f678 --- /dev/null +++ b/src/main/java/net/minecraftforge/common/world/structure/StructureAttachRegistry.java @@ -0,0 +1,43 @@ +package net.minecraftforge.common.world.structure; + +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.WorldServer; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.ChunkPrimer; +import net.minecraft.world.chunk.IChunkProvider; +import net.minecraft.world.gen.IChunkGenerator; + +import javax.annotation.Nullable; +import java.util.HashMap; + +public class StructureAttachRegistry { + private static final HashMap REGISTRY = new HashMap<>(); + public static StructureCollection newStructureCollectionFor(WorldServer worldServer, IChunkGenerator chunkGenerator){ + StructureCollection collection = new StructureCollection(worldServer.getSeed(), worldServer); + REGISTRY.put(chunkGenerator, collection); + return collection; + } + public static void postGenerateChunk(IChunkGenerator generator, World world, Chunk chunk, int x, int z){ + ChunkPrimer chunkPrimer = new IStructureProvider.ChunkReflection(chunk, x, z); + StructureCollection collection = REGISTRY.get(generator); + if (collection != null) collection.generate(generator, world, chunkPrimer, x, z); + } + public static void postPopulate(IChunkGenerator generator, World world, int x, int z){ + StructureCollection collection = REGISTRY.get(generator); + if (collection != null) collection.generateStructure(generator, world, collection.random, x, z); + } + + @Nullable + public static BlockPos getNearestStructurePos(IChunkGenerator generator, World worldIn, String structureName, BlockPos position, boolean findUnexplored) + { + StructureCollection collection = REGISTRY.get(generator); + if (collection != null) return collection.getNearestStructurePos(generator, worldIn, structureName, position, findUnexplored); + return null; + } + public static boolean isInsideStructure(IChunkGenerator generator, World worldIn, String structureName, BlockPos pos){ + StructureCollection collection = REGISTRY.get(generator); + if (collection != null) return collection.isInsideStructure(generator, worldIn, structureName, pos); + return false; + } +} diff --git a/src/main/java/net/minecraftforge/common/world/structure/StructureCollection.java b/src/main/java/net/minecraftforge/common/world/structure/StructureCollection.java new file mode 100644 index 000000000..9b54906ec --- /dev/null +++ b/src/main/java/net/minecraftforge/common/world/structure/StructureCollection.java @@ -0,0 +1,67 @@ +package net.minecraftforge.common.world.structure; + +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.WorldServer; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.ChunkPrimer; +import net.minecraft.world.gen.IChunkGenerator; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.world.StructureAttachEvent; + +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Random; + +public class StructureCollection implements IStructureProvider, Iterable{ + public final HashMap providers = new HashMap<>(); + public final Random random; + public StructureCollection(long seed, WorldServer worldServer) { + this.random = new Random(seed); + MinecraftForge.EVENT_BUS.post(new StructureAttachEvent(this, worldServer)); + } + + public StructureCollection add(IStructureProvider provider){ + providers.put(provider.getName(), provider); + return this; + } + @Override + public String getName() { + return "StructureCollection"; + } + + @Override + public void generate(IChunkGenerator generator, World world, ChunkPrimer chunk, int x, int z) { + for(IStructureProvider structureProvider: providers.values()){ + structureProvider.generate(generator, world, chunk, x, z); + } + } + + @Override + public void generateStructure(IChunkGenerator generator, World world, Random random, int x, int z) { + for(IStructureProvider structureProvider: providers.values()){ + structureProvider.generateStructure(generator, world, random, x, z); + } + } + + @Nullable + @Override + public BlockPos getNearestStructurePos(IChunkGenerator generator, World worldIn, String structureName, BlockPos position, boolean findUnexplored) { + IStructureProvider provider = providers.get(structureName); + if (provider != null) return provider.getNearestStructurePos(generator, worldIn, structureName, position, findUnexplored); + else return null; + } + + @Override + public boolean isInsideStructure(IChunkGenerator generator, World worldIn, String structureName, BlockPos pos) { + IStructureProvider provider = providers.get(structureName); + if (provider != null) return provider.isInsideStructure(generator, worldIn, structureName, pos); + else return false; + } + + @Override + public Iterator iterator() { + return providers.values().iterator(); + } +} diff --git a/src/main/java/net/minecraftforge/event/world/StructureAttachEvent.java b/src/main/java/net/minecraftforge/event/world/StructureAttachEvent.java new file mode 100644 index 000000000..2e6bd19e5 --- /dev/null +++ b/src/main/java/net/minecraftforge/event/world/StructureAttachEvent.java @@ -0,0 +1,24 @@ +package net.minecraftforge.event.world; + +import net.minecraft.world.WorldProvider; +import net.minecraft.world.WorldServer; +import net.minecraft.world.gen.IChunkGenerator; +import net.minecraftforge.common.world.structure.StructureCollection; +import net.minecraftforge.fml.common.eventhandler.Event; + +public class StructureAttachEvent extends Event { + private StructureCollection structureCollection; + private WorldServer worldServer; + public StructureAttachEvent(StructureCollection collection, WorldServer worldServer){ + this.structureCollection = collection; + this.worldServer = worldServer; + } + + public StructureCollection getStructureCollection() { + return structureCollection; + } + + public WorldServer getWorldServer() { + return worldServer; + } +} From c398376d9c7abf11c18475ec5576b32a2f4a9cbc Mon Sep 17 00:00:00 2001 From: Hileb <107909747+Ecdcaeb@users.noreply.github.com> Date: Sat, 2 Mar 2024 19:10:45 +0800 Subject: [PATCH 2/6] update java doc --- src/main/java/net/minecraftforge/common/ForgeHooks.java | 4 ++++ .../common/world/structure/IStructureProvider.java | 8 ++++++-- .../common/world/structure/StructureAttachRegistry.java | 4 ++++ .../common/world/structure/StructureCollection.java | 2 +- 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/minecraftforge/common/ForgeHooks.java b/src/main/java/net/minecraftforge/common/ForgeHooks.java index 425ade2bd..ab776c810 100644 --- a/src/main/java/net/minecraftforge/common/ForgeHooks.java +++ b/src/main/java/net/minecraftforge/common/ForgeHooks.java @@ -116,6 +116,7 @@ import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.storage.IChunkLoader; import net.minecraft.world.gen.IChunkGenerator; +import net.minecraft.world.gen.structure.MapGenStructureIO; import net.minecraft.world.storage.loot.LootEntry; import net.minecraft.world.storage.loot.LootTable; import net.minecraft.world.storage.loot.LootTableManager; @@ -1538,4 +1539,7 @@ public static boolean isInsideStructure(IChunkGenerator generator, World worldIn public static void onCreateChunkProvider(WorldServer worldServer, IChunkLoader loader ,WorldProvider provider, IChunkGenerator generator){ StructureAttachRegistry.newStructureCollectionFor(worldServer, generator); } + public static void onRecreateStructures(IChunkGenerator generator, World world, int x , int z){ + StructureAttachRegistry.recreateStructures(generator, world, x, z); + } } diff --git a/src/main/java/net/minecraftforge/common/world/structure/IStructureProvider.java b/src/main/java/net/minecraftforge/common/world/structure/IStructureProvider.java index 2a6583393..b71be406a 100644 --- a/src/main/java/net/minecraftforge/common/world/structure/IStructureProvider.java +++ b/src/main/java/net/minecraftforge/common/world/structure/IStructureProvider.java @@ -12,6 +12,9 @@ import javax.annotation.Nullable; import java.util.Random; +/** + * If modder do not have their own special proposal. Use the base implement {@link SingleStructureProvider} is enough. + */ public interface IStructureProvider { String getName() ; @@ -21,11 +24,11 @@ public interface IStructureProvider { * * @param generator the {@link IChunkGenerator} * @param world the {@link World} - * @param chunk the {@link ChunkReflection}, a special {@link ChunkPrimer} + * @param chunk the {@link ChunkReflection}, a special {@link ChunkPrimer} , Nullable. if it is a null, it is recreating Structures * @param x the x of a chunk * @param z the z of a chunk */ - void generate(IChunkGenerator generator, World world, ChunkPrimer chunk, int x, int z); + void generate(IChunkGenerator generator, World world, @Nullable ChunkPrimer chunk, int x, int z); /** * invoke after {@link IChunkGenerator#generateStructures(Chunk, int, int)} @@ -53,6 +56,7 @@ public interface IStructureProvider { BlockPos getNearestStructurePos(IChunkGenerator generator,World worldIn, String structureName, BlockPos position, boolean findUnexplored); /** + * usually invoke {@link net.minecraft.world.gen.structure.MapGenStructure#isInsideStructure(BlockPos)} * @param generator * @param worldIn * @param structureName diff --git a/src/main/java/net/minecraftforge/common/world/structure/StructureAttachRegistry.java b/src/main/java/net/minecraftforge/common/world/structure/StructureAttachRegistry.java index 37135f678..78f11f8a2 100644 --- a/src/main/java/net/minecraftforge/common/world/structure/StructureAttachRegistry.java +++ b/src/main/java/net/minecraftforge/common/world/structure/StructureAttachRegistry.java @@ -18,6 +18,10 @@ public static StructureCollection newStructureCollectionFor(WorldServer worldSer REGISTRY.put(chunkGenerator, collection); return collection; } + public static void recreateStructures(IChunkGenerator generator, World world, int x, int z){ + StructureCollection collection = REGISTRY.get(generator); + if (collection != null) collection.generate(generator, world, null, x, z); + } public static void postGenerateChunk(IChunkGenerator generator, World world, Chunk chunk, int x, int z){ ChunkPrimer chunkPrimer = new IStructureProvider.ChunkReflection(chunk, x, z); StructureCollection collection = REGISTRY.get(generator); diff --git a/src/main/java/net/minecraftforge/common/world/structure/StructureCollection.java b/src/main/java/net/minecraftforge/common/world/structure/StructureCollection.java index 9b54906ec..8524d5b06 100644 --- a/src/main/java/net/minecraftforge/common/world/structure/StructureCollection.java +++ b/src/main/java/net/minecraftforge/common/world/structure/StructureCollection.java @@ -32,7 +32,7 @@ public String getName() { } @Override - public void generate(IChunkGenerator generator, World world, ChunkPrimer chunk, int x, int z) { + public void generate(IChunkGenerator generator, World world, ChunkPrimer chunk, int x, int z) { for(IStructureProvider structureProvider: providers.values()){ structureProvider.generate(generator, world, chunk, x, z); } From 95c7d34869ce289b46c5c7a2abb82cf6292a4028 Mon Sep 17 00:00:00 2001 From: Hileb <107909747+Ecdcaeb@users.noreply.github.com> Date: Sat, 2 Mar 2024 19:17:35 +0800 Subject: [PATCH 3/6] space --- .../command/CommandLocate.java.patch | 11 ++++++++++ .../world/gen/ChunkProviderServer.java.patch | 20 +++++++++++++------ .../structure/MapGenStructureIO.java.patch | 13 ++++++++++++ .../structure/SingleStructureProvider.java | 1 + .../structure/StructureAttachRegistry.java | 10 ++++++++-- 5 files changed, 47 insertions(+), 8 deletions(-) create mode 100644 patches/minecraft/net/minecraft/command/CommandLocate.java.patch create mode 100644 patches/minecraft/net/minecraft/world/gen/structure/MapGenStructureIO.java.patch diff --git a/patches/minecraft/net/minecraft/command/CommandLocate.java.patch b/patches/minecraft/net/minecraft/command/CommandLocate.java.patch new file mode 100644 index 000000000..9da7546c5 --- /dev/null +++ b/patches/minecraft/net/minecraft/command/CommandLocate.java.patch @@ -0,0 +1,11 @@ +--- before/net/minecraft/command/CommandLocate.java ++++ after/net/minecraft/command/CommandLocate.java +@@ -54,7 +54,7 @@ + public List func_184883_a(MinecraftServer p_184883_1_, ICommandSender p_184883_2_, String[] p_184883_3_, @Nullable BlockPos p_184883_4_) + { + return p_184883_3_.length == 1 +- ? func_71530_a(p_184883_3_, new String[] {"Stronghold", "Monument", "Village", "Mansion", "EndCity", "Fortress", "Temple", "Mineshaft"}) ++ ? func_71530_a(p_184883_3_, net.minecraft.world.gen.structure.MapGenStructureIO.getStartNames()) + : Collections.emptyList(); + } + } diff --git a/patches/minecraft/net/minecraft/world/gen/ChunkProviderServer.java.patch b/patches/minecraft/net/minecraft/world/gen/ChunkProviderServer.java.patch index 3e4779c26..08e4e546f 100644 --- a/patches/minecraft/net/minecraft/world/gen/ChunkProviderServer.java.patch +++ b/patches/minecraft/net/minecraft/world/gen/ChunkProviderServer.java.patch @@ -127,7 +127,15 @@ crashreportcategory.func_71507_a("Generator", this.field_186029_c); throw new ReportedException(crashreport); } -@@ -199,8 +230,9 @@ +@@ -141,6 +172,7 @@ + { + chunk.func_177432_b(this.field_73251_h.func_82737_E()); + this.field_186029_c.func_180514_a(chunk, p_73239_1_, p_73239_2_); ++ net.minecraftforge.common.ForgeHooks.onRecreateStructures(this.field_186029_c, this.field_73251_h, p_73239_1_, p_73239_2_); + } + + return chunk; +@@ -199,8 +231,9 @@ { this.func_73242_b(chunk); chunk.func_177427_f(false); @@ -138,7 +146,7 @@ { return false; } -@@ -215,23 +247,28 @@ +@@ -215,23 +248,28 @@ this.field_73247_e.func_75818_b(); } @@ -169,7 +177,7 @@ this.func_73242_b(chunk); this.func_73243_a(chunk); this.field_73244_f.remove(olong); -@@ -240,6 +277,8 @@ +@@ -240,6 +278,8 @@ } } @@ -178,7 +186,7 @@ this.field_73247_e.func_75817_a(); } -@@ -251,7 +290,6 @@ +@@ -251,7 +291,6 @@ return !this.field_73251_h.field_73058_d; } @@ -186,7 +194,7 @@ public String func_73148_d() { return "ServerChunkCache: " + this.field_73244_f.size() + " Drop: " + this.field_73248_b.size(); -@@ -265,12 +303,14 @@ +@@ -265,12 +304,14 @@ @Nullable public BlockPos func_180513_a(World p_180513_1_, String p_180513_2_, BlockPos p_180513_3_, boolean p_180513_4_) { @@ -202,7 +210,7 @@ } public int func_73152_e() -@@ -283,7 +323,6 @@ +@@ -283,7 +324,6 @@ return this.field_73244_f.containsKey(ChunkPos.func_77272_a(p_73149_1_, p_73149_2_)); } diff --git a/patches/minecraft/net/minecraft/world/gen/structure/MapGenStructureIO.java.patch b/patches/minecraft/net/minecraft/world/gen/structure/MapGenStructureIO.java.patch new file mode 100644 index 000000000..c41813fc0 --- /dev/null +++ b/patches/minecraft/net/minecraft/world/gen/structure/MapGenStructureIO.java.patch @@ -0,0 +1,13 @@ +--- before/net/minecraft/world/gen/structure/MapGenStructureIO.java ++++ after/net/minecraft/world/gen/structure/MapGenStructureIO.java +@@ -120,4 +120,10 @@ + StructureEndCityPieces.func_186200_a(); + WoodlandMansionPieces.func_191153_a(); + } ++ ++ /* ======================================== FORGE START =====================================*/ ++ ++ public static String[] getStartNames(){ ++ return field_143040_a.keySet().toArray(new String[0]); ++ } + } diff --git a/src/main/java/net/minecraftforge/common/world/structure/SingleStructureProvider.java b/src/main/java/net/minecraftforge/common/world/structure/SingleStructureProvider.java index e96419d35..565259a7f 100644 --- a/src/main/java/net/minecraftforge/common/world/structure/SingleStructureProvider.java +++ b/src/main/java/net/minecraftforge/common/world/structure/SingleStructureProvider.java @@ -32,6 +32,7 @@ public void generateStructure(IChunkGenerator generator, World world, Random ran public BlockPos getNearestStructurePos(IChunkGenerator generator, World worldIn, String structureName, BlockPos position, boolean findUnexplored) { return structure.getNearestStructurePos(worldIn, position, findUnexplored); } + @Override public boolean isInsideStructure(IChunkGenerator generator, World worldIn, String structureName, BlockPos pos){ return structure.isInsideStructure(pos); diff --git a/src/main/java/net/minecraftforge/common/world/structure/StructureAttachRegistry.java b/src/main/java/net/minecraftforge/common/world/structure/StructureAttachRegistry.java index 78f11f8a2..d1b095ae0 100644 --- a/src/main/java/net/minecraftforge/common/world/structure/StructureAttachRegistry.java +++ b/src/main/java/net/minecraftforge/common/world/structure/StructureAttachRegistry.java @@ -5,28 +5,31 @@ import net.minecraft.world.WorldServer; import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.ChunkPrimer; -import net.minecraft.world.chunk.IChunkProvider; import net.minecraft.world.gen.IChunkGenerator; import javax.annotation.Nullable; import java.util.HashMap; -public class StructureAttachRegistry { +public final class StructureAttachRegistry { private static final HashMap REGISTRY = new HashMap<>(); + public static StructureCollection newStructureCollectionFor(WorldServer worldServer, IChunkGenerator chunkGenerator){ StructureCollection collection = new StructureCollection(worldServer.getSeed(), worldServer); REGISTRY.put(chunkGenerator, collection); return collection; } + public static void recreateStructures(IChunkGenerator generator, World world, int x, int z){ StructureCollection collection = REGISTRY.get(generator); if (collection != null) collection.generate(generator, world, null, x, z); } + public static void postGenerateChunk(IChunkGenerator generator, World world, Chunk chunk, int x, int z){ ChunkPrimer chunkPrimer = new IStructureProvider.ChunkReflection(chunk, x, z); StructureCollection collection = REGISTRY.get(generator); if (collection != null) collection.generate(generator, world, chunkPrimer, x, z); } + public static void postPopulate(IChunkGenerator generator, World world, int x, int z){ StructureCollection collection = REGISTRY.get(generator); if (collection != null) collection.generateStructure(generator, world, collection.random, x, z); @@ -39,9 +42,12 @@ public static BlockPos getNearestStructurePos(IChunkGenerator generator, World w if (collection != null) return collection.getNearestStructurePos(generator, worldIn, structureName, position, findUnexplored); return null; } + public static boolean isInsideStructure(IChunkGenerator generator, World worldIn, String structureName, BlockPos pos){ StructureCollection collection = REGISTRY.get(generator); if (collection != null) return collection.isInsideStructure(generator, worldIn, structureName, pos); return false; } + + private StructureAttachRegistry(){} } From b35acf6599dee96a0c4f48e6464b518b466d4f7f Mon Sep 17 00:00:00 2001 From: Hileb <107909747+Ecdcaeb@users.noreply.github.com> Date: Tue, 21 May 2024 23:39:24 +0800 Subject: [PATCH 4/6] fill java doc --- .../common/world/structure/IStructureProvider.java | 12 ++++++++++-- .../world/structure/SingleStructureProvider.java | 1 + .../world/structure/StructureAttachRegistry.java | 2 +- .../event/world/StructureAttachEvent.java | 9 +++++++++ 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/minecraftforge/common/world/structure/IStructureProvider.java b/src/main/java/net/minecraftforge/common/world/structure/IStructureProvider.java index b71be406a..882d0089b 100644 --- a/src/main/java/net/minecraftforge/common/world/structure/IStructureProvider.java +++ b/src/main/java/net/minecraftforge/common/world/structure/IStructureProvider.java @@ -13,7 +13,7 @@ import java.util.Random; /** - * If modder do not have their own special proposal. Use the base implement {@link SingleStructureProvider} is enough. + * If modder do not have their own special proposal, using the base implement {@link SingleStructureProvider} is enough. */ public interface IStructureProvider { String getName() ; @@ -43,7 +43,9 @@ public interface IStructureProvider { void generateStructure(IChunkGenerator generator, World world, Random random, int x, int z); /** - * locate the structure, for /locate command. + * Get the nearest structure location. + * + * Command /locate or treasure map. * * @param generator * @param worldIn @@ -56,6 +58,7 @@ public interface IStructureProvider { BlockPos getNearestStructurePos(IChunkGenerator generator,World worldIn, String structureName, BlockPos position, boolean findUnexplored); /** + * Checks whether a location is inside a structure. * usually invoke {@link net.minecraft.world.gen.structure.MapGenStructure#isInsideStructure(BlockPos)} * @param generator * @param worldIn @@ -65,6 +68,11 @@ public interface IStructureProvider { */ boolean isInsideStructure(IChunkGenerator generator,World worldIn, String structureName, BlockPos pos); + /** + * {@link ChunkPrimer} is the precursor material for building {@link Chunk|, which can achieve a large number of modifications with little overhead. + * Unfortunately, {@link ChunkPrimer} is generated and consumed internally in {@link IChunkGenerater}, and externally, we can only operate on {@link Chunk}. + * All operations of {@link ChunkReflection} are implemented on adult {@link Chunk}s. + */ class ChunkReflection extends ChunkPrimer { private static final IBlockState DEFAULT_STATE = Blocks.AIR.getDefaultState(); private int x; diff --git a/src/main/java/net/minecraftforge/common/world/structure/SingleStructureProvider.java b/src/main/java/net/minecraftforge/common/world/structure/SingleStructureProvider.java index 565259a7f..4fcf3aea7 100644 --- a/src/main/java/net/minecraftforge/common/world/structure/SingleStructureProvider.java +++ b/src/main/java/net/minecraftforge/common/world/structure/SingleStructureProvider.java @@ -12,6 +12,7 @@ import java.util.Random; public record SingleStructureProvider(MapGenStructure structure) implements IStructureProvider { + @Override public String getName() { return structure.getStructureName(); diff --git a/src/main/java/net/minecraftforge/common/world/structure/StructureAttachRegistry.java b/src/main/java/net/minecraftforge/common/world/structure/StructureAttachRegistry.java index d1b095ae0..a10cea019 100644 --- a/src/main/java/net/minecraftforge/common/world/structure/StructureAttachRegistry.java +++ b/src/main/java/net/minecraftforge/common/world/structure/StructureAttachRegistry.java @@ -11,7 +11,7 @@ import java.util.HashMap; public final class StructureAttachRegistry { - private static final HashMap REGISTRY = new HashMap<>(); + private static final HashMap REGISTRY = new HashMap<>(); public static StructureCollection newStructureCollectionFor(WorldServer worldServer, IChunkGenerator chunkGenerator){ StructureCollection collection = new StructureCollection(worldServer.getSeed(), worldServer); diff --git a/src/main/java/net/minecraftforge/event/world/StructureAttachEvent.java b/src/main/java/net/minecraftforge/event/world/StructureAttachEvent.java index 2e6bd19e5..52d7a70bd 100644 --- a/src/main/java/net/minecraftforge/event/world/StructureAttachEvent.java +++ b/src/main/java/net/minecraftforge/event/world/StructureAttachEvent.java @@ -6,6 +6,15 @@ import net.minecraftforge.common.world.structure.StructureCollection; import net.minecraftforge.fml.common.eventhandler.Event; +/** + * StructureAttachEvent is fired when a dimension is ready to be appended to the structures.
+ *
+ * This event is not {@link net.minecraftforge.fml.common.eventhandler.Cancelable;}.
+ *
+ * This event does not have a result. {@link HasResult}
+ *
+ * This event is fired on the {@link net.minecraftforge.common.MinecraftForge#EVENT_BUS}. + **/ public class StructureAttachEvent extends Event { private StructureCollection structureCollection; private WorldServer worldServer; From b03e68961d70a0834a4eceeab1e7a83f88c23352 Mon Sep 17 00:00:00 2001 From: Hileb <107909747+Ecdcaeb@users.noreply.github.com> Date: Sun, 16 Feb 2025 11:24:12 +0800 Subject: [PATCH 5/6] change names --- .../common/world/structure/StructureAttachRegistry.java | 2 +- .../common/world/structure/StructureCollection.java | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/minecraftforge/common/world/structure/StructureAttachRegistry.java b/src/main/java/net/minecraftforge/common/world/structure/StructureAttachRegistry.java index a10cea019..c796bdb47 100644 --- a/src/main/java/net/minecraftforge/common/world/structure/StructureAttachRegistry.java +++ b/src/main/java/net/minecraftforge/common/world/structure/StructureAttachRegistry.java @@ -14,7 +14,7 @@ public final class StructureAttachRegistry { private static final HashMap REGISTRY = new HashMap<>(); public static StructureCollection newStructureCollectionFor(WorldServer worldServer, IChunkGenerator chunkGenerator){ - StructureCollection collection = new StructureCollection(worldServer.getSeed(), worldServer); + StructureCollection collection = new StructureCollection("ForgeStructureCollection", worldServer.getSeed(), worldServer); REGISTRY.put(chunkGenerator, collection); return collection; } diff --git a/src/main/java/net/minecraftforge/common/world/structure/StructureCollection.java b/src/main/java/net/minecraftforge/common/world/structure/StructureCollection.java index 8524d5b06..24833ca5e 100644 --- a/src/main/java/net/minecraftforge/common/world/structure/StructureCollection.java +++ b/src/main/java/net/minecraftforge/common/world/structure/StructureCollection.java @@ -17,7 +17,8 @@ public class StructureCollection implements IStructureProvider, Iterable{ public final HashMap providers = new HashMap<>(); public final Random random; - public StructureCollection(long seed, WorldServer worldServer) { + public final String name; + public StructureCollection(String name, long seed, WorldServer worldServer) { this.random = new Random(seed); MinecraftForge.EVENT_BUS.post(new StructureAttachEvent(this, worldServer)); } @@ -28,7 +29,7 @@ public StructureCollection add(IStructureProvider provider){ } @Override public String getName() { - return "StructureCollection"; + return name; } @Override From 2e546c6905994faff2a9f8e5fadb8fd52395d83b Mon Sep 17 00:00:00 2001 From: Hileb <107909747+Ecdcaeb@users.noreply.github.com> Date: Tue, 5 Aug 2025 20:54:26 +0800 Subject: [PATCH 6/6] update? --- .../command/CommandLocate.java.patch | 11 ++ .../minecraft/world/WorldServer.java.patch | 49 ++++---- .../minecraft/world/chunk/Chunk.java.patch | 35 +++--- .../world/gen/ChunkProviderServer.java.patch | 119 ++++++------------ .../structure/MapGenStructureIO.java.patch | 13 ++ .../net/minecraftforge/common/ForgeHooks.java | 33 ++++- .../world/structure/IStructureProvider.java | 113 +++++++++++++++++ .../structure/SingleStructureProvider.java | 40 ++++++ .../world/structure/StructureAttachEvent.java | 36 ++++++ .../structure/StructureAttachRegistry.java | 53 ++++++++ .../world/structure/StructureCollection.java | 74 +++++++++++ 11 files changed, 448 insertions(+), 128 deletions(-) create mode 100644 patches/minecraft/net/minecraft/command/CommandLocate.java.patch create mode 100644 patches/minecraft/net/minecraft/world/gen/structure/MapGenStructureIO.java.patch create mode 100644 src/main/java/net/minecraftforge/common/world/structure/IStructureProvider.java create mode 100644 src/main/java/net/minecraftforge/common/world/structure/SingleStructureProvider.java create mode 100644 src/main/java/net/minecraftforge/common/world/structure/StructureAttachEvent.java create mode 100644 src/main/java/net/minecraftforge/common/world/structure/StructureAttachRegistry.java create mode 100644 src/main/java/net/minecraftforge/common/world/structure/StructureCollection.java diff --git a/patches/minecraft/net/minecraft/command/CommandLocate.java.patch b/patches/minecraft/net/minecraft/command/CommandLocate.java.patch new file mode 100644 index 000000000..9da7546c5 --- /dev/null +++ b/patches/minecraft/net/minecraft/command/CommandLocate.java.patch @@ -0,0 +1,11 @@ +--- before/net/minecraft/command/CommandLocate.java ++++ after/net/minecraft/command/CommandLocate.java +@@ -54,7 +54,7 @@ + public List func_184883_a(MinecraftServer p_184883_1_, ICommandSender p_184883_2_, String[] p_184883_3_, @Nullable BlockPos p_184883_4_) + { + return p_184883_3_.length == 1 +- ? func_71530_a(p_184883_3_, new String[] {"Stronghold", "Monument", "Village", "Mansion", "EndCity", "Fortress", "Temple", "Mineshaft"}) ++ ? func_71530_a(p_184883_3_, net.minecraft.world.gen.structure.MapGenStructureIO.getStartNames()) + : Collections.emptyList(); + } + } diff --git a/patches/minecraft/net/minecraft/world/WorldServer.java.patch b/patches/minecraft/net/minecraft/world/WorldServer.java.patch index fa5629f06..266fbdce0 100644 --- a/patches/minecraft/net/minecraft/world/WorldServer.java.patch +++ b/patches/minecraft/net/minecraft/world/WorldServer.java.patch @@ -479,7 +479,7 @@ public void func_72866_a(Entity p_72866_1_, boolean p_72866_2_) { if (!this.func_175735_ai() && (p_72866_1_ instanceof EntityAnimal || p_72866_1_ instanceof EntityWaterMob)) -@@ -852,20 +842,21 @@ +@@ -852,20 +842,23 @@ return this.field_73061_a.func_71268_U(); } @@ -487,7 +487,10 @@ protected IChunkProvider func_72970_h() { IChunkLoader ichunkloader = this.field_73019_z.func_75763_a(this.field_73011_w); - return new ChunkProviderServer(this, ichunkloader, this.field_73011_w.func_186060_c()); +- return new ChunkProviderServer(this, ichunkloader, this.field_73011_w.func_186060_c()); ++ var generator = this.field_73011_w.func_186060_c(); ++ net.minecraftforge.common.ForgeHooks.onCreateChunkProvider(this, ichunkloader, this.field_73011_w, generator); ++ return new ChunkProviderServer(this, ichunkloader, generator); } - @Override @@ -504,7 +507,7 @@ public void func_72963_a(WorldSettings p_72963_1_) { if (!this.field_72986_A.func_76070_v()) -@@ -881,16 +872,17 @@ +@@ -881,16 +874,17 @@ super.func_72963_a(p_72963_1_); } @@ -525,7 +528,7 @@ } throw new ReportedException(crashreport); -@@ -927,6 +919,7 @@ +@@ -927,6 +921,7 @@ } else { @@ -533,7 +536,7 @@ this.field_72987_B = true; BiomeProvider biomeprovider = this.field_73011_w.func_177499_m(); List list = biomeprovider.func_76932_a(); -@@ -952,8 +945,9 @@ +@@ -952,8 +947,9 @@ { i += random.nextInt(64) - random.nextInt(64); k += random.nextInt(64) - random.nextInt(64); @@ -544,7 +547,7 @@ { break; } -@@ -973,7 +967,7 @@ +@@ -973,7 +969,7 @@ { WorldGeneratorBonusChest worldgeneratorbonuschest = new WorldGeneratorBonusChest(); @@ -553,7 +556,7 @@ { int j = this.field_72986_A.func_76079_c() + this.field_73012_v.nextInt(6) - this.field_73012_v.nextInt(6); int k = this.field_72986_A.func_76074_e() + this.field_73012_v.nextInt(6) - this.field_73012_v.nextInt(6); -@@ -1011,6 +1005,7 @@ +@@ -1011,6 +1007,7 @@ } chunkproviderserver.func_186027_a(p_73044_1_); @@ -561,7 +564,7 @@ for (Chunk chunk : Lists.newArrayList(chunkproviderserver.func_189548_a())) { -@@ -1055,20 +1050,19 @@ +@@ -1055,20 +1052,19 @@ this.field_72986_A.func_176135_e(this.func_175723_af().func_177732_i()); this.field_73019_z.func_75755_a(this.field_72986_A, this.field_73061_a.func_184103_al().func_72378_q()); this.field_72988_C.func_75744_a(); @@ -584,7 +587,7 @@ { this.field_72996_f.add(entity); this.func_72923_a(entity); -@@ -1080,7 +1074,7 @@ +@@ -1080,7 +1076,7 @@ { if (p_184165_1_.field_70128_L) { @@ -593,7 +596,7 @@ return false; } else -@@ -1103,7 +1097,7 @@ +@@ -1103,7 +1099,7 @@ return false; } @@ -602,7 +605,7 @@ } this.func_72973_f(entity); -@@ -1113,7 +1107,6 @@ +@@ -1113,7 +1109,6 @@ } } @@ -610,7 +613,7 @@ public void func_72923_a(Entity p_72923_1_) { super.func_72923_a(p_72923_1_); -@@ -1130,7 +1123,6 @@ +@@ -1130,7 +1125,6 @@ } } @@ -618,7 +621,7 @@ public void func_72847_b(Entity p_72847_1_) { super.func_72847_b(p_72847_1_); -@@ -1147,22 +1139,11 @@ +@@ -1147,22 +1141,11 @@ } } @@ -642,7 +645,7 @@ return true; } else -@@ -1171,7 +1152,6 @@ +@@ -1171,7 +1154,6 @@ } } @@ -650,7 +653,7 @@ public void func_72960_a(Entity p_72960_1_, byte p_72960_2_) { this.func_73039_n().func_151248_b(p_72960_1_, new SPacketEntityStatus(p_72960_1_, p_72960_2_)); -@@ -1182,12 +1162,10 @@ +@@ -1182,12 +1164,10 @@ return (ChunkProviderServer)super.func_72863_F(); } @@ -665,7 +668,7 @@ explosion.func_77278_a(); explosion.func_77279_a(false); -@@ -1198,20 +1176,15 @@ +@@ -1198,20 +1178,15 @@ for (EntityPlayer entityplayer : this.field_73010_i) { @@ -688,7 +691,7 @@ public void func_175641_c(BlockPos p_175641_1_, Block p_175641_2_, int p_175641_3_, int p_175641_4_) { BlockEventData blockeventdata = new BlockEventData(p_175641_1_, p_175641_2_, p_175641_3_, p_175641_4_); -@@ -1238,19 +1211,7 @@ +@@ -1238,19 +1213,7 @@ { if (this.func_147485_a(blockeventdata)) { @@ -709,7 +712,7 @@ } } -@@ -1261,9 +1222,7 @@ +@@ -1261,9 +1224,7 @@ private boolean func_147485_a(BlockEventData p_147485_1_) { IBlockState iblockstate = this.func_180495_p(p_147485_1_.func_180328_a()); @@ -720,7 +723,7 @@ } public void func_73041_k() -@@ -1271,7 +1230,6 @@ +@@ -1271,7 +1232,6 @@ this.field_73019_z.func_75759_a(); } @@ -728,7 +731,7 @@ protected void func_72979_l() { boolean flag = this.func_72896_J(); -@@ -1279,36 +1237,35 @@ +@@ -1279,36 +1239,35 @@ if (this.field_73003_n != this.field_73004_o) { @@ -775,7 +778,7 @@ public MinecraftServer func_73046_m() { return this.field_73061_a; -@@ -1334,98 +1291,34 @@ +@@ -1334,98 +1293,34 @@ return this.field_73019_z.func_186340_h(); } @@ -883,7 +886,7 @@ { p_184159_1_.field_71135_a.func_147359_a(p_184159_9_); } -@@ -1437,20 +1330,17 @@ +@@ -1437,20 +1332,17 @@ return this.field_175741_N.get(p_175733_1_); } @@ -904,7 +907,7 @@ public BlockPos func_190528_a(String p_190528_1_, BlockPos p_190528_2_, boolean p_190528_3_) { return this.func_72863_F().func_180513_a(this, p_190528_1_, p_190528_2_, p_190528_3_); -@@ -1464,6 +1354,11 @@ +@@ -1464,6 +1356,11 @@ public FunctionManager func_193037_A() { return this.field_193036_D; diff --git a/patches/minecraft/net/minecraft/world/chunk/Chunk.java.patch b/patches/minecraft/net/minecraft/world/chunk/Chunk.java.patch index 03519c560..837d1417b 100644 --- a/patches/minecraft/net/minecraft/world/chunk/Chunk.java.patch +++ b/patches/minecraft/net/minecraft/world/chunk/Chunk.java.patch @@ -511,10 +511,11 @@ if (this.func_177419_t()) { if (p_186034_1_.func_185933_a(this, this.field_76635_g, this.field_76647_h)) -@@ -1012,8 +1017,10 @@ +@@ -1012,8 +1017,11 @@ { this.func_150809_p(); p_186034_1_.func_185931_b(this.field_76635_g, this.field_76647_h); ++ net.minecraftforge.common.ForgeHooks.postPopulateGenerate(p_186034_1_, this.field_76637_e, this.field_76635_g, this.field_76647_h); + net.minecraftforge.fml.common.registry.GameRegistry.generateWorld(this.field_76635_g, this.field_76647_h, this.field_76637_e, p_186034_1_, this.field_76637_e.func_72863_F()); this.func_76630_e(); } @@ -522,7 +523,7 @@ } public BlockPos func_177440_h(BlockPos p_177440_1_) -@@ -1068,7 +1075,7 @@ +@@ -1068,7 +1076,7 @@ { BlockPos blockpos = this.field_177447_w.poll(); @@ -531,7 +532,7 @@ { TileEntity tileentity = this.func_177422_i(blockpos); this.field_76637_e.func_175690_a(blockpos, tileentity); -@@ -1121,7 +1128,7 @@ +@@ -1121,7 +1129,7 @@ { if (this.field_76652_q.length != p_76602_1_.length) { @@ -540,7 +541,7 @@ } else { -@@ -1132,9 +1139,16 @@ +@@ -1132,9 +1140,16 @@ @SideOnly(Side.CLIENT) public void func_186033_a(PacketBuffer p_186033_1_, int p_186033_2_, boolean p_186033_3_) { @@ -558,7 +559,7 @@ { ExtendedBlockStorage extendedblockstorage = this.field_76652_q[i]; -@@ -1168,7 +1182,7 @@ +@@ -1168,7 +1183,7 @@ p_186033_1_.readBytes(this.field_76651_r); } @@ -567,7 +568,7 @@ { if (this.field_76652_q[j] != field_186036_a && (p_186033_2_ & 1 << j) != 0) { -@@ -1180,10 +1194,16 @@ +@@ -1180,10 +1195,16 @@ this.field_76646_k = true; this.func_76590_a(); @@ -584,7 +585,7 @@ } public Biome func_177411_a(BlockPos p_177411_1_, BiomeProvider p_177411_2_) -@@ -1194,9 +1214,14 @@ +@@ -1194,9 +1215,14 @@ if (k == 255) { @@ -601,7 +602,7 @@ } Biome biome1 = Biome.func_150568_d(k); -@@ -1212,7 +1237,7 @@ +@@ -1212,7 +1238,7 @@ { if (this.field_76651_r.length != p_76616_1_.length) { @@ -610,7 +611,7 @@ } else { -@@ -1231,7 +1256,7 @@ +@@ -1231,7 +1257,7 @@ { BlockPos blockpos = new BlockPos(this.field_76635_g << 4, 0, this.field_76647_h << 4); @@ -619,7 +620,7 @@ { if (this.field_76649_t >= 4096) { -@@ -1241,21 +1266,20 @@ +@@ -1241,21 +1267,20 @@ int j = this.field_76649_t % 16; int k = this.field_76649_t / 16 % 16; int l = this.field_76649_t / 256; @@ -645,7 +646,7 @@ { this.field_76637_e.func_175664_x(blockpos2); } -@@ -1280,9 +1304,9 @@ +@@ -1280,9 +1305,9 @@ { label44: @@ -657,7 +658,7 @@ { if (!this.func_150811_f(i, j)) { -@@ -1312,7 +1336,7 @@ +@@ -1312,7 +1337,7 @@ private void func_177441_y() { @@ -666,7 +667,7 @@ { this.field_76639_c[i] = true; } -@@ -1326,28 +1350,28 @@ +@@ -1326,28 +1351,28 @@ { if (p_180700_1_ == EnumFacing.EAST) { @@ -699,7 +700,7 @@ { this.func_150811_f(l, 0); } -@@ -1360,11 +1384,9 @@ +@@ -1360,11 +1385,9 @@ int i = this.func_76625_h(); boolean flag = false; boolean flag1 = false; @@ -713,7 +714,7 @@ { blockpos$mutableblockpos.func_181079_c(blockpos$mutableblockpos.func_177958_n(), j, blockpos$mutableblockpos.func_177952_p()); int k = this.func_177437_b(blockpos$mutableblockpos); -@@ -1384,11 +1406,11 @@ +@@ -1384,11 +1407,11 @@ } } @@ -727,7 +728,7 @@ { this.field_76637_e.func_175664_x(blockpos$mutableblockpos); } -@@ -1422,11 +1444,12 @@ +@@ -1422,11 +1445,12 @@ { if (this.field_76634_f.length != p_177420_1_.length) { @@ -741,7 +742,7 @@ } } -@@ -1495,5 +1518,56 @@ +@@ -1495,5 +1519,56 @@ IMMEDIATE, QUEUED, CHECK; diff --git a/patches/minecraft/net/minecraft/world/gen/ChunkProviderServer.java.patch b/patches/minecraft/net/minecraft/world/gen/ChunkProviderServer.java.patch index cc801a8c2..3472452a9 100644 --- a/patches/minecraft/net/minecraft/world/gen/ChunkProviderServer.java.patch +++ b/patches/minecraft/net/minecraft/world/gen/ChunkProviderServer.java.patch @@ -1,61 +1,14 @@ --- before/net/minecraft/world/gen/ChunkProviderServer.java +++ after/net/minecraft/world/gen/ChunkProviderServer.java -@@ -4,6 +4,7 @@ - import com.google.common.collect.Sets; - import it.unimi.dsi.fastutil.longs.Long2ObjectMap; - import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; -+import it.unimi.dsi.fastutil.objects.ObjectIterator; - import java.io.IOException; - import java.util.Collection; - import java.util.Iterator; -@@ -29,11 +30,12 @@ - public class ChunkProviderServer implements IChunkProvider - { - private static final Logger field_147417_b = LogManager.getLogger(); -- private final Set field_73248_b = Sets.newHashSet(); -+ private final Set field_73248_b = Sets.newHashSet(); - public final IChunkGenerator field_186029_c; +@@ -34,6 +34,7 @@ public final IChunkLoader field_73247_e; -- public final Long2ObjectMap field_73244_f = new Long2ObjectOpenHashMap<>(8192); -+ public final Long2ObjectMap field_73244_f = new Long2ObjectOpenHashMap(8192); + public final Long2ObjectMap field_73244_f = new Long2ObjectOpenHashMap<>(8192); public final WorldServer field_73251_h; + private final Set loadingChunks = com.google.common.collect.Sets.newHashSet(); public ChunkProviderServer(WorldServer p_i46838_1_, IChunkLoader p_i46838_2_, IChunkGenerator p_i46838_3_) { -@@ -51,25 +53,27 @@ - { - if (this.field_73251_h.field_73011_w.func_186056_c(p_189549_1_.field_76635_g, p_189549_1_.field_76647_h)) - { -- this.field_73248_b.add(ChunkPos.func_77272_a(p_189549_1_.field_76635_g, p_189549_1_.field_76647_h)); -+ this.field_73248_b.add(Long.valueOf(ChunkPos.func_77272_a(p_189549_1_.field_76635_g, p_189549_1_.field_76647_h))); - p_189549_1_.field_189550_d = true; - } - } - - public void func_73240_a() - { -- for (Chunk chunk : this.field_73244_f.values()) -+ ObjectIterator objectiterator = this.field_73244_f.values().iterator(); -+ -+ while (objectiterator.hasNext()) - { -+ Chunk chunk = (Chunk)objectiterator.next(); - this.func_189549_a(chunk); - } - } - - @Nullable -- @Override - public Chunk func_186026_b(int p_186026_1_, int p_186026_2_) - { - long i = ChunkPos.func_77272_a(p_186026_1_, p_186026_2_); -- Chunk chunk = this.field_73244_f.get(i); -+ Chunk chunk = (Chunk)this.field_73244_f.get(i); - - if (chunk != null) - { -@@ -82,24 +86,50 @@ +@@ -82,24 +83,49 @@ @Nullable public Chunk func_186028_c(int p_186028_1_, int p_186028_2_) { @@ -74,7 +27,7 @@ - if (chunk != null) + long pos = ChunkPos.func_77272_a(p_186028_1_, p_186028_2_); + chunk = net.minecraftforge.common.ForgeChunkManager.fetchDormantChunk(pos, this.field_73251_h); -+ if (chunk != null || !(this.field_73247_e instanceof net.minecraft.world.chunk.storage.AnvilChunkLoader)) ++ if (chunk != null || !(this.field_73247_e instanceof net.minecraft.world.chunk.storage.AnvilChunkLoader loader)) { + if (!loadingChunks.add(pos)) net.minecraftforge.fml.common.FMLLog.bigWarning("There is an attempt to load a chunk ({},{}) in dimension {} that is already being loaded. This will cause weird chunk breakages.", p_186028_1_, p_186028_2_, this.field_73251_h.field_73011_w.getDimension()); + if (chunk == null) chunk = this.func_73239_e(p_186028_1_, p_186028_2_); @@ -90,7 +43,6 @@ + } + else + { -+ net.minecraft.world.chunk.storage.AnvilChunkLoader loader = (net.minecraft.world.chunk.storage.AnvilChunkLoader) this.field_73247_e; + if (runnable == null || !net.minecraftforge.common.ForgeChunkManager.asyncChunkLoading) + chunk = net.minecraftforge.common.chunkio.ChunkIOExecutor.syncChunkLoad(this.field_73251_h, loader, this, p_186028_1_, p_186028_2_); + else if (loader.func_191063_a(p_186028_1_, p_186028_2_)) @@ -111,25 +63,23 @@ public Chunk func_186025_d(int p_186025_1_, int p_186025_2_) { Chunk chunk = this.func_186028_c(p_186025_1_, p_186025_2_); -@@ -117,7 +147,7 @@ - CrashReport crashreport = CrashReport.func_85055_a(throwable, "Exception generating new chunk"); - CrashReportCategory crashreportcategory = crashreport.func_85058_a("Chunk to be generated"); - crashreportcategory.func_71507_a("Location", String.format("%d,%d", p_186025_1_, p_186025_2_)); -- crashreportcategory.func_71507_a("Position hash", i); -+ crashreportcategory.func_71507_a("Position hash", Long.valueOf(i)); - crashreportcategory.func_71507_a("Generator", this.field_186029_c); - throw new ReportedException(crashreport); +@@ -111,6 +137,7 @@ + try + { + chunk = this.field_186029_c.func_185932_a(p_186025_1_, p_186025_2_); ++ net.minecraftforge.common.ForgeHooks.postGenerateChunk(this.field_186029_c, this.field_73251_h, chunk, p_186025_1_, p_186025_2_); + } + catch (Throwable throwable) + { +@@ -141,6 +168,7 @@ + { + chunk.func_177432_b(this.field_73251_h.func_82737_E()); + this.field_186029_c.func_180514_a(chunk, p_73239_1_, p_73239_2_); ++ net.minecraftforge.common.ForgeHooks.onRecreateStructures(this.field_186029_c, this.field_73251_h, p_73239_1_, p_73239_2_); } -@@ -186,7 +216,7 @@ - int i = 0; - List list = Lists.newArrayList(this.field_73244_f.values()); - -- for (int j = 0; j < list.size(); j++) -+ for (int j = 0; j < list.size(); ++j) - { - Chunk chunk = list.get(j); -@@ -199,8 +229,9 @@ + return chunk; +@@ -199,8 +227,9 @@ { this.func_73242_b(chunk); chunk.func_177427_f(false); @@ -140,7 +90,7 @@ { return false; } -@@ -215,31 +246,38 @@ +@@ -215,13 +244,17 @@ this.field_73247_e.func_75818_b(); } @@ -159,11 +109,7 @@ Iterator iterator = this.field_73248_b.iterator(); for (int i = 0; i < 100 && iterator.hasNext(); iterator.remove()) - { - Long olong = iterator.next(); -- Chunk chunk = this.field_73244_f.get(olong); -+ Chunk chunk = (Chunk)this.field_73244_f.get(olong); - +@@ -232,6 +265,7 @@ if (chunk != null && chunk.field_189550_d) { chunk.func_76623_d(); @@ -171,9 +117,7 @@ this.func_73242_b(chunk); this.func_73243_a(chunk); this.field_73244_f.remove(olong); -- i++; -+ ++i; - } +@@ -240,6 +274,8 @@ } } @@ -182,7 +126,7 @@ this.field_73247_e.func_75817_a(); } -@@ -251,7 +289,6 @@ +@@ -251,7 +287,6 @@ return !this.field_73251_h.field_73058_d; } @@ -190,11 +134,18 @@ public String func_73148_d() { return "ServerChunkCache: " + this.field_73244_f.size() + " Drop: " + this.field_73248_b.size(); -@@ -283,7 +320,6 @@ - return this.field_73244_f.containsKey(ChunkPos.func_77272_a(p_73149_1_, p_73149_2_)); +@@ -265,12 +300,12 @@ + @Nullable + public BlockPos func_180513_a(World p_180513_1_, String p_180513_2_, BlockPos p_180513_3_, boolean p_180513_4_) + { +- return this.field_186029_c.func_180513_a(p_180513_1_, p_180513_2_, p_180513_3_, p_180513_4_); ++ return this.field_186029_c.func_180513_a(p_180513_1_, p_180513_2_, p_180513_3_, p_180513_4_) instanceof BlockPos blockPos ? blockPos : net.minecraftforge.common.ForgeHooks.onGetNearestStructurePos(this.field_186029_c, p_180513_1_, p_180513_2_, p_180513_3_, p_180513_4_); } -- @Override - public boolean func_191062_e(int p_191062_1_, int p_191062_2_) + public boolean func_193413_a(World p_193413_1_, String p_193413_2_, BlockPos p_193413_3_) { - return this.field_73244_f.containsKey(ChunkPos.func_77272_a(p_191062_1_, p_191062_2_)) || this.field_73247_e.func_191063_a(p_191062_1_, p_191062_2_); +- return this.field_186029_c.func_193414_a(p_193413_1_, p_193413_2_, p_193413_3_); ++ return this.field_186029_c.func_193414_a(p_193413_1_, p_193413_2_, p_193413_3_) || net.minecraftforge.common.ForgeHooks.isInsideStructure(this.field_186029_c, p_193413_1_, p_193413_2_, p_193413_3_); + } + + public int func_73152_e() diff --git a/patches/minecraft/net/minecraft/world/gen/structure/MapGenStructureIO.java.patch b/patches/minecraft/net/minecraft/world/gen/structure/MapGenStructureIO.java.patch new file mode 100644 index 000000000..e28cff8bf --- /dev/null +++ b/patches/minecraft/net/minecraft/world/gen/structure/MapGenStructureIO.java.patch @@ -0,0 +1,13 @@ +--- before/net/minecraft/world/gen/structure/MapGenStructureIO.java ++++ after/net/minecraft/world/gen/structure/MapGenStructureIO.java +@@ -120,4 +120,10 @@ + StructureEndCityPieces.func_186200_a(); + WoodlandMansionPieces.func_191153_a(); + } ++ ++ /* ======================================== FORGE START =====================================*/ ++ ++ public static String[] getStartNames(){ ++ return field_143040_a.keySet().toArray(new String[0]); ++ } + } diff --git a/src/main/java/net/minecraftforge/common/ForgeHooks.java b/src/main/java/net/minecraftforge/common/ForgeHooks.java index 3aaf57048..cc1f0bf29 100644 --- a/src/main/java/net/minecraftforge/common/ForgeHooks.java +++ b/src/main/java/net/minecraftforge/common/ForgeHooks.java @@ -110,10 +110,10 @@ import net.minecraft.util.text.TextComponentString; import net.minecraft.util.text.TextFormatting; import net.minecraft.util.text.event.ClickEvent; -import net.minecraft.world.IBlockAccess; -import net.minecraft.world.World; -import net.minecraft.world.EnumDifficulty; -import net.minecraft.world.GameType; +import net.minecraft.world.*; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.storage.IChunkLoader; +import net.minecraft.world.gen.IChunkGenerator; import net.minecraft.world.storage.loot.LootEntry; import net.minecraft.world.storage.loot.LootTable; import net.minecraft.world.storage.loot.LootTableManager; @@ -121,6 +121,7 @@ import net.minecraftforge.common.crafting.CraftingHelper; import net.minecraftforge.common.crafting.JsonContext; import net.minecraftforge.common.util.BlockSnapshot; +import net.minecraftforge.common.world.structure.StructureAttachRegistry; import net.minecraftforge.event.AnvilUpdateEvent; import net.minecraftforge.event.DifficultyChangeEvent; import net.minecraftforge.event.ForgeEventFactory; @@ -1567,4 +1568,28 @@ public static String gatherMixinInfo(Throwable throwable){ return ""; } + + public static void postGenerateChunk(IChunkGenerator generator, World world, Chunk chunk, int x, int z){ + StructureAttachRegistry.postGenerateChunk(generator, world, chunk, x, z); + } + + public static void postPopulateGenerate(IChunkGenerator generator, World world, int x, int z){ + StructureAttachRegistry.postPopulate(generator, world, x, z); + } + + public static BlockPos onGetNearestStructurePos(IChunkGenerator generator, World worldIn, String structureName, BlockPos position, boolean findUnexplored) + { + return StructureAttachRegistry.getNearestStructurePos(generator, worldIn, structureName, position, findUnexplored); + } + + public static boolean isInsideStructure(IChunkGenerator generator, World worldIn, String structureName, BlockPos pos){ + return StructureAttachRegistry.isInsideStructure(generator, worldIn, structureName, pos); + } + + public static void onCreateChunkProvider(WorldServer worldServer, IChunkLoader loader , WorldProvider provider, IChunkGenerator generator){ + StructureAttachRegistry.newStructureCollectionFor(worldServer, generator); + } + public static void onRecreateStructures(IChunkGenerator generator, World world, int x , int z){ + StructureAttachRegistry.recreateStructures(generator, world, x, z); + } } diff --git a/src/main/java/net/minecraftforge/common/world/structure/IStructureProvider.java b/src/main/java/net/minecraftforge/common/world/structure/IStructureProvider.java new file mode 100644 index 000000000..e426c7ebd --- /dev/null +++ b/src/main/java/net/minecraftforge/common/world/structure/IStructureProvider.java @@ -0,0 +1,113 @@ +package net.minecraftforge.common.world.structure; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.init.Blocks; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.ChunkPrimer; +import net.minecraft.world.gen.IChunkGenerator; + +import javax.annotation.Nullable; +import java.util.Random; + +/** + * If modder do not have their own special proposal, using the base implement {@link SingleStructureProvider} is enough. + */ +public interface IStructureProvider { + String getName() ; + + /** + * generate after {@link IChunkGenerator#generateChunk(int, int)} + * usually invoke {@link net.minecraft.world.gen.structure.MapGenStructure#generate(World, int, int, ChunkPrimer)} here. + * + * @param generator the {@link IChunkGenerator} + * @param world the {@link World} + * @param chunk the {@link ChunkReflection}, a special {@link ChunkPrimer} , Nullable. if it is a null, it is recreating Structures + * @param x the x of a chunk + * @param z the z of a chunk + */ + void generate(IChunkGenerator generator, World world, @Nullable ChunkPrimer chunk, int x, int z); + + /** + * invoke after {@link IChunkGenerator#generateStructures(Chunk, int, int)} + * usually invoke {@link net.minecraft.world.gen.structure.MapGenStructure#generateStructure(World, Random, ChunkPos)} here + * + * @param generator the {@link IChunkGenerator} + * @param world the {@link World} + * @param random the random + * @param x the x of a chunk + * @param z the z of a chunk + */ + void generateStructure(IChunkGenerator generator, World world, Random random, int x, int z); + + /** + * Get the nearest structure location. + * + * Command /locate or treasure map. + * + * @param generator + * @param worldIn + * @param structureName + * @param position + * @param findUnexplored + * @return null if not found. + */ + @Nullable + BlockPos getNearestStructurePos(IChunkGenerator generator,World worldIn, String structureName, BlockPos position, boolean findUnexplored); + + /** + * Checks whether a location is inside a structure. + * usually invoke {@link net.minecraft.world.gen.structure.MapGenStructure#isInsideStructure(BlockPos)} + * @param generator + * @param worldIn + * @param structureName + * @param pos + * @return false if not + */ + boolean isInsideStructure(IChunkGenerator generator,World worldIn, String structureName, BlockPos pos); + + /** + * {@link ChunkPrimer} is the precursor material for building {@link Chunk|, which can achieve a large number of modifications with little overhead. + * Unfortunately, {@link ChunkPrimer} is generated and consumed internally in {@link IChunkGenerater}, and externally, we can only operate on {@link Chunk}. + * All operations of {@link ChunkReflection} are implemented on adult {@link Chunk}s. + */ + class ChunkReflection extends ChunkPrimer { + private static final IBlockState DEFAULT_STATE = Blocks.AIR.getDefaultState(); + private int x; + private int z; + private Chunk chunk; + public ChunkReflection(Chunk chunk, int x, int z){ + this.chunk = chunk; + this.x = x; + this.z = z; + } + + @Override + public void setBlockState(int x, int y, int z, IBlockState state) { + chunk.setBlockState(new BlockPos(x, y, z), state); + } + + @Override + public IBlockState getBlockState(int x, int y, int z) { + return chunk.getBlockState(x, y, z); + } + + @Override + public int findGroundBlockIdx(int x, int z) + { + for (int j = 255; j >= 0; --j) + { + IBlockState iblockstate = getBlockState(x, j, z); + + if (iblockstate != DEFAULT_STATE) + { + return j; + } + } + + return 0; + } + } +} diff --git a/src/main/java/net/minecraftforge/common/world/structure/SingleStructureProvider.java b/src/main/java/net/minecraftforge/common/world/structure/SingleStructureProvider.java new file mode 100644 index 000000000..0428ef9ac --- /dev/null +++ b/src/main/java/net/minecraftforge/common/world/structure/SingleStructureProvider.java @@ -0,0 +1,40 @@ +package net.minecraftforge.common.world.structure; + +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.world.World; +import net.minecraft.world.chunk.ChunkPrimer; +import net.minecraft.world.gen.IChunkGenerator; +import net.minecraft.world.gen.structure.MapGenStructure; + +import javax.annotation.Nullable; +import java.util.Random; + +public record SingleStructureProvider(MapGenStructure structure) implements IStructureProvider { + + @Override + public String getName() { + return structure.getStructureName(); + } + + @Override + public void generate(IChunkGenerator generator, World world, ChunkPrimer chunk, int x, int z) { + structure.generate(world, x, z, chunk); + } + + @Override + public void generateStructure(IChunkGenerator generator, World world, Random random, int x, int z) { + structure.generateStructure(world, random, new ChunkPos(x,z)); + } + + @Nullable + @Override + public BlockPos getNearestStructurePos(IChunkGenerator generator, World worldIn, String structureName, BlockPos position, boolean findUnexplored) { + return structure.getNearestStructurePos(worldIn, position, findUnexplored); + } + + @Override + public boolean isInsideStructure(IChunkGenerator generator, World worldIn, String structureName, BlockPos pos){ + return structure.isInsideStructure(pos); + } +} diff --git a/src/main/java/net/minecraftforge/common/world/structure/StructureAttachEvent.java b/src/main/java/net/minecraftforge/common/world/structure/StructureAttachEvent.java new file mode 100644 index 000000000..44a6c0901 --- /dev/null +++ b/src/main/java/net/minecraftforge/common/world/structure/StructureAttachEvent.java @@ -0,0 +1,36 @@ +package net.minecraftforge.event.world; + +import net.minecraft.world.WorldProvider; +import net.minecraft.world.WorldServer; +import net.minecraft.world.gen.IChunkGenerator; +import net.minecraftforge.common.world.structure.StructureCollection; +import net.minecraftforge.fml.common.eventhandler.Event; + +/** + * StructureAttachEvent is fired when a dimension is ready to be appended to the structures.
+ *
+ * This event is not {@link net.minecraftforge.fml.common.eventhandler.Cancelable;}.
+ *
+ * This event does not have a result. {@link HasResult}
+ *
+ * This event is fired on the {@link net.minecraftforge.common.MinecraftForge#EVENT_BUS}. + **/ +public class StructureAttachEvent extends Event { + + private final StructureCollection structureCollection; + + private final WorldServer worldServer; + + public StructureAttachEvent(StructureCollection collection, WorldServer worldServer){ + this.structureCollection = collection; + this.worldServer = worldServer; + } + + public StructureCollection getStructureCollection() { + return structureCollection; + } + + public WorldServer getWorldServer() { + return worldServer; + } +} \ No newline at end of file diff --git a/src/main/java/net/minecraftforge/common/world/structure/StructureAttachRegistry.java b/src/main/java/net/minecraftforge/common/world/structure/StructureAttachRegistry.java new file mode 100644 index 000000000..c796bdb47 --- /dev/null +++ b/src/main/java/net/minecraftforge/common/world/structure/StructureAttachRegistry.java @@ -0,0 +1,53 @@ +package net.minecraftforge.common.world.structure; + +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.WorldServer; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.ChunkPrimer; +import net.minecraft.world.gen.IChunkGenerator; + +import javax.annotation.Nullable; +import java.util.HashMap; + +public final class StructureAttachRegistry { + private static final HashMap REGISTRY = new HashMap<>(); + + public static StructureCollection newStructureCollectionFor(WorldServer worldServer, IChunkGenerator chunkGenerator){ + StructureCollection collection = new StructureCollection("ForgeStructureCollection", worldServer.getSeed(), worldServer); + REGISTRY.put(chunkGenerator, collection); + return collection; + } + + public static void recreateStructures(IChunkGenerator generator, World world, int x, int z){ + StructureCollection collection = REGISTRY.get(generator); + if (collection != null) collection.generate(generator, world, null, x, z); + } + + public static void postGenerateChunk(IChunkGenerator generator, World world, Chunk chunk, int x, int z){ + ChunkPrimer chunkPrimer = new IStructureProvider.ChunkReflection(chunk, x, z); + StructureCollection collection = REGISTRY.get(generator); + if (collection != null) collection.generate(generator, world, chunkPrimer, x, z); + } + + public static void postPopulate(IChunkGenerator generator, World world, int x, int z){ + StructureCollection collection = REGISTRY.get(generator); + if (collection != null) collection.generateStructure(generator, world, collection.random, x, z); + } + + @Nullable + public static BlockPos getNearestStructurePos(IChunkGenerator generator, World worldIn, String structureName, BlockPos position, boolean findUnexplored) + { + StructureCollection collection = REGISTRY.get(generator); + if (collection != null) return collection.getNearestStructurePos(generator, worldIn, structureName, position, findUnexplored); + return null; + } + + public static boolean isInsideStructure(IChunkGenerator generator, World worldIn, String structureName, BlockPos pos){ + StructureCollection collection = REGISTRY.get(generator); + if (collection != null) return collection.isInsideStructure(generator, worldIn, structureName, pos); + return false; + } + + private StructureAttachRegistry(){} +} diff --git a/src/main/java/net/minecraftforge/common/world/structure/StructureCollection.java b/src/main/java/net/minecraftforge/common/world/structure/StructureCollection.java new file mode 100644 index 000000000..490c1d035 --- /dev/null +++ b/src/main/java/net/minecraftforge/common/world/structure/StructureCollection.java @@ -0,0 +1,74 @@ +package net.minecraftforge.common.world.structure; + +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.WorldServer; +import net.minecraft.world.chunk.ChunkPrimer; +import net.minecraft.world.gen.IChunkGenerator; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.world.StructureAttachEvent; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Random; + +public class StructureCollection implements IStructureProvider, Iterable{ + + public final HashMap providers = new HashMap<>(); + + public final Random random; + + public final String name; + + public StructureCollection(String name, long seed, WorldServer worldServer) { + this.name = name; + this.random = new Random(seed); + MinecraftForge.EVENT_BUS.post(new StructureAttachEvent(this, worldServer)); + } + + public StructureCollection add(IStructureProvider provider){ + providers.put(provider.getName(), provider); + return this; + } + @Override + public String getName() { + return name; + } + + @Override + public void generate(IChunkGenerator generator, World world, ChunkPrimer chunk, int x, int z) { + for(IStructureProvider structureProvider: providers.values()){ + structureProvider.generate(generator, world, chunk, x, z); + } + } + + @Override + public void generateStructure(IChunkGenerator generator, World world, Random random, int x, int z) { + for(IStructureProvider structureProvider: providers.values()){ + structureProvider.generateStructure(generator, world, random, x, z); + } + } + + @Nullable + @Override + public BlockPos getNearestStructurePos(IChunkGenerator generator, World worldIn, String structureName, BlockPos position, boolean findUnexplored) { + IStructureProvider provider = providers.get(structureName); + if (provider != null) return provider.getNearestStructurePos(generator, worldIn, structureName, position, findUnexplored); + else return null; + } + + @Override + public boolean isInsideStructure(IChunkGenerator generator, World worldIn, String structureName, BlockPos pos) { + IStructureProvider provider = providers.get(structureName); + if (provider != null) return provider.isInsideStructure(generator, worldIn, structureName, pos); + else return false; + } + + @Nonnull + @Override + public Iterator iterator() { + return providers.values().iterator(); + } +}