Upstream Paper
This commit is contained in:
@@ -23,6 +23,9 @@
|
||||
*/
|
||||
package co.aikar.timings;
|
||||
|
||||
import javax.annotation.Nonnull; // Akarin - javax.annotation
|
||||
import javax.annotation.Nullable; // Akarin - javax.annotation
|
||||
|
||||
/**
|
||||
* Provides an ability to time sections of code within the Minecraft Server
|
||||
*/
|
||||
@@ -32,6 +35,7 @@ public interface Timing extends AutoCloseable {
|
||||
*
|
||||
* @return Timing
|
||||
*/
|
||||
@Nonnull // Akarin - javax.annotation
|
||||
Timing startTiming();
|
||||
default Timing startTiming(boolean assertThread) { return startTiming(); }; // Akarin
|
||||
default Timing startTimingUnsafe() { return startTiming(); }; // Akarin
|
||||
@@ -51,6 +55,7 @@ public interface Timing extends AutoCloseable {
|
||||
*
|
||||
* @return Timing
|
||||
*/
|
||||
@Nonnull // Akarin - javax.annotation
|
||||
Timing startTimingIfSync();
|
||||
default Timing startTimingIfSync(boolean assertThread) { return startTimingIfSync(); }; // Akarin
|
||||
|
||||
@@ -64,8 +69,9 @@ public interface Timing extends AutoCloseable {
|
||||
void stopTimingIfSync();
|
||||
|
||||
/**
|
||||
* Stops timing and disregards current timing data.
|
||||
* @deprecated Doesn't do anything - Removed
|
||||
*/
|
||||
@Deprecated
|
||||
void abort();
|
||||
|
||||
/**
|
||||
@@ -73,6 +79,7 @@ public interface Timing extends AutoCloseable {
|
||||
*
|
||||
* @return TimingHandler
|
||||
*/
|
||||
@Nullable
|
||||
TimingHandler getTimingHandler();
|
||||
|
||||
@Override
|
||||
|
||||
@@ -26,17 +26,25 @@ package co.aikar.timings;
|
||||
import co.aikar.util.LoadingIntMap;
|
||||
import io.akarin.server.core.AkarinGlobalConfig;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.annotation.Nonnull; // Akarin - javax.annotation
|
||||
import javax.annotation.Nullable; // Akarin - javax.annotation
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
class TimingHandler implements Timing {
|
||||
|
||||
private static AtomicInteger idPool = new AtomicInteger(1);
|
||||
static Deque<TimingHandler> TIMING_STACK = new ArrayDeque<>();
|
||||
final int id = idPool.getAndIncrement();
|
||||
|
||||
final String name;
|
||||
final TimingIdentifier identifier;
|
||||
private final boolean verbose;
|
||||
|
||||
private final Int2ObjectOpenHashMap<TimingData> children = new LoadingIntMap<>(TimingData::new);
|
||||
@@ -49,18 +57,11 @@ class TimingHandler implements Timing {
|
||||
private boolean added;
|
||||
private boolean timed;
|
||||
private boolean enabled;
|
||||
private TimingHandler parent;
|
||||
private boolean unsafe; // Akarin
|
||||
|
||||
TimingHandler(TimingIdentifier id) {
|
||||
if (id.name.startsWith("##")) {
|
||||
verbose = true;
|
||||
this.name = id.name.substring(3);
|
||||
} else {
|
||||
this.name = id.name;
|
||||
verbose = false;
|
||||
}
|
||||
|
||||
TimingHandler(@Nonnull TimingIdentifier id) { // Akarin - javax.annotation
|
||||
this.identifier = id;
|
||||
this.verbose = id.name.startsWith("##");
|
||||
this.record = new TimingData(this.id);
|
||||
this.groupHandler = id.groupHandler;
|
||||
|
||||
@@ -85,15 +86,17 @@ class TimingHandler implements Timing {
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull // Akarin - javax.annotation
|
||||
@Override
|
||||
// Akarin start
|
||||
public Timing startTimingIfSync() {
|
||||
// Akarin start
|
||||
return startTiming(false);
|
||||
}
|
||||
@Nonnull // Akarin - javax.annotation
|
||||
@Override
|
||||
// Akarin end
|
||||
public Timing startTimingIfSync(boolean assertThread) {
|
||||
startTiming(assertThread);
|
||||
// Akarin end
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -101,20 +104,31 @@ class TimingHandler implements Timing {
|
||||
public void stopTimingIfSync() {
|
||||
stopTiming();
|
||||
}
|
||||
|
||||
// Akarin start
|
||||
@Override
|
||||
|
||||
@Nonnull // Akarin - javax.annotation
|
||||
public Timing startTiming() {
|
||||
// Akarin start
|
||||
return startTiming(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Timing startTimingUnsafe() {
|
||||
if (enabled && ++timingDepth == 1) {
|
||||
start = System.nanoTime();
|
||||
parent = TimingsManager.CURRENT;
|
||||
TimingsManager.CURRENT = this;
|
||||
unsafe = true;
|
||||
// Akarin end
|
||||
start = System.nanoTime();
|
||||
TIMING_STACK.addLast(this);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
// Akarin start
|
||||
@Override
|
||||
public Timing startTiming(boolean assertThread) {
|
||||
if (enabled && (ThreadAssertion.isMainThread() || Bukkit.isPrimaryThread()) && ++timingDepth == 1) {
|
||||
start = System.nanoTime();
|
||||
TIMING_STACK.addLast(this);
|
||||
if (assertThread && AkarinGlobalConfig.lazyThreadAssertion)
|
||||
ThreadAssertion.setMainThread(true);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
@@ -122,52 +136,47 @@ class TimingHandler implements Timing {
|
||||
@Override
|
||||
public void stopTimingUnsafe() {
|
||||
if (enabled && timingDepth > 0 && --timingDepth == 0 && start != 0) {
|
||||
addDiff(System.nanoTime() - start);
|
||||
start = 0;
|
||||
unsafe = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Timing startTiming(boolean assertThread) {
|
||||
if (enabled && (ThreadAssertion.isMainThread() || Bukkit.isPrimaryThread()) /*&& ++timingDepth == 1*/) {
|
||||
if (AkarinGlobalConfig.lazyThreadAssertion && assertThread) ThreadAssertion.setMainThread(true);
|
||||
if (++timingDepth != 1) return this;
|
||||
// Akarin end
|
||||
start = System.nanoTime();
|
||||
parent = TimingsManager.CURRENT;
|
||||
TimingsManager.CURRENT = this;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopTiming() {
|
||||
// Akarin start
|
||||
if (enabled && timingDepth > 0 && (ThreadAssertion.isMainThread() || Bukkit.isPrimaryThread()) /*&& --timingDepth == 0 && start != 0*/) {
|
||||
if (AkarinGlobalConfig.lazyThreadAssertion) ThreadAssertion.setMainThread(false);
|
||||
if (--timingDepth != 0 || start == 0) return;
|
||||
unsafe = false;
|
||||
// Akarin end
|
||||
addDiff(System.nanoTime() - start);
|
||||
start = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abort() {
|
||||
if (enabled && timingDepth > 0) {
|
||||
start = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void addDiff(long diff) {
|
||||
if (TimingsManager.CURRENT == this) {
|
||||
TimingsManager.CURRENT = parent;
|
||||
if (parent != null) {
|
||||
parent.children.get(id).add(diff);
|
||||
TimingHandler last = TIMING_STACK.removeLast();
|
||||
if (last != this) {
|
||||
Logger.getGlobal().log(Level.SEVERE, "TIMING_STACK_CORRUPTION - Report this to Paper! ( " + this.identifier + ":" + last +")", new Throwable());
|
||||
TIMING_STACK.addLast(last); // Add it back
|
||||
}
|
||||
addDiff(System.nanoTime() - start, TIMING_STACK.peekLast());
|
||||
|
||||
start = 0;
|
||||
unsafe = false;
|
||||
}
|
||||
}
|
||||
// Akarin end
|
||||
|
||||
public void stopTiming() {
|
||||
if (enabled && timingDepth > 0 && (ThreadAssertion.isMainThread() || Bukkit.isPrimaryThread()) && --timingDepth == 0 && start != 0) { // Akarin
|
||||
TimingHandler last = TIMING_STACK.removeLast();
|
||||
if (last != this) {
|
||||
Logger.getGlobal().log(Level.SEVERE, "TIMING_STACK_CORRUPTION - Report this to Paper! ( " + this.identifier + ":" + last +")", new Throwable());
|
||||
TIMING_STACK.addLast(last); // Add it back
|
||||
}
|
||||
addDiff(System.nanoTime() - start, TIMING_STACK.peekLast());
|
||||
|
||||
start = 0;
|
||||
// Akarin start
|
||||
if (AkarinGlobalConfig.lazyThreadAssertion)
|
||||
ThreadAssertion.setMainThread(false);
|
||||
unsafe = false;
|
||||
// Akarin end
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void abort() {
|
||||
|
||||
}
|
||||
|
||||
void addDiff(long diff, @Nullable TimingHandler parent) {
|
||||
if (parent != null) {
|
||||
parent.children.get(id).add(diff);
|
||||
}
|
||||
|
||||
record.add(diff);
|
||||
if (!added) {
|
||||
added = true;
|
||||
@@ -175,15 +184,13 @@ class TimingHandler implements Timing {
|
||||
TimingsManager.HANDLERS.add(this);
|
||||
}
|
||||
if (groupHandler != null) {
|
||||
groupHandler.addDiff(diff);
|
||||
groupHandler.addDiff(diff, parent);
|
||||
groupHandler.children.get(id).add(diff);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset this timer, setting all values to zero.
|
||||
*
|
||||
* @param full
|
||||
*/
|
||||
void reset(boolean full) {
|
||||
record.reset();
|
||||
@@ -197,6 +204,7 @@ class TimingHandler implements Timing {
|
||||
checkEnabled();
|
||||
}
|
||||
|
||||
@Nonnull // Akarin - javax.annotation
|
||||
@Override
|
||||
public TimingHandler getTimingHandler() {
|
||||
return this;
|
||||
@@ -213,8 +221,7 @@ class TimingHandler implements Timing {
|
||||
}
|
||||
|
||||
/**
|
||||
* This is simply for the Closeable interface so it can be used with
|
||||
* try-with-resources ()
|
||||
* This is simply for the Closeable interface so it can be used with try-with-resources ()
|
||||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
@@ -233,6 +240,7 @@ class TimingHandler implements Timing {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
@Nonnull // Akarin - javax.annotation
|
||||
TimingData[] cloneChildren() {
|
||||
final TimingData[] clonedChildren = new TimingData[children.size()];
|
||||
int i = 0;
|
||||
|
||||
@@ -594,4 +594,14 @@ public class PaperWorldConfig {
|
||||
log("Using vanilla redstone algorithm.");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean countAllMobsForSpawning = false;
|
||||
private void countAllMobsForSpawning() {
|
||||
countAllMobsForSpawning = getBoolean("count-all-mobs-for-spawning", false);
|
||||
if (countAllMobsForSpawning) {
|
||||
log("Counting all mobs for spawning. Mob farms may reduce natural spawns elsewhere in world.");
|
||||
} else {
|
||||
log("Using improved mob spawn limits (Only Natural Spawns impact spawn limits for more natural spawns)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,11 @@ public class PaperWorldEntityList extends ArrayList<Entity> {
|
||||
|
||||
public void updateEntityCount(Entity entity, int amt) {
|
||||
// Only count natural spawns so that mob
|
||||
if (!(entity instanceof IAnimal) || entity.spawnReason != SpawnReason.NATURAL) return;
|
||||
if (!(entity instanceof IAnimal) || (
|
||||
!world.paperConfig.countAllMobsForSpawning &&
|
||||
entity.spawnReason != SpawnReason.NATURAL &&
|
||||
entity.spawnReason != SpawnReason.CHUNK_GEN
|
||||
)) return;
|
||||
|
||||
if (entity instanceof EntityInsentient) {
|
||||
EntityInsentient entityinsentient = (EntityInsentient) entity;
|
||||
|
||||
@@ -1131,7 +1131,7 @@ public class ChunkRegionLoader implements IChunkLoader, IAsyncChunkSaver {
|
||||
while (iterator.hasNext()) {
|
||||
Entity entity1 = (Entity) iterator.next();
|
||||
|
||||
a(entity1, generatoraccess);
|
||||
a(entity1, generatoraccess, reason); // Paper
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ public class EntityItem extends Entity {
|
||||
// CraftBukkit start - Use wall time for pickup and despawn timers
|
||||
int elapsedTicks = MinecraftServer.currentTick - this.lastTick;
|
||||
if (this.pickupDelay != 32767) this.pickupDelay -= elapsedTicks;
|
||||
this.pickupDelay = Math.max(0, this.pickupDelay); // Paper - don't go below 0
|
||||
if (this.age != -32768) this.age += elapsedTicks;
|
||||
this.lastTick = MinecraftServer.currentTick;
|
||||
// CraftBukkit end
|
||||
@@ -147,6 +148,7 @@ public class EntityItem extends Entity {
|
||||
// CraftBukkit start - Use wall time for pickup and despawn timers
|
||||
int elapsedTicks = MinecraftServer.currentTick - this.lastTick;
|
||||
if (this.pickupDelay != 32767) this.pickupDelay -= elapsedTicks;
|
||||
this.pickupDelay = Math.max(0, this.pickupDelay); // Paper - don't go below 0
|
||||
if (this.age != -32768) this.age += elapsedTicks;
|
||||
this.lastTick = MinecraftServer.currentTick;
|
||||
// CraftBukkit end
|
||||
@@ -363,7 +365,6 @@ public class EntityItem extends Entity {
|
||||
// CraftBukkit end
|
||||
|
||||
if (this.pickupDelay == 0 && (this.g == null || 6000 - this.age <= 200 || this.g.equals(entityhuman.getUniqueID())) && entityhuman.inventory.pickup(itemstack)) {
|
||||
entityhuman.receive(this, i);
|
||||
// Paper Start
|
||||
if (flyAtPlayer) {
|
||||
entityhuman.receive(this, i);
|
||||
|
||||
25
src/main/java/net/minecraft/server/ItemSign.java
Normal file
25
src/main/java/net/minecraft/server/ItemSign.java
Normal file
@@ -0,0 +1,25 @@
|
||||
package net.minecraft.server;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class ItemSign extends ItemBlockWallable {
|
||||
|
||||
public static boolean openSign; // CraftBukkit
|
||||
|
||||
public ItemSign(Item.Info item_info) {
|
||||
super(Blocks.SIGN, Blocks.WALL_SIGN, item_info);
|
||||
}
|
||||
|
||||
protected boolean a(BlockPosition blockposition, World world, @Nullable EntityHuman entityhuman, ItemStack itemstack, IBlockData iblockdata) {
|
||||
boolean flag = super.a(blockposition, world, entityhuman, itemstack, iblockdata);
|
||||
|
||||
if (!world.isClientSide && !flag && entityhuman != null) {
|
||||
// CraftBukkit start - SPIGOT-4678
|
||||
// entityhuman.openSign((TileEntitySign) world.getTileEntity(blockposition));
|
||||
ItemSign.openSign = true;
|
||||
// CraftBukkit end
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
}
|
||||
@@ -301,6 +301,12 @@ public final class ItemStack {
|
||||
}
|
||||
}
|
||||
|
||||
// SPIGOT-4678
|
||||
if (this.item instanceof ItemSign && ItemSign.openSign) {
|
||||
ItemSign.openSign = false;
|
||||
entityhuman.openSign((TileEntitySign) world.getTileEntity(new BlockActionContext(itemactioncontext).getClickPosition()));
|
||||
}
|
||||
|
||||
// SPIGOT-1288 - play sound stripped from ItemBlock
|
||||
if (this.item instanceof ItemBlock) {
|
||||
SoundEffectType soundeffecttype = ((ItemBlock) this.item).getBlock().getStepSound();
|
||||
|
||||
@@ -1117,7 +1117,7 @@ public abstract class MinecraftServer implements IAsyncTaskHandler, IMojangStati
|
||||
|
||||
//this.methodProfiler.exit(); // Akarin
|
||||
//this.methodProfiler.enter(* // Akarin - remove caller
|
||||
worldserver.getTracker().updatePlayers();
|
||||
if (playerList.players.size() > 0) worldserver.getTracker().updatePlayers(); // Paper - No players, why spend time tracking them? (See patch)
|
||||
//this.methodProfiler.exit(); // Akarin
|
||||
//this.methodProfiler.exit(); // Akarin
|
||||
worldserver.explosionDensityCache.clear(); // Paper - Optimize explosions
|
||||
|
||||
@@ -121,7 +121,7 @@ public abstract class MobSpawnerAbstract {
|
||||
}
|
||||
}
|
||||
// Paper end
|
||||
Entity entity = ChunkRegionLoader.a(nbttagcompound, world, d3, d4, d5, false);
|
||||
Entity entity = ChunkRegionLoader.spawnEntity(nbttagcompound, world, d3, d4, d5, false, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER); // Paper
|
||||
|
||||
if (entity == null) {
|
||||
this.i();
|
||||
|
||||
@@ -2052,7 +2052,7 @@ public class PlayerConnection implements PacketListenerPlayIn, ITickable {
|
||||
|
||||
if (event.isCancelled() || this.player.inventory.getItemInHand() == null || this.player.inventory.getItemInHand().getItem() != origItem) {
|
||||
// Refresh the current entity metadata
|
||||
this.sendPacket(new PacketPlayOutEntityMetadata(entity.getId(), entity.datawatcher, true));
|
||||
entity.tracker.broadcast(new PacketPlayOutEntityMetadata(entity.getId(), entity.datawatcher, true)); // Paper - update entity for all players
|
||||
}
|
||||
|
||||
if (event.isCancelled()) {
|
||||
|
||||
@@ -198,7 +198,7 @@ public abstract class PlayerList {
|
||||
|
||||
if (nbttagcompound != null && nbttagcompound.hasKeyOfType("RootVehicle", 10)) {
|
||||
NBTTagCompound nbttagcompound1 = nbttagcompound.getCompound("RootVehicle");
|
||||
Entity entity = ChunkRegionLoader.a(nbttagcompound1.getCompound("Entity"), worldserver, true);
|
||||
Entity entity = ChunkRegionLoader.spawnEntity(nbttagcompound1.getCompound("Entity"), worldserver, true, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.MOUNT); // Paper
|
||||
|
||||
if (entity != null) {
|
||||
UUID uuid = nbttagcompound1.a("Attach");
|
||||
@@ -665,9 +665,14 @@ public abstract class PlayerList {
|
||||
// this.a(entityplayer1, entityplayer, worldserver); // CraftBukkit - removed
|
||||
BlockPosition blockposition1;
|
||||
|
||||
// Paper start
|
||||
boolean isBedSpawn = false;
|
||||
boolean isRespawn = false;
|
||||
// Paper end
|
||||
|
||||
// CraftBukkit start - fire PlayerRespawnEvent
|
||||
if (location == null) {
|
||||
boolean isBedSpawn = false;
|
||||
//boolean isBedSpawn = false; Paper - moved up
|
||||
CraftWorld cworld = (CraftWorld) this.server.server.getWorld(entityplayer.spawnWorld);
|
||||
if (cworld != null && blockposition != null) {
|
||||
blockposition1 = EntityHuman.getBed(cworld.getHandle(), blockposition, flag1);
|
||||
@@ -697,6 +702,7 @@ public abstract class PlayerList {
|
||||
|
||||
location = respawnEvent.getRespawnLocation();
|
||||
entityplayer.reset();
|
||||
isRespawn = true; // Paper
|
||||
} else {
|
||||
location.setWorld(server.getWorldServer(dimensionmanager).getWorld());
|
||||
}
|
||||
@@ -758,6 +764,13 @@ public abstract class PlayerList {
|
||||
if (entityplayer.playerConnection.isDisconnected()) {
|
||||
this.savePlayerFile(entityplayer);
|
||||
}
|
||||
|
||||
// Paper start
|
||||
if (isRespawn) {
|
||||
cserver.getPluginManager().callEvent(new com.destroystokyo.paper.event.player.PlayerPostRespawnEvent(entityplayer.getBukkitEntity(), location, isBedSpawn));
|
||||
}
|
||||
// Paper end
|
||||
|
||||
// CraftBukkit end
|
||||
return entityplayer1;
|
||||
}
|
||||
|
||||
152
src/main/java/net/minecraft/server/RemoteConnectionThread.java
Normal file
152
src/main/java/net/minecraft/server/RemoteConnectionThread.java
Normal file
@@ -0,0 +1,152 @@
|
||||
package net.minecraft.server;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.ServerSocket;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
public abstract class RemoteConnectionThread implements Runnable {
|
||||
|
||||
private static final Logger h = LogManager.getLogger();
|
||||
private static final AtomicInteger i = new AtomicInteger(0);
|
||||
protected boolean a;
|
||||
protected IMinecraftServer b; protected IMinecraftServer getServer() { return b; } // Paper - OBFHELPER
|
||||
protected final String c;
|
||||
protected Thread d;
|
||||
protected int e = 5;
|
||||
protected List<DatagramSocket> f = Lists.newArrayList();
|
||||
protected List<ServerSocket> g = Lists.newArrayList();
|
||||
|
||||
protected RemoteConnectionThread(IMinecraftServer iminecraftserver, String s) {
|
||||
this.b = iminecraftserver;
|
||||
this.c = s;
|
||||
if (this.b.isDebugging()) {
|
||||
this.c("Debugging is enabled, performance maybe reduced!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public synchronized void a() {
|
||||
this.d = new Thread(this, this.c + " #" + RemoteConnectionThread.i.incrementAndGet());
|
||||
this.d.setUncaughtExceptionHandler(new ThreadNamedUncaughtExceptionHandler(RemoteConnectionThread.h));
|
||||
this.d.start();
|
||||
this.a = true;
|
||||
}
|
||||
|
||||
public boolean c() {
|
||||
return this.a;
|
||||
}
|
||||
|
||||
protected void a(String s) {
|
||||
this.b.g(s);
|
||||
}
|
||||
|
||||
protected void b(String s) {
|
||||
this.b.info(s);
|
||||
}
|
||||
|
||||
protected void c(String s) {
|
||||
this.b.warning(s);
|
||||
}
|
||||
|
||||
protected void d(String s) {
|
||||
this.b.f(s);
|
||||
}
|
||||
|
||||
protected int getPlayerCount() { return d(); } // Paper - OBFHELPER
|
||||
protected int d() {
|
||||
return this.b.getPlayerCount();
|
||||
}
|
||||
|
||||
protected void a(DatagramSocket datagramsocket) {
|
||||
this.a("registerSocket: " + datagramsocket);
|
||||
this.f.add(datagramsocket);
|
||||
}
|
||||
|
||||
protected boolean a(DatagramSocket datagramsocket, boolean flag) {
|
||||
this.a("closeSocket: " + datagramsocket);
|
||||
if (null == datagramsocket) {
|
||||
return false;
|
||||
} else {
|
||||
boolean flag1 = false;
|
||||
|
||||
if (!datagramsocket.isClosed()) {
|
||||
datagramsocket.close();
|
||||
flag1 = true;
|
||||
}
|
||||
|
||||
if (flag) {
|
||||
this.f.remove(datagramsocket);
|
||||
}
|
||||
|
||||
return flag1;
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean b(ServerSocket serversocket) {
|
||||
return this.a(serversocket, true);
|
||||
}
|
||||
|
||||
protected boolean a(ServerSocket serversocket, boolean flag) {
|
||||
this.a("closeSocket: " + serversocket);
|
||||
if (null == serversocket) {
|
||||
return false;
|
||||
} else {
|
||||
boolean flag1 = false;
|
||||
|
||||
try {
|
||||
if (!serversocket.isClosed()) {
|
||||
serversocket.close();
|
||||
flag1 = true;
|
||||
}
|
||||
} catch (IOException ioexception) {
|
||||
this.c("IO: " + ioexception.getMessage());
|
||||
}
|
||||
|
||||
if (flag) {
|
||||
this.g.remove(serversocket);
|
||||
}
|
||||
|
||||
return flag1;
|
||||
}
|
||||
}
|
||||
|
||||
protected void e() {
|
||||
this.a(false);
|
||||
}
|
||||
|
||||
protected void a(boolean flag) {
|
||||
int i = 0;
|
||||
Iterator iterator = this.f.iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
DatagramSocket datagramsocket = (DatagramSocket) iterator.next();
|
||||
|
||||
if (this.a(datagramsocket, false)) {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
this.f.clear();
|
||||
iterator = this.g.iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
ServerSocket serversocket = (ServerSocket) iterator.next();
|
||||
|
||||
if (this.a(serversocket, false)) {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
this.g.clear();
|
||||
if (flag && 0 < i) {
|
||||
this.c("Force closed " + i + " sockets");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
430
src/main/java/net/minecraft/server/RemoteStatusListener.java
Normal file
430
src/main/java/net/minecraft/server/RemoteStatusListener.java
Normal file
@@ -0,0 +1,430 @@
|
||||
package net.minecraft.server;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.InetAddress;
|
||||
import java.net.PortUnreachableException;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.SocketException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
public class RemoteStatusListener extends RemoteConnectionThread {
|
||||
|
||||
private long h;
|
||||
private int i;
|
||||
private final int j; private int getServerPort() { return j; } // Paper - OBFHELPER
|
||||
private final int k; private int getMaxPlayers() { return k; } // Paper - OBFHELPER
|
||||
private final String l; private String getMotd() { return l; } // Paper - OBFHELPER
|
||||
private final String m; private String getWorldName() { return m; } // Paper - OBFHELPER
|
||||
private DatagramSocket n;
|
||||
private final byte[] o = new byte[1460];
|
||||
private DatagramPacket p;
|
||||
private final Map<SocketAddress, String> q;
|
||||
private String r; private String getServerHost() { return r; } // Paper - OBFHELPER
|
||||
private String s;
|
||||
private final Map<SocketAddress, RemoteStatusListener.RemoteStatusChallenge> t;
|
||||
private final long u;
|
||||
private final RemoteStatusReply v; private RemoteStatusReply getCachedFullResponse() { return v; } // Paper - OBFHELPER
|
||||
private long w;
|
||||
|
||||
public RemoteStatusListener(IMinecraftServer iminecraftserver) {
|
||||
super(iminecraftserver, "Query Listener");
|
||||
this.i = iminecraftserver.a("query.port", 0);
|
||||
this.s = iminecraftserver.e();
|
||||
this.j = iminecraftserver.e_();
|
||||
this.l = iminecraftserver.m();
|
||||
this.k = iminecraftserver.getMaxPlayers();
|
||||
this.m = iminecraftserver.getWorld();
|
||||
this.w = 0L;
|
||||
this.r = "0.0.0.0";
|
||||
if (!this.s.isEmpty() && !this.r.equals(this.s)) {
|
||||
this.r = this.s;
|
||||
} else {
|
||||
this.s = "0.0.0.0";
|
||||
|
||||
try {
|
||||
InetAddress inetaddress = InetAddress.getLocalHost();
|
||||
|
||||
this.r = inetaddress.getHostAddress();
|
||||
} catch (UnknownHostException unknownhostexception) {
|
||||
this.c("Unable to determine local host IP, please set server-ip in '" + iminecraftserver.d_() + "' : " + unknownhostexception.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == this.i) {
|
||||
this.i = this.j;
|
||||
this.b("Setting default query port to " + this.i);
|
||||
iminecraftserver.a("query.port", (Object) this.i);
|
||||
iminecraftserver.a("debug", (Object) false);
|
||||
iminecraftserver.c_();
|
||||
}
|
||||
|
||||
this.q = Maps.newHashMap();
|
||||
this.v = new RemoteStatusReply(1460);
|
||||
this.t = Maps.newHashMap();
|
||||
this.u = (new Date()).getTime();
|
||||
}
|
||||
|
||||
private void a(byte[] abyte, DatagramPacket datagrampacket) throws IOException {
|
||||
this.n.send(new DatagramPacket(abyte, abyte.length, datagrampacket.getSocketAddress()));
|
||||
}
|
||||
|
||||
private boolean a(DatagramPacket datagrampacket) throws IOException {
|
||||
byte[] abyte = datagrampacket.getData();
|
||||
int i = datagrampacket.getLength();
|
||||
SocketAddress socketaddress = datagrampacket.getSocketAddress();
|
||||
|
||||
this.a("Packet len " + i + " [" + socketaddress + "]");
|
||||
if (3 <= i && -2 == abyte[0] && -3 == abyte[1]) {
|
||||
this.a("Packet '" + StatusChallengeUtils.a(abyte[2]) + "' [" + socketaddress + "]");
|
||||
switch (abyte[2]) {
|
||||
case 0:
|
||||
if (!this.c(datagrampacket)) {
|
||||
this.a("Invalid challenge [" + socketaddress + "]");
|
||||
return false;
|
||||
} else if (15 == i) {
|
||||
this.a(this.b(datagrampacket), datagrampacket);
|
||||
this.a("Rules [" + socketaddress + "]");
|
||||
} else {
|
||||
RemoteStatusReply remotestatusreply = new RemoteStatusReply(1460);
|
||||
|
||||
remotestatusreply.a((int) 0);
|
||||
remotestatusreply.a(this.a(datagrampacket.getSocketAddress()));
|
||||
/* Paper start - GS4 Query event
|
||||
remotestatusreply.a(this.l);
|
||||
remotestatusreply.a("SMP");
|
||||
remotestatusreply.a(this.m);
|
||||
remotestatusreply.a(Integer.toString(this.d()));
|
||||
remotestatusreply.a(Integer.toString(this.k));
|
||||
remotestatusreply.a((short) this.j);
|
||||
remotestatusreply.a(this.r);
|
||||
*/
|
||||
com.destroystokyo.paper.event.server.GS4QueryEvent.QueryType queryType =
|
||||
com.destroystokyo.paper.event.server.GS4QueryEvent.QueryType.BASIC;
|
||||
com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse queryResponse = com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.builder()
|
||||
.motd(this.getMotd())
|
||||
.map(this.getWorldName())
|
||||
.currentPlayers(this.getPlayerCount())
|
||||
.maxPlayers(this.getMaxPlayers())
|
||||
.port(this.getServerPort())
|
||||
.hostname(this.getServerHost())
|
||||
.gameVersion(this.getServer().getVersion())
|
||||
.serverVersion(org.bukkit.Bukkit.getServer().getName() + " on " + org.bukkit.Bukkit.getServer().getBukkitVersion())
|
||||
.build();
|
||||
com.destroystokyo.paper.event.server.GS4QueryEvent queryEvent =
|
||||
new com.destroystokyo.paper.event.server.GS4QueryEvent(queryType, datagrampacket.getAddress(), queryResponse);
|
||||
queryEvent.callEvent();
|
||||
queryResponse = queryEvent.getResponse();
|
||||
remotestatusreply.writeString(queryResponse.getMotd());
|
||||
remotestatusreply.writeString("SMP");
|
||||
remotestatusreply.writeString(queryResponse.getMap());
|
||||
remotestatusreply.writeString(Integer.toString(queryResponse.getCurrentPlayers()));
|
||||
remotestatusreply.writeString(Integer.toString(queryResponse.getMaxPlayers()));
|
||||
remotestatusreply.writeShort((short) queryResponse.getPort());
|
||||
remotestatusreply.writeString(queryResponse.getHostname());
|
||||
// Paper end
|
||||
this.a(remotestatusreply.a(), datagrampacket);
|
||||
this.a("Status [" + socketaddress + "]");
|
||||
}
|
||||
default:
|
||||
return true;
|
||||
case 9:
|
||||
this.d(datagrampacket);
|
||||
this.a("Challenge [" + socketaddress + "]");
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
this.a("Invalid packet [" + socketaddress + "]");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] b(DatagramPacket datagrampacket) throws IOException {
|
||||
long i = SystemUtils.getMonotonicMillis();
|
||||
|
||||
if (i < this.w + 5000L) {
|
||||
byte[] abyte = this.v.a();
|
||||
byte[] abyte1 = this.a(datagrampacket.getSocketAddress());
|
||||
|
||||
abyte[1] = abyte1[0];
|
||||
abyte[2] = abyte1[1];
|
||||
abyte[3] = abyte1[2];
|
||||
abyte[4] = abyte1[3];
|
||||
return abyte;
|
||||
} else {
|
||||
this.w = i;
|
||||
this.v.b();
|
||||
this.v.a((int) 0);
|
||||
this.v.a(this.a(datagrampacket.getSocketAddress()));
|
||||
this.v.a("splitnum");
|
||||
this.v.a((int) 128);
|
||||
this.v.a((int) 0);
|
||||
/* Paper start - GS4 Query event
|
||||
this.v.a("hostname");
|
||||
this.v.a(this.l);
|
||||
this.v.a("gametype");
|
||||
this.v.a("SMP");
|
||||
this.v.a("game_id");
|
||||
this.v.a("MINECRAFT");
|
||||
this.v.a("version");
|
||||
this.v.a(this.b.getVersion());
|
||||
this.v.a("plugins");
|
||||
this.v.a(this.b.getPlugins());
|
||||
this.v.a("map");
|
||||
this.v.a(this.m);
|
||||
this.v.a("numplayers");
|
||||
this.v.a("" + this.d());
|
||||
this.v.a("maxplayers");
|
||||
this.v.a("" + this.k);
|
||||
this.v.a("hostport");
|
||||
this.v.a("" + this.j);
|
||||
this.v.a("hostip");
|
||||
this.v.a(this.r);
|
||||
this.v.a((int) 0);
|
||||
this.v.a((int) 1);
|
||||
this.v.a("player_");
|
||||
this.v.a((int) 0);
|
||||
String[] astring = this.b.getPlayers();
|
||||
String[] astring1 = astring;
|
||||
int j = astring.length;
|
||||
|
||||
for (int k = 0; k < j; ++k) {
|
||||
String s = astring1[k];
|
||||
|
||||
this.v.a(s);
|
||||
}
|
||||
|
||||
this.v.a((int) 0);
|
||||
*/
|
||||
// Pack plugins
|
||||
java.util.List<com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.PluginInformation> plugins = java.util.Collections.emptyList();
|
||||
org.bukkit.plugin.Plugin[] bukkitPlugins;
|
||||
if(((DedicatedServer) this.getServer()).server.getQueryPlugins() && (bukkitPlugins = org.bukkit.Bukkit.getPluginManager().getPlugins()).length > 0) {
|
||||
plugins = java.util.stream.Stream.of(bukkitPlugins)
|
||||
.map(plugin -> com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.PluginInformation.of(plugin.getName(), plugin.getDescription().getVersion()))
|
||||
.collect(java.util.stream.Collectors.toList());
|
||||
}
|
||||
|
||||
com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse queryResponse = com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.builder()
|
||||
.motd(this.getMotd())
|
||||
.map(this.getWorldName())
|
||||
.currentPlayers(this.getPlayerCount())
|
||||
.maxPlayers(this.getMaxPlayers())
|
||||
.port(this.getServerPort())
|
||||
.hostname(this.getServerHost())
|
||||
.plugins(plugins)
|
||||
.players(this.getServer().getPlayers())
|
||||
.gameVersion(this.getServer().getVersion())
|
||||
.serverVersion(org.bukkit.Bukkit.getServer().getName() + " on " + org.bukkit.Bukkit.getServer().getBukkitVersion())
|
||||
.build();
|
||||
com.destroystokyo.paper.event.server.GS4QueryEvent.QueryType queryType =
|
||||
com.destroystokyo.paper.event.server.GS4QueryEvent.QueryType.FULL;
|
||||
com.destroystokyo.paper.event.server.GS4QueryEvent queryEvent =
|
||||
new com.destroystokyo.paper.event.server.GS4QueryEvent(queryType, datagrampacket.getAddress(), queryResponse);
|
||||
queryEvent.callEvent();
|
||||
queryResponse = queryEvent.getResponse();
|
||||
this.getCachedFullResponse().writeString("hostname");
|
||||
this.getCachedFullResponse().writeString(queryResponse.getMotd());
|
||||
this.getCachedFullResponse().writeString("gametype");
|
||||
this.getCachedFullResponse().writeString("SMP");
|
||||
this.getCachedFullResponse().writeString("game_id");
|
||||
this.getCachedFullResponse().writeString("MINECRAFT");
|
||||
this.getCachedFullResponse().writeString("version");
|
||||
this.getCachedFullResponse().writeString(queryResponse.getGameVersion());
|
||||
this.getCachedFullResponse().writeString("plugins");
|
||||
java.lang.StringBuilder pluginsString = new java.lang.StringBuilder();
|
||||
pluginsString.append(queryResponse.getServerVersion());
|
||||
if(!queryResponse.getPlugins().isEmpty()) {
|
||||
pluginsString.append(": ");
|
||||
Iterator<com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.PluginInformation> iter = queryResponse.getPlugins().iterator();
|
||||
while(iter.hasNext()) {
|
||||
com.destroystokyo.paper.event.server.GS4QueryEvent.QueryResponse.PluginInformation info = iter.next();
|
||||
pluginsString.append(info.getName());
|
||||
if (info.getVersion() != null) {
|
||||
pluginsString.append(' ').append(info.getVersion().replaceAll(";", ","));
|
||||
}
|
||||
if (iter.hasNext()) {
|
||||
pluginsString.append(';').append(' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
this.getCachedFullResponse().writeString(pluginsString.toString());
|
||||
this.getCachedFullResponse().writeString("map");
|
||||
this.getCachedFullResponse().writeString(queryResponse.getMap());
|
||||
this.getCachedFullResponse().writeString("numplayers");
|
||||
this.getCachedFullResponse().writeString(Integer.toString(queryResponse.getCurrentPlayers()));
|
||||
this.getCachedFullResponse().writeString("maxplayers");
|
||||
this.getCachedFullResponse().writeString(Integer.toString(queryResponse.getMaxPlayers()));
|
||||
this.getCachedFullResponse().writeString("hostport");
|
||||
this.getCachedFullResponse().writeString(Integer.toString(queryResponse.getPort()));
|
||||
this.getCachedFullResponse().writeString("hostip");
|
||||
this.getCachedFullResponse().writeString(queryResponse.getHostname());
|
||||
// The "meaningless data" start, copied from above
|
||||
this.getCachedFullResponse().writeInt(0);
|
||||
this.getCachedFullResponse().writeInt(1);
|
||||
this.getCachedFullResponse().writeString("player_");
|
||||
this.getCachedFullResponse().writeInt(0);
|
||||
// "Meaningless data" end
|
||||
queryResponse.getPlayers().forEach(this.getCachedFullResponse()::writeStringUnchecked);
|
||||
this.getCachedFullResponse().writeInt(0);
|
||||
// Paper end
|
||||
return this.v.a();
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] a(SocketAddress socketaddress) {
|
||||
return ((RemoteStatusListener.RemoteStatusChallenge) this.t.get(socketaddress)).c();
|
||||
}
|
||||
|
||||
private Boolean c(DatagramPacket datagrampacket) {
|
||||
SocketAddress socketaddress = datagrampacket.getSocketAddress();
|
||||
|
||||
if (!this.t.containsKey(socketaddress)) {
|
||||
return false;
|
||||
} else {
|
||||
byte[] abyte = datagrampacket.getData();
|
||||
|
||||
return ((RemoteStatusListener.RemoteStatusChallenge) this.t.get(socketaddress)).a() != StatusChallengeUtils.c(abyte, 7, datagrampacket.getLength()) ? false : true;
|
||||
}
|
||||
}
|
||||
|
||||
private void d(DatagramPacket datagrampacket) throws IOException {
|
||||
RemoteStatusListener.RemoteStatusChallenge remotestatuslistener_remotestatuschallenge = new RemoteStatusListener.RemoteStatusChallenge(datagrampacket);
|
||||
|
||||
this.t.put(datagrampacket.getSocketAddress(), remotestatuslistener_remotestatuschallenge);
|
||||
this.a(remotestatuslistener_remotestatuschallenge.b(), datagrampacket);
|
||||
}
|
||||
|
||||
private void f() {
|
||||
if (this.a) {
|
||||
long i = SystemUtils.getMonotonicMillis();
|
||||
|
||||
if (i >= this.h + 30000L) {
|
||||
this.h = i;
|
||||
Iterator iterator = this.t.entrySet().iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
Entry<SocketAddress, RemoteStatusListener.RemoteStatusChallenge> entry = (Entry) iterator.next();
|
||||
|
||||
if (((RemoteStatusListener.RemoteStatusChallenge) entry.getValue()).a(i)) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
this.b("Query running on " + this.s + ":" + this.i);
|
||||
this.h = SystemUtils.getMonotonicMillis();
|
||||
this.p = new DatagramPacket(this.o, this.o.length);
|
||||
|
||||
try {
|
||||
while (this.a) {
|
||||
try {
|
||||
this.n.receive(this.p);
|
||||
this.f();
|
||||
this.a(this.p);
|
||||
} catch (SocketTimeoutException sockettimeoutexception) {
|
||||
this.f();
|
||||
} catch (PortUnreachableException portunreachableexception) {
|
||||
;
|
||||
} catch (IOException ioexception) {
|
||||
this.a((Exception) ioexception);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
this.e();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void a() {
|
||||
if (!this.a) {
|
||||
if (0 < this.i && 65535 >= this.i) {
|
||||
if (this.g()) {
|
||||
super.a();
|
||||
}
|
||||
|
||||
} else {
|
||||
this.c("Invalid query port " + this.i + " found in '" + this.b.d_() + "' (queries disabled)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void a(Exception exception) {
|
||||
if (this.a) {
|
||||
this.c("Unexpected exception, buggy JRE? (" + exception + ")");
|
||||
if (!this.g()) {
|
||||
this.d("Failed to recover from buggy JRE, shutting down!");
|
||||
this.a = false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private boolean g() {
|
||||
try {
|
||||
this.n = new DatagramSocket(this.i, InetAddress.getByName(this.s));
|
||||
this.a(this.n);
|
||||
this.n.setSoTimeout(500);
|
||||
return true;
|
||||
} catch (SocketException socketexception) {
|
||||
this.c("Unable to initialise query system on " + this.s + ":" + this.i + " (Socket): " + socketexception.getMessage());
|
||||
} catch (UnknownHostException unknownhostexception) {
|
||||
this.c("Unable to initialise query system on " + this.s + ":" + this.i + " (Unknown Host): " + unknownhostexception.getMessage());
|
||||
} catch (Exception exception) {
|
||||
this.c("Unable to initialise query system on " + this.s + ":" + this.i + " (E): " + exception.getMessage());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
class RemoteStatusChallenge {
|
||||
|
||||
private final long time = (new Date()).getTime();
|
||||
private final int token;
|
||||
private final byte[] identity;
|
||||
private final byte[] e;
|
||||
private final String f;
|
||||
|
||||
public RemoteStatusChallenge(DatagramPacket datagrampacket) {
|
||||
byte[] abyte = datagrampacket.getData();
|
||||
|
||||
this.identity = new byte[4];
|
||||
this.identity[0] = abyte[3];
|
||||
this.identity[1] = abyte[4];
|
||||
this.identity[2] = abyte[5];
|
||||
this.identity[3] = abyte[6];
|
||||
this.f = new String(this.identity, StandardCharsets.UTF_8);
|
||||
this.token = (new Random()).nextInt(16777216);
|
||||
this.e = String.format("\t%s%d\u0000", this.f, this.token).getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public Boolean a(long i) {
|
||||
return this.time < i;
|
||||
}
|
||||
|
||||
public int a() {
|
||||
return this.token;
|
||||
}
|
||||
|
||||
public byte[] b() {
|
||||
return this.e;
|
||||
}
|
||||
|
||||
public byte[] c() {
|
||||
return this.identity;
|
||||
}
|
||||
}
|
||||
}
|
||||
53
src/main/java/net/minecraft/server/RemoteStatusReply.java
Normal file
53
src/main/java/net/minecraft/server/RemoteStatusReply.java
Normal file
@@ -0,0 +1,53 @@
|
||||
package net.minecraft.server;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class RemoteStatusReply {
|
||||
|
||||
private final ByteArrayOutputStream a;
|
||||
private final DataOutputStream b;
|
||||
|
||||
public RemoteStatusReply(int i) {
|
||||
this.a = new ByteArrayOutputStream(i);
|
||||
this.b = new DataOutputStream(this.a);
|
||||
}
|
||||
|
||||
public void a(byte[] abyte) throws IOException {
|
||||
this.b.write(abyte, 0, abyte.length);
|
||||
}
|
||||
|
||||
public void writeString(String string) throws IOException { a(string); } // Paper - OBFHELPER
|
||||
public void a(String s) throws IOException {
|
||||
this.b.writeBytes(s);
|
||||
this.b.write(0);
|
||||
}
|
||||
// Paper start - unchecked exception variant to use in Stream API
|
||||
public void writeStringUnchecked(String string) {
|
||||
try {
|
||||
writeString(string);
|
||||
} catch (IOException e) {
|
||||
com.destroystokyo.paper.util.SneakyThrow.sneaky(e);
|
||||
}
|
||||
}
|
||||
// Paper end
|
||||
|
||||
public void writeInt(int i) throws IOException { a(i); } // Paper - OBFHELPER
|
||||
public void a(int i) throws IOException {
|
||||
this.b.write(i);
|
||||
}
|
||||
|
||||
public void writeShort(short i) throws IOException { a(i); } // Paper - OBFHELPER
|
||||
public void a(short short0) throws IOException {
|
||||
this.b.writeShort(Short.reverseBytes(short0));
|
||||
}
|
||||
|
||||
public byte[] a() {
|
||||
return this.a.toByteArray();
|
||||
}
|
||||
|
||||
public void b() {
|
||||
this.a.reset();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user