Skip to content
This repository was archived by the owner on Jun 3, 2024. It is now read-only.

Commit a31d6ac

Browse files
committed
Merge branch 'world_event'
2 parents a57fa28 + 628bb5b commit a31d6ac

9 files changed

Lines changed: 663 additions & 1 deletion

File tree

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Minecraft Forge, Patchwork Project
3+
* Copyright (c) 2016-2020, 2019-2020
4+
*
5+
* This library is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Lesser General Public
7+
* License as published by the Free Software Foundation version 2.1
8+
* of the License.
9+
*
10+
* This library is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this library; if not, write to the Free Software
17+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18+
*/
19+
20+
package com.patchworkmc.impl.event.world;
21+
22+
import java.util.Collections;
23+
import java.util.List;
24+
25+
import net.minecraftforge.common.MinecraftForge;
26+
import net.minecraftforge.event.world.WorldEvent;
27+
28+
import net.minecraft.entity.EntityCategory;
29+
import net.minecraft.util.math.BlockPos;
30+
import net.minecraft.world.IWorld;
31+
import net.minecraft.world.biome.Biome;
32+
import net.minecraft.world.level.LevelInfo;
33+
34+
public class WorldEvents {
35+
public static boolean onCreateWorldSpawn(IWorld world, LevelInfo settings) {
36+
return MinecraftForge.EVENT_BUS.post(new WorldEvent.CreateSpawnPosition(world, settings));
37+
}
38+
39+
public static List<Biome.SpawnEntry> getPotentialSpawns(IWorld world, EntityCategory type, BlockPos pos, List<Biome.SpawnEntry> oldSpawns) {
40+
WorldEvent.PotentialSpawns event = new WorldEvent.PotentialSpawns(world, type, pos, oldSpawns);
41+
42+
if (MinecraftForge.EVENT_BUS.post(event)) {
43+
return Collections.emptyList();
44+
}
45+
46+
return event.getList();
47+
}
48+
49+
public static void onWorldLoad(IWorld world) {
50+
MinecraftForge.EVENT_BUS.post(new WorldEvent.Load(world));
51+
}
52+
53+
public static void onWorldUnload(IWorld world) {
54+
MinecraftForge.EVENT_BUS.post(new WorldEvent.Unload(world));
55+
}
56+
57+
public static void onWorldSave(IWorld world) {
58+
MinecraftForge.EVENT_BUS.post(new WorldEvent.Save(world));
59+
}
60+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Minecraft Forge, Patchwork Project
3+
* Copyright (c) 2016-2020, 2019-2020
4+
*
5+
* This library is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Lesser General Public
7+
* License as published by the Free Software Foundation version 2.1
8+
* of the License.
9+
*
10+
* This library is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this library; if not, write to the Free Software
17+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18+
*/
19+
20+
package com.patchworkmc.mixin.event.world;
21+
22+
import org.spongepowered.asm.mixin.Mixin;
23+
import org.spongepowered.asm.mixin.gen.Accessor;
24+
25+
import net.minecraft.world.IWorld;
26+
import net.minecraft.world.gen.chunk.ChunkGenerator;
27+
28+
@Mixin(ChunkGenerator.class)
29+
public interface MixinChunkGenerator {
30+
@Accessor
31+
IWorld getWorld();
32+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Minecraft Forge, Patchwork Project
3+
* Copyright (c) 2016-2020, 2019-2020
4+
*
5+
* This library is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Lesser General Public
7+
* License as published by the Free Software Foundation version 2.1
8+
* of the License.
9+
*
10+
* This library is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this library; if not, write to the Free Software
17+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18+
*/
19+
20+
package com.patchworkmc.mixin.event.world;
21+
22+
import java.util.function.BiFunction;
23+
24+
import org.spongepowered.asm.mixin.Mixin;
25+
import org.spongepowered.asm.mixin.injection.At;
26+
import org.spongepowered.asm.mixin.injection.Inject;
27+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
28+
29+
import net.minecraft.util.profiler.Profiler;
30+
import net.minecraft.world.chunk.ChunkManager;
31+
import net.minecraft.world.dimension.Dimension;
32+
import net.minecraft.world.dimension.DimensionType;
33+
import net.minecraft.world.level.LevelProperties;
34+
import net.minecraft.world.World;
35+
import net.minecraft.client.world.ClientWorld;
36+
37+
import com.patchworkmc.impl.event.world.WorldEvents;
38+
39+
@Mixin(ClientWorld.class)
40+
public abstract class MixinClientWorld extends World {
41+
protected MixinClientWorld(LevelProperties levelProperties, DimensionType dimensionType, BiFunction<World, Dimension, ChunkManager> chunkManagerProvider, Profiler profiler, boolean isClient) {
42+
super(levelProperties, dimensionType, chunkManagerProvider, profiler, isClient);
43+
}
44+
45+
@Inject(method = "<init>", at = @At(value = "TAIL"))
46+
private void postConstruct(CallbackInfo info) {
47+
WorldEvents.onWorldLoad((ClientWorld) (Object) this);
48+
}
49+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Minecraft Forge, Patchwork Project
3+
* Copyright (c) 2016-2020, 2019-2020
4+
*
5+
* This library is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Lesser General Public
7+
* License as published by the Free Software Foundation version 2.1
8+
* of the License.
9+
*
10+
* This library is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this library; if not, write to the Free Software
17+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18+
*/
19+
20+
package com.patchworkmc.mixin.event.world;
21+
22+
import org.objectweb.asm.Opcodes;
23+
import org.spongepowered.asm.mixin.Mixin;
24+
import org.spongepowered.asm.mixin.Shadow;
25+
import org.spongepowered.asm.mixin.injection.At;
26+
import org.spongepowered.asm.mixin.injection.Inject;
27+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
28+
29+
import net.minecraft.client.MinecraftClient;
30+
import net.minecraft.client.world.ClientWorld;
31+
32+
import com.patchworkmc.impl.event.world.WorldEvents;
33+
34+
@Mixin(MinecraftClient.class)
35+
public class MixinMinecraftClient {
36+
@Shadow
37+
public ClientWorld world;
38+
39+
@Inject(method = "joinWorld", at = @At(value = "HEAD"))
40+
private void hookJoinWorld(CallbackInfo info) {
41+
if (this.world != null) {
42+
WorldEvents.onWorldUnload(this.world);
43+
}
44+
}
45+
46+
@Inject(method = "disconnect(Lnet/minecraft/client/gui/screen/Screen;)V", at = @At(value = "FIELD", opcode = Opcodes.GETFIELD, target = "net/minecraft/client/MinecraftClient.world : Lnet/minecraft/client/world/ClientWorld;"))
47+
private void hookDisconnect(CallbackInfo info) {
48+
if (this.world != null) {
49+
WorldEvents.onWorldUnload(this.world);
50+
}
51+
}
52+
}
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/*
2+
* Minecraft Forge, Patchwork Project
3+
* Copyright (c) 2016-2020, 2019-2020
4+
*
5+
* This library is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Lesser General Public
7+
* License as published by the Free Software Foundation version 2.1
8+
* of the License.
9+
*
10+
* This library is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this library; if not, write to the Free Software
17+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18+
*/
19+
20+
package com.patchworkmc.mixin.event.world;
21+
22+
import java.io.IOException;
23+
import java.util.Iterator;
24+
import java.util.Map;
25+
26+
import org.spongepowered.asm.mixin.Final;
27+
import org.spongepowered.asm.mixin.Mixin;
28+
import org.spongepowered.asm.mixin.Shadow;
29+
import org.spongepowered.asm.mixin.injection.At;
30+
import org.spongepowered.asm.mixin.injection.Redirect;
31+
32+
import net.minecraft.server.MinecraftServer;
33+
import net.minecraft.server.ServerTask;
34+
import net.minecraft.server.world.ServerWorld;
35+
import net.minecraft.util.NonBlockingThreadExecutor;
36+
import net.minecraft.world.dimension.DimensionType;
37+
38+
import com.patchworkmc.impl.event.world.WorldEvents;
39+
40+
@Mixin(MinecraftServer.class)
41+
public abstract class MixinMinecraftServer extends NonBlockingThreadExecutor<ServerTask> {
42+
public MixinMinecraftServer(String name) {
43+
super(name);
44+
}
45+
46+
@Shadow
47+
@Final
48+
private Map<DimensionType, ServerWorld> worlds;
49+
50+
/*
51+
// This is a variant of the world load hook that is less likely to break mods and more likely to break on updates.
52+
// Should get called once per loop, regardless of which if branch it takes.
53+
@Inject(
54+
method = "createWorlds",
55+
slice = @Slice(
56+
from = @At(value = "INVOKE", target = "java/util/Iterator.hasNext ()Z")
57+
),
58+
at = @At(value = "JUMP", opcode = Opcodes.GOTO),
59+
locals = LocalCapture.CAPTURE_FAILHARD
60+
)
61+
private void hookCreateWorlds(WorldSaveHandler worldSaveHandler, LevelProperties properties, LevelInfo levelInfo, WorldGenerationProgressListener worldGenerationProgressListener, CallbackInfo ci, ServerWorld serverWorld, ServerWorld serverWorld2, Iterator var7, DimensionType dimensionType) {
62+
WorldEvents.onWorldLoad(this.worlds.get(dimensionType));
63+
}
64+
65+
*/
66+
67+
// This injection gets called at the beginning of each loop, and is used to special case the overworld dimension type.
68+
@Redirect(method = "createWorlds", at = @At(value = "INVOKE", target = "java/util/Iterator.next ()Ljava/lang/Object;"))
69+
private Object proxyNextWorldToSpecialCaseOverworld(Iterator<DimensionType> iterator) {
70+
DimensionType type = iterator.next();
71+
72+
if (type == DimensionType.OVERWORLD) {
73+
WorldEvents.onWorldLoad(this.worlds.get(type));
74+
}
75+
76+
return type;
77+
}
78+
79+
// This injection handles every other dimension type.
80+
@Redirect(method = "createWorlds", at = @At(value = "INVOKE", target = "java/util/Map.put (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", ordinal = 1))
81+
private Object proxyPutWorld(Map<Object, Object> worlds, Object type, Object world) {
82+
worlds.put(type, world);
83+
WorldEvents.onWorldLoad((ServerWorld) world);
84+
85+
return world;
86+
}
87+
88+
@Redirect(method = "shutdown", at = @At(value = "INVOKE", target = "net/minecraft/server/world/ServerWorld.close ()V"))
89+
private void proxyClose(ServerWorld world) throws IOException {
90+
WorldEvents.onWorldUnload(world);
91+
world.close();
92+
}
93+
94+
// TODO: DimensionManager, and move this into a seperate module/*
95+
/*@Inject(method = "createWorlds", at = @At(value = "HEAD"))
96+
private void hookCreateWorldsForDimensionRegistration(CallbackInfo info) {
97+
DimensionManager.fireRegister();
98+
}
99+
100+
@Shadow
101+
private int ticks;
102+
103+
@Redirect(method = "tickWorlds", at = @At(value = "INVOKE_STRING", target = "net/minecraft/util/profiler/DisableableProfiler.swap (Ljava/lang/String;)V", args = { "ldc=connection" }))
104+
private void hookTickWorldsForDimensionUnload(DisableableProfiler profiler, String section) {
105+
MinecraftServer server = (MinecraftServer) (Object) this;
106+
profiler.swap("dim_unloading");
107+
DimensionManager.unloadWorlds(server, this.ticks % 200);
108+
profiler.swap(section);
109+
}
110+
111+
@Redirect(method = "getWorld", at = @At(value = "INVOKE", target = "java/util/Map.get (Ljava/lang/Object;)Ljava/lang/Object;"))
112+
private Object hookGetWorld(Map worlds, Object type) {
113+
MinecraftServer server = (MinecraftServer) (Object) this;
114+
return DimensionManager.getWorld(server, type, true, true);
115+
}*/
116+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Minecraft Forge, Patchwork Project
3+
* Copyright (c) 2016-2020, 2019-2020
4+
*
5+
* This library is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Lesser General Public
7+
* License as published by the Free Software Foundation version 2.1
8+
* of the License.
9+
*
10+
* This library is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this library; if not, write to the Free Software
17+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18+
*/
19+
20+
package com.patchworkmc.mixin.event.world;
21+
22+
import java.util.function.BiFunction;
23+
24+
import org.spongepowered.asm.mixin.Mixin;
25+
import org.spongepowered.asm.mixin.injection.At;
26+
import org.spongepowered.asm.mixin.injection.Inject;
27+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
28+
29+
import net.minecraft.util.profiler.Profiler;
30+
import net.minecraft.world.chunk.ChunkManager;
31+
import net.minecraft.world.dimension.Dimension;
32+
import net.minecraft.world.dimension.DimensionType;
33+
import net.minecraft.world.level.LevelInfo;
34+
import net.minecraft.world.level.LevelProperties;
35+
import net.minecraft.world.World;
36+
import net.minecraft.server.world.ServerWorld;
37+
38+
import com.patchworkmc.impl.event.world.WorldEvents;
39+
40+
@Mixin(ServerWorld.class)
41+
public abstract class MixinServerWorld extends World {
42+
protected MixinServerWorld(LevelProperties levelProperties, DimensionType dimensionType, BiFunction<World, Dimension, ChunkManager> chunkManagerProvider, Profiler profiler, boolean isClient) {
43+
super(levelProperties, dimensionType, chunkManagerProvider, profiler, isClient);
44+
}
45+
46+
@Inject(method = "save", at = @At(value = "INVOKE", target = "net/minecraft/server/world/ServerChunkManager.save (Z)V"))
47+
private void hookSave(CallbackInfo info) {
48+
WorldEvents.onWorldSave((ServerWorld) (Object) this);
49+
}
50+
51+
// TODO: consider adding a shift to before obtaining the ChunkManager to match forge more closely
52+
// I don't think it'll make much of a difference.
53+
@Inject(method = "init", cancellable = true, at = @At(value = "INVOKE", target = "net/minecraft/world/gen/chunk/ChunkGenerator.getBiomeSource ()Lnet/minecraft/world/biome/source/BiomeSource;"))
54+
private void hookInitForCreateWorldSpawn(LevelInfo levelInfo, CallbackInfo info) {
55+
ServerWorld world = (ServerWorld) (Object) this;
56+
57+
if (WorldEvents.onCreateWorldSpawn(world, levelInfo)) {
58+
info.cancel();
59+
}
60+
}
61+
}

0 commit comments

Comments
 (0)