Skip to content

Instantly share code, notes, and snippets.

@bfu4
Created March 16, 2021 02:11
Show Gist options
  • Save bfu4/f224f4736f11328a4c2304c38f09e0c3 to your computer and use it in GitHub Desktop.
Save bfu4/f224f4736f11328a4c2304c38f09e0c3 to your computer and use it in GitHub Desktop.
force bukkit to render all maps by id on player join (fuck you)

if you aren't going to use CraftBukkit give up now

i also do not care if "you probably shouldn't use craftbukkit non-reflectively" as i'd prefer not to waste my time writing an implementation that's actually useful. i'll depend on what i need to depend to get what i need. this is simply a cheat on top of a cheat, and is probably good insight on how you could achieve this.

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_16_R3.map.CraftMapView;
import org.bukkit.craftbukkit.v1_16_R3.map.RenderData;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
public class PlayerJoinListener implements Listener {
// CraftMapView#renderCache
private static Field craftBukkitRenderCache;
static {
try {
craftBukkitRenderCache = CraftMapView.class.getDeclaredField("renderCache");
craftBukkitRenderCache.setAccessible(true);
} catch (NoSuchFieldException e) {
// do something
}
}
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
// We need CraftPlayer for this invocation
CraftPlayer player = (CraftPlayer) event.getPlayer();
// Supply this, we're going to do this in a lambda
List<Integer> mapsYouWantToRender = getTheMapsYouWantToRender();
// Lambda for iteration
mapsYouWantToRender.forEach(map -> {
// get a map by the current iterated map id. you store these somewhere, i'd hope
MapView view = Bukkit.getMap(map);
// don't do anything if it's null
if (view != null) {
// cast to get the mapview we need
CraftMapView craftMapView = (CraftMapView) view;
try {
// steal the cache
Map<CraftPlayer, RenderData> cache = (Map<CraftPlayer, RenderData>) field.get(craftMapView);
// check to see if the cache contains the player who just logged in
if (!cache.containsKey(player)) {
// no? lets render the mapview to the player
craftMapView.render(player);
// update the map (send it back)
player.sendMap(view);
}
} catch (IllegalAccessException e) {
// whatever
}
}
});
}
}
import org.bukkit.map.MapRenderer;
import org.bukkit.map.MapCanvas;
import org.bukkit.map.MapView;
public class SomeRenderer extends MapRenderer {
public SomeRenderer() {
// The first trick of this is feeding "true" into the super call
// Since MapRenderer is really a CraftRenderer, this sets CraftRenderer#isContextual to true
// We need to trick the actual render implementation so that the player it caches is not null,
// so we need CraftRenderer#isContextual to return true.
super(true);
}
@Override
public void render(MapView mapView, MapCanvas mapCanvas, Player player) {
// Do something
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment