Skip to content

Commit 528dc00

Browse files
committed
[Savestates] Fixed world being unloaded after loadstate
1 parent 8f310d8 commit 528dc00

File tree

7 files changed

+140
-36
lines changed

7 files changed

+140
-36
lines changed

src/main/java/com/minecrafttas/tasmod/mixin/savestates/AccessorPlayerChunkMap.java

Lines changed: 0 additions & 22 deletions
This file was deleted.
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package com.minecrafttas.tasmod.mixin.savestates;
2+
3+
import java.util.Collections;
4+
import java.util.Comparator;
5+
import java.util.Iterator;
6+
import java.util.List;
7+
8+
import org.spongepowered.asm.mixin.Final;
9+
import org.spongepowered.asm.mixin.Mixin;
10+
import org.spongepowered.asm.mixin.Shadow;
11+
12+
import com.google.common.collect.ComparisonChain;
13+
import com.minecrafttas.tasmod.savestates.handlers.SavestateWorldHandler;
14+
import com.minecrafttas.tasmod.util.Ducks.PlayerChunkMapDuck;
15+
16+
import net.minecraft.entity.player.EntityPlayerMP;
17+
import net.minecraft.server.management.PlayerChunkMap;
18+
import net.minecraft.server.management.PlayerChunkMapEntry;
19+
import net.minecraft.world.WorldProvider;
20+
import net.minecraft.world.WorldServer;
21+
22+
@Mixin(PlayerChunkMap.class)
23+
public class MixinPlayerChunkMap implements PlayerChunkMapDuck {
24+
25+
@Shadow
26+
@Final
27+
private List<EntityPlayerMP> players;
28+
@Shadow
29+
private boolean sortMissingChunks;
30+
@Shadow
31+
@Final
32+
private List<PlayerChunkMapEntry> entriesWithoutChunks;
33+
@Shadow
34+
private boolean sortSendToPlayers;
35+
@Shadow
36+
@Final
37+
private List<PlayerChunkMapEntry> pendingSendToPlayers;
38+
@Shadow
39+
@Final
40+
private WorldServer world;
41+
42+
/**
43+
* @return The players from the specified chunk map
44+
* @see SavestateWorldHandler#addPlayerToChunkMap()
45+
*/
46+
@Override
47+
public List<EntityPlayerMP> getPlayers() {
48+
return players;
49+
}
50+
51+
/**
52+
* {@inheritDoc}
53+
* @see SavestateWorldHandler#addPlayersToChunkMap()
54+
*/
55+
@Override
56+
public void forceTick() {
57+
this.sortMissingChunks = false;
58+
Collections.sort(this.entriesWithoutChunks, new Comparator<PlayerChunkMapEntry>() {
59+
public int compare(PlayerChunkMapEntry playerChunkMapEntry, PlayerChunkMapEntry playerChunkMapEntry2) {
60+
return ComparisonChain.start().compare(playerChunkMapEntry.getClosestPlayerDistance(), playerChunkMapEntry2.getClosestPlayerDistance()).result();
61+
}
62+
});
63+
64+
this.sortSendToPlayers = false;
65+
Collections.sort(this.pendingSendToPlayers, new Comparator<PlayerChunkMapEntry>() {
66+
67+
public int compare(PlayerChunkMapEntry playerChunkMapEntry, PlayerChunkMapEntry playerChunkMapEntry2) {
68+
return ComparisonChain.start().compare(playerChunkMapEntry.getClosestPlayerDistance(), playerChunkMapEntry2.getClosestPlayerDistance()).result();
69+
}
70+
});
71+
72+
if (!this.pendingSendToPlayers.isEmpty()) {
73+
74+
int i = 81;
75+
Iterator<PlayerChunkMapEntry> iterator2 = this.pendingSendToPlayers.iterator();
76+
77+
while (iterator2.hasNext()) {
78+
PlayerChunkMapEntry playerChunkMapEntry3 = (PlayerChunkMapEntry) iterator2.next();
79+
if (playerChunkMapEntry3.sendToPlayers()) {
80+
iterator2.remove();
81+
if (--i < 0) {
82+
break;
83+
}
84+
}
85+
}
86+
}
87+
88+
if (this.players.isEmpty()) {
89+
WorldProvider worldProvider = this.world.provider;
90+
if (!worldProvider.canRespawnHere()) {
91+
this.world.getChunkProvider().queueUnloadAll();
92+
}
93+
}
94+
}
95+
}

src/main/java/com/minecrafttas/tasmod/registries/TASmodKeybinds.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,6 @@ public enum TASmodKeybinds {
3939
TEST1("Various Testing", "TASmod", Keyboard.KEY_F12, () -> {
4040
}, VirtualKeybindings::isKeyDown),
4141
TEST2("Various Testing2", "TASmod", Keyboard.KEY_F7, () -> {
42-
// try {
43-
// TASmodClient.client = new Client("localhost", TASmod.networkingport - 1, TASmodPackets.values(), mc.getSession().getProfile().getName(), true);
44-
// } catch (Exception e) {
45-
// e.printStackTrace();
46-
// }
47-
// TASmodClient.controller.setTASState(TASstate.PLAYBACK);
4842
}, VirtualKeybindings::isKeyDown);
4943

5044
private Keybind keybind;

src/main/java/com/minecrafttas/tasmod/savestates/SavestateHandlerServer.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -394,9 +394,7 @@ public void loadState(int savestateIndex, boolean tickrate0, boolean changeIndex
394394
server.getPlayerList().sendMessage(new TextComponentString(TextFormatting.GREEN + "Savestate " + indexToLoad + " loaded"));
395395

396396
// Add players to the chunk
397-
server.getPlayerList().getPlayers().forEach(player -> {
398-
worldHandler.addPlayerToServerChunk(player);
399-
});
397+
worldHandler.addPlayersToServerChunks();
400398

401399
worldHandler.sendChunksToClient();
402400

src/main/java/com/minecrafttas/tasmod/savestates/handlers/SavestateWorldHandler.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44

55
import java.util.List;
66

7-
import com.minecrafttas.tasmod.mixin.savestates.AccessorPlayerChunkMap;
87
import com.minecrafttas.tasmod.mixin.savestates.MixinChunkProviderServer;
98
import com.minecrafttas.tasmod.savestates.SavestateHandlerClient;
109
import com.minecrafttas.tasmod.util.Ducks.ChunkProviderDuck;
10+
import com.minecrafttas.tasmod.util.Ducks.PlayerChunkMapDuck;
1111
import com.minecrafttas.tasmod.util.Ducks.WorldServerDuck;
1212
import com.minecrafttas.tasmod.util.LoggerMarkers;
1313

@@ -55,6 +55,15 @@ public void enableLevelSaving() {
5555
}
5656
}
5757

58+
/**
59+
* Add players to their respective chunks
60+
*/
61+
public void addPlayersToServerChunks() {
62+
server.getPlayerList().getPlayers().forEach(player -> {
63+
addPlayerToServerChunk(player);
64+
});
65+
}
66+
5867
/**
5968
* Just like {@link SavestateHandlerClient#addPlayerToClientChunk(EntityPlayer)}, adds the player to the chunk on the server.
6069
* This prevents the player from being able to place block inside of him
@@ -138,6 +147,11 @@ public void addPlayersToChunkMap() {
138147
break;
139148
}
140149
}
150+
151+
// Tick the player chunk map to send the chunks to the clients
152+
for (WorldServer world : worlds) {
153+
((PlayerChunkMapDuck) world.getPlayerChunkMap()).forceTick();
154+
}
141155
}
142156

143157
/**
@@ -150,15 +164,14 @@ private void addPlayerToChunkMap(WorldServer world, EntityPlayerMP player) {
150164
int playerChunkPosY = (int) player.posZ >> 4;
151165
PlayerChunkMap playerChunkMap = world.getPlayerChunkMap();
152166

153-
List<EntityPlayerMP> players = ((AccessorPlayerChunkMap) playerChunkMap).getPlayers();
167+
List<EntityPlayerMP> players = ((PlayerChunkMapDuck) playerChunkMap).getPlayers();
154168

155169
if (players.contains(player)) {
156170
LOGGER.debug(LoggerMarkers.Savestate, "Not adding player {} to chunkmap, player already exists", player.getName());
157171
} else {
158172
playerChunkMap.addPlayer(player);
159173
}
160-
Chunk chunk = world.getChunkProvider().provideChunk(playerChunkPosX, playerChunkPosY);
161-
chunk.addEntity(player);
174+
world.getChunkProvider().provideChunk(playerChunkPosX, playerChunkPosY);
162175

163176
world.spawnEntity(player);
164177
}

src/main/java/com/minecrafttas/tasmod/util/Ducks.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
package com.minecrafttas.tasmod.util;
22

3+
import java.util.List;
4+
5+
import com.minecrafttas.tasmod.mixin.savestates.MixinPlayerChunkMap;
6+
7+
import net.minecraft.entity.player.EntityPlayerMP;
8+
39
/**
410
* Oh boy, ducks! I can't help but quack up when they waddle their way into the code. :duck:
511
* But let me tell you a little secret: I have a love-hate relationship with ducks. Not the adorable feathered creatures, mind you, but those sneaky little programming devils that swim in the deep waters of out-of-scope variables.
@@ -129,4 +135,24 @@ public static interface WorldClientDuck {
129135
*/
130136
public void clearEntityList();
131137
}
138+
139+
/**
140+
* Quacks the {@link MixinPlayerChunkMap}
141+
*/
142+
public static interface PlayerChunkMapDuck {
143+
/**
144+
* @return The list of players of this chunk map
145+
*/
146+
public List<EntityPlayerMP> getPlayers();
147+
148+
/**
149+
* <p>Forces a tick in the chunk map without being dependent on the world time.
150+
* <p>The chunk map is responsible for sending the necessary chunks to the client.<br>
151+
* However, to properly do that, the chunks have to be sorted first, which happens every few world ticks.
152+
*
153+
* <p>This method sorts and sends the chunks to the clients, without waiting for the world time
154+
* @see MixinPlayerChunkMap#forceTick()
155+
*/
156+
public void forceTick();
157+
}
132158
}

src/main/resources/tasmod.mixin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"savestates.AccessorAnvilChunkLoader",
1313
"savestates.AccessorChunkLoader",
1414
"savestates.AccessorEntityLivingBase",
15-
"savestates.AccessorPlayerChunkMap",
15+
"savestates.MixinPlayerChunkMap",
1616
"savestates.MixinChunkProviderServer",
1717
"savestates.MixinNetHandlerPlayServer",
1818
"savestates.MixinScoreboard",

0 commit comments

Comments
 (0)