3916 lines
144 KiB
Java
Executable file
3916 lines
144 KiB
Java
Executable file
package client;
|
|
|
|
import java.awt.image.BufferedImage;
|
|
import java.io.BufferedInputStream;
|
|
import java.io.BufferedReader;
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
import java.io.InputStreamReader;
|
|
import java.lang.reflect.Field;
|
|
import java.lang.reflect.InvocationTargetException;
|
|
import java.lang.reflect.Modifier;
|
|
import java.net.IDN;
|
|
import java.net.InetAddress;
|
|
import java.net.UnknownHostException;
|
|
import java.nio.ByteBuffer;
|
|
import java.nio.ByteOrder;
|
|
import java.text.SimpleDateFormat;
|
|
import java.util.ArrayDeque;
|
|
import java.util.Arrays;
|
|
import java.util.Date;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.Locale;
|
|
import java.util.Map;
|
|
import java.util.Map.Entry;
|
|
import java.util.Queue;
|
|
import java.util.Set;
|
|
import java.util.function.Function;
|
|
|
|
import javax.imageio.ImageIO;
|
|
import javax.swing.JFileChooser;
|
|
|
|
import org.lwjgl.opengl.GL;
|
|
import org.lwjgl.opengl.GL15;
|
|
|
|
import client.audio.AudioInterface;
|
|
import client.audio.MidiBank;
|
|
import client.audio.MidiDecoder;
|
|
import client.audio.SoundManager;
|
|
import client.audio.Volume;
|
|
import client.gui.FileCallback;
|
|
import client.gui.Font;
|
|
import client.gui.Gui;
|
|
import client.gui.GuiConnect.ServerInfo;
|
|
import client.gui.GuiConsole;
|
|
import client.gui.GuiInfo;
|
|
import client.gui.GuiLoading;
|
|
import client.gui.GuiMenu;
|
|
import client.gui.GuiPlayer;
|
|
import client.gui.GuiServer;
|
|
import client.gui.Style;
|
|
import client.gui.character.GuiChar;
|
|
import client.gui.container.GuiContainer;
|
|
import client.gui.container.GuiInventory;
|
|
import client.gui.element.Area;
|
|
import client.gui.element.InventoryButton;
|
|
import client.gui.ingame.GuiGameOver;
|
|
import client.gui.ingame.GuiRename;
|
|
import client.init.DimensionMapping;
|
|
import client.network.ClientLoginHandler;
|
|
import client.network.ClientPlayer;
|
|
import client.network.DummyConnection;
|
|
import client.renderer.Drawing;
|
|
import client.renderer.EffectRenderer;
|
|
import client.renderer.Renderer;
|
|
import client.renderer.ShaderContext;
|
|
import client.renderer.GlState;
|
|
import client.renderer.ItemRenderer;
|
|
import client.renderer.blockmodel.ModelManager;
|
|
import client.renderer.chunk.RenderChunk;
|
|
import client.renderer.entity.RenderItem;
|
|
import client.renderer.entity.RenderManager;
|
|
import client.renderer.texture.EntityTexManager;
|
|
import client.renderer.texture.TextureManager;
|
|
import client.renderer.texture.TextureMap;
|
|
import client.renderer.texture.TextureUtil;
|
|
import client.util.FileUtils;
|
|
import client.util.Message;
|
|
import client.util.PerfSection;
|
|
import client.util.PlayerController;
|
|
import client.vars.BoolVar;
|
|
import client.vars.CVar;
|
|
import client.vars.CVarCategory;
|
|
import client.vars.ColorVar;
|
|
import client.vars.EnumVar;
|
|
import client.vars.FloatVar;
|
|
import client.vars.IntVar;
|
|
import client.vars.StringVar;
|
|
import client.vars.Variable;
|
|
import client.vars.BaseVar.VarFunction;
|
|
import client.vars.BoolVar.BoolFunction;
|
|
import client.vars.EnumVar.EnumFunction;
|
|
import client.vars.FloatVar.FloatFunction;
|
|
import client.vars.IntVar.IntFunction;
|
|
import client.vars.StringVar.StringFunction;
|
|
import client.vars.Variable.IntType;
|
|
import client.window.Bind;
|
|
import client.window.Button;
|
|
import client.window.DisplayMode;
|
|
import client.window.KeyEvent;
|
|
import client.window.Keysym;
|
|
import client.window.Wheel;
|
|
import client.window.Window;
|
|
import client.window.WindowEvent;
|
|
import client.world.ChunkClient;
|
|
import client.world.ChunkEmpty;
|
|
import common.Version;
|
|
import common.block.Block;
|
|
import common.block.liquid.BlockLiquid;
|
|
import common.collect.Lists;
|
|
import common.collect.Maps;
|
|
import common.collect.Sets;
|
|
import common.dimension.Dimension;
|
|
import common.dimension.Space;
|
|
import common.effect.Effect;
|
|
import common.effect.StatusEffect;
|
|
import common.entity.Entity;
|
|
import common.entity.animal.EntityHorse;
|
|
import common.entity.item.EntityCamera;
|
|
import common.entity.item.EntityCamera.CameraType;
|
|
import common.entity.item.EntityCart;
|
|
import common.entity.npc.Energy;
|
|
import common.entity.npc.EntityCameraHolder;
|
|
import common.entity.npc.EntityNPC;
|
|
import common.entity.npc.EntityWaterNPC;
|
|
import common.entity.npc.PlayerCharacter;
|
|
import common.entity.types.EntityLiving;
|
|
import common.init.BlockRegistry;
|
|
import common.init.Blocks;
|
|
import common.init.EntityRegistry;
|
|
import common.init.ItemRegistry;
|
|
import common.init.Items;
|
|
import common.init.Registry;
|
|
import common.init.SoundEvent;
|
|
import common.item.Item;
|
|
import common.item.ItemControl;
|
|
import common.item.ItemStack;
|
|
import common.item.ItemCategory;
|
|
import common.item.material.ItemBucket;
|
|
import common.log.Log;
|
|
import common.log.LogLevel;
|
|
import common.net.bootstrap.Bootstrap;
|
|
import common.net.channel.Channel;
|
|
import common.net.channel.ChannelException;
|
|
import common.net.channel.ChannelInitializer;
|
|
import common.net.channel.ChannelOption;
|
|
import common.net.channel.nio.NioEventLoopGroup;
|
|
import common.net.channel.socket.nio.NioSocketChannel;
|
|
import common.net.handler.timeout.ReadTimeoutHandler;
|
|
import common.net.util.concurrent.Future;
|
|
import common.net.util.concurrent.GenericFutureListener;
|
|
import common.network.IThreadListener;
|
|
import common.network.NetConnection;
|
|
import common.network.PacketDecoder;
|
|
import common.network.PacketEncoder;
|
|
import common.network.PacketPrepender;
|
|
import common.network.PacketRegistry;
|
|
import common.network.PacketSplitter;
|
|
import common.network.NetHandler.ThreadQuickExitException;
|
|
import common.packet.CPacketAction;
|
|
import common.packet.CPacketCheat;
|
|
import common.packet.CPacketInput;
|
|
import common.packet.CPacketMessage;
|
|
import common.packet.CPacketPlayerPosLook;
|
|
import common.packet.HPacketHandshake;
|
|
import common.packet.CPacketAction.Action;
|
|
import common.properties.Property;
|
|
import common.rng.Random;
|
|
import common.sound.EventType;
|
|
import common.sound.MovingSoundMinecart;
|
|
import common.sound.PositionedSound;
|
|
import common.tileentity.TileEntity;
|
|
import common.util.LocalPos;
|
|
import common.util.BoundingBox;
|
|
import common.util.CharValidator;
|
|
import common.util.ExtMath;
|
|
import common.util.HitPosition;
|
|
import common.util.IntHashMap;
|
|
import common.util.LongHashMap;
|
|
import common.util.MutablePos;
|
|
import common.util.ParticleType;
|
|
import common.util.Color;
|
|
import common.util.Util;
|
|
import common.util.Var;
|
|
import common.util.HitPosition.ObjectType;
|
|
import common.vars.Vars;
|
|
import common.world.Chunk;
|
|
import common.world.State;
|
|
import common.world.Weather;
|
|
import common.world.World;
|
|
|
|
/*
|
|
Een net ganz funktionierndes Programm ...
|
|
|
|
Absolute Mindestanforderungen:
|
|
|
|
Prozessor : Intel Core i3 530 oder AMD Phenom 2 X2 545
|
|
Grafikkarte : NVIDIA GeForce GTS 450 oder AMD Radeon HD 7730
|
|
Arbeitsspeicher : Etwa 512 MB ~ 1 GB, 2 - 4 GB empfohlen
|
|
Mainboard : Was gerade passt (auch mit Hammer)
|
|
Kühler : Ne Klimaanlage oder ordentlich Pusten
|
|
Festplatte : Richtet sich nach der Geduld des Nutzers
|
|
Netzteil : Atomkraftwerk oder stabiler Energiekern
|
|
Gehäuse : Pappkarton, Bierkasten oder auch gar keins
|
|
Tastatur : Hlb fktonrnd odr bsr
|
|
Maus : Aus Plastik oder mit extra Quietsch-Effekt
|
|
Monitor : Olle Röhre oder gebrochener Flachbild (Mindestens 800x450)
|
|
Stuhl : Interessiert niemanden (sonst siehe Gehäuse)
|
|
|
|
[[oder einfach einen Toaster mit nem LCD und Maus]]
|
|
*/
|
|
|
|
public class Client implements IThreadListener {
|
|
public static class SyncFunction implements IntFunction {
|
|
public void apply(IntVar cv, int value) {
|
|
Client.CLIENT.sync(value);
|
|
}
|
|
}
|
|
|
|
public static class TickFunction implements FloatFunction {
|
|
public void apply(FloatVar cv, float value) {
|
|
Client.CLIENT.tick_target(value);
|
|
}
|
|
}
|
|
|
|
public static class ConsoleFunction implements IntFunction {
|
|
public void apply(IntVar cv, int value) {
|
|
Client.CLIENT.resizeConsole();
|
|
}
|
|
}
|
|
|
|
public static class ChatFunction implements IntFunction {
|
|
public void apply(IntVar cv, int value) {
|
|
Client.CLIENT.resizeChat();
|
|
}
|
|
}
|
|
|
|
public static class FeedFunction implements IntFunction {
|
|
public void apply(IntVar cv, int value) {
|
|
Client.CLIENT.resizeFeed();
|
|
}
|
|
}
|
|
|
|
public static class HotbarFunction implements IntFunction {
|
|
public void apply(IntVar cv, int value) {
|
|
Client.CLIENT.resizeHotbar();
|
|
}
|
|
}
|
|
|
|
public static class DistanceFunction implements IntFunction {
|
|
public void apply(IntVar cv, int value) {
|
|
Client.CLIENT.applyDistance();
|
|
}
|
|
}
|
|
|
|
public static class RedrawFunction implements IntFunction {
|
|
public void apply(IntVar cv, int value) {
|
|
Client.CLIENT.rescale();
|
|
}
|
|
}
|
|
|
|
public static class ItemRedrawFunction implements BoolFunction {
|
|
public void apply(BoolVar cv, boolean value) {
|
|
Client.CLIENT.rescale();
|
|
}
|
|
}
|
|
|
|
public static class LevelFunction implements EnumFunction<LogLevel> {
|
|
public void apply(EnumVar cv, LogLevel value) {
|
|
Log.setLevel(value);
|
|
}
|
|
}
|
|
|
|
public static class FontFunction implements EnumFunction<Font> {
|
|
public void apply(EnumVar cv, Font value) {
|
|
Font.select(value);
|
|
Client.CLIENT.rescale();
|
|
}
|
|
}
|
|
|
|
public static class StyleFunction implements EnumFunction<Style> {
|
|
public void apply(EnumVar cv, Style value) {
|
|
Client.CLIENT.rescale();
|
|
}
|
|
}
|
|
|
|
public static class MidiDebugFunction implements BoolFunction {
|
|
public void apply(BoolVar cv, boolean value) {
|
|
Client.CLIENT.setMidiDebug();
|
|
}
|
|
}
|
|
|
|
public static class MidiVisFunction implements BoolFunction {
|
|
public void apply(BoolVar cv, boolean value) {
|
|
if(Client.CLIENT.open instanceof GuiPlayer)
|
|
Client.CLIENT.rescale();
|
|
}
|
|
}
|
|
|
|
public static class MidiFlagFunction implements BoolFunction {
|
|
public void apply(BoolVar cv, boolean value) {
|
|
if(Client.CLIENT.getAudioInterface() != null)
|
|
GuiPlayer.INSTANCE.updateFlags();
|
|
}
|
|
}
|
|
|
|
public static class MidiIntFunction implements IntFunction {
|
|
public void apply(IntVar cv, int value) {
|
|
if(Client.CLIENT.getAudioInterface() != null)
|
|
GuiPlayer.INSTANCE.updateFlags();
|
|
}
|
|
}
|
|
|
|
public static class MidiBankFunction implements EnumFunction<MidiBank> {
|
|
public void apply(EnumVar cv, MidiBank value) {
|
|
if(Client.CLIENT.getAudioInterface() != null)
|
|
GuiPlayer.INSTANCE.updateBank();
|
|
}
|
|
}
|
|
|
|
private interface DebugRunner {
|
|
void execute(Keysym key);
|
|
}
|
|
|
|
private record DebugFunction(Keysym key, DebugRunner runner, String help) {
|
|
}
|
|
|
|
private final class WorldClient extends World {
|
|
public WorldClient(Dimension dim) {
|
|
super(dim, true);
|
|
this.orbit = dim.getOrbit();
|
|
this.rotation = dim.getRotation();
|
|
this.calculateInitialWeather();
|
|
this.updatePhysics();
|
|
}
|
|
|
|
protected void onEntityAdded(Entity entityIn) {
|
|
}
|
|
|
|
protected void onEntityRemoved(Entity entityIn) {
|
|
if(Client.this.entityList.contains(entityIn)) {
|
|
if(!entityIn.isEntityAlive())
|
|
Client.this.entityList.remove(entityIn);
|
|
}
|
|
}
|
|
|
|
public Entity getEntityByID(int id) {
|
|
return id == Client.this.player.getId() ? Client.this.player : super.getEntityByID(id);
|
|
}
|
|
|
|
public void clientSound(SoundEvent sound, double x, double y, double z, float volume) {
|
|
Client.this.getSoundManager().playSound(new PositionedSound(sound, volume, (float)x, (float)y, (float)z));
|
|
}
|
|
|
|
public Chunk getChunk(int x, int z) {
|
|
return Client.this.getChunk(x, z);
|
|
}
|
|
|
|
public Chunk getChunk(LocalPos pos) {
|
|
return Client.this.getChunk(pos.getX() >> 4, pos.getZ() >> 4);
|
|
}
|
|
|
|
protected float getTemperature(LocalPos pos) {
|
|
if(!isValid(pos))
|
|
return 0.0f;
|
|
ChunkClient chunk = Client.this.getChunk(pos.getX() >> 4, pos.getZ() >> 4);
|
|
return pos.getY() > 64 ? chunk.getTemperature(pos) - (chunk.getOffset(pos) + (float)pos.getY() - 64.0F) / 15.0f : chunk.getTemperature(pos);
|
|
}
|
|
|
|
protected boolean isLoaded(int x, int z, boolean allowEmpty) {
|
|
return allowEmpty || !Client.this.getChunk(x, z).isDummy();
|
|
}
|
|
|
|
public void clientParticle(ParticleType particle, double xCoord, double yCoord, double zCoord, int data) {
|
|
Client.this.effectRenderer.spawnParticle(Client.this.getRenderViewEntity(), particle, xCoord, yCoord, zCoord, data);
|
|
}
|
|
|
|
public void playEffect(EntityNPC player, int sfxType, LocalPos blockPosIn, int data) {
|
|
if(Client.this.getNetHandler() != null)
|
|
Client.this.getNetHandler().playAuxSFX(sfxType, blockPosIn, data);
|
|
}
|
|
|
|
public void markBlockForUpdate(LocalPos pos) {
|
|
int x = pos.getX();
|
|
int y = pos.getY();
|
|
int z = pos.getZ();
|
|
Client.this.renderer.markUpdate(x - 1, y - 1, z - 1, x + 1, y + 1, z + 1);
|
|
}
|
|
|
|
public void clientNotifyLight(LocalPos pos) {
|
|
int x = pos.getX();
|
|
int y = pos.getY();
|
|
int z = pos.getZ();
|
|
Client.this.renderer.markUpdate(x - 1, y - 1, z - 1, x + 1, y + 1, z + 1);
|
|
}
|
|
|
|
public void clientRenderUpdate(int x1, int y1, int z1, int x2, int y2, int z2) {
|
|
Client.this.renderer.markUpdate(x1 - 1, y1 - 1, z1 - 1, x2 + 1, y2 + 1, z2 + 1);
|
|
}
|
|
|
|
public void setLastLightning(int last, int color) {
|
|
Client.this.renderer.setLastLightning(last, color);
|
|
}
|
|
|
|
public void checkBlockLight(LocalPos pos) {
|
|
Client.this.renderer.checkBlockLight(pos);
|
|
}
|
|
|
|
public int getCombinedLight(LocalPos pos) {
|
|
return Client.this.renderer.getCombinedLight(pos);
|
|
}
|
|
|
|
public int getCombinedBrightness(LocalPos pos) {
|
|
return Client.this.renderer.getCombinedBrightness(pos);
|
|
}
|
|
}
|
|
|
|
public static final String VERSION = Version.NAME + " Client " + Util.VERSION;
|
|
public static final int LOG_BUFFER = 32768;
|
|
public static final int MIN_WIDTH = 800;
|
|
public static final int MIN_HEIGHT = 450;
|
|
|
|
private final Thread thread = Thread.currentThread();
|
|
private final NioEventLoopGroup eventGroup = new NioEventLoopGroup(0, Util.getThreadFactory("Netty Client IO"));
|
|
private final Queue<Runnable> tasks = new ArrayDeque<Runnable>();
|
|
private final Map<Integer, Long> bars = Maps.newTreeMap();
|
|
private final Map<String, CVar> cvars = Maps.newTreeMap();
|
|
private final Map<String, Field> synced = Maps.newTreeMap();
|
|
private final Map<Keysym, DebugFunction> debug = Maps.newTreeMap();
|
|
private final List<Message> console = Lists.newArrayList();
|
|
private final List<Message> chat = Lists.newArrayList();
|
|
private final List<Message> feed = Lists.newArrayList();
|
|
private final List<Message> hotbar = Lists.newArrayList();
|
|
private final File config = new File(System.getProperty("config.file", "client.cfg"));
|
|
private final Bind[] keyBindsHotbar = new Bind[] {
|
|
Bind.SELECT1, Bind.SELECT2, Bind.SELECT3, Bind.SELECT4, Bind.SELECT5, Bind.SELECT6, Bind.SELECT7, Bind.SELECT8,
|
|
Bind.SELECT9, Bind.SELECT10, Bind.SELECT11, Bind.SELECT12, Bind.SELECT13, Bind.SELECT14, Bind.SELECT15, Bind.SELECT16
|
|
};
|
|
private final int[] tickTimes = new int[240];
|
|
private final long[] frames = new long[240];
|
|
public final Map<String, Integer> playerList = Maps.<String, Integer>newTreeMap();
|
|
public final List<PlayerCharacter> characterList = Lists.<PlayerCharacter>newArrayList();
|
|
private final Set<Entity> entityList = Sets.<Entity>newHashSet();
|
|
private final LongHashMap<ChunkClient> chunkMapping = new LongHashMap();
|
|
private final Set<Long> emptyChunkListing = Sets.<Long>newHashSet();
|
|
private final Set<Long> nextEmptyChunkListing = Sets.<Long>newHashSet();
|
|
public final int[] lastSelection = new int[ItemCategory.values().length];
|
|
|
|
private boolean primary;
|
|
private boolean secondary;
|
|
private boolean tertiary;
|
|
private boolean quarternary;
|
|
private boolean showHud = true;
|
|
private boolean cfgDirty;
|
|
private boolean waitingForFile;
|
|
private boolean refreshing;
|
|
private boolean debugPlayer;
|
|
private boolean mouseFirst;
|
|
private boolean nograb = System.getProperty("mouse.nograb") != null;
|
|
private boolean syncLimited;
|
|
private boolean vsync;
|
|
private boolean screenshot;
|
|
private boolean saving;
|
|
private boolean drawFps;
|
|
private boolean drawDebug;
|
|
public boolean jump;
|
|
public boolean sneak;
|
|
public boolean debugCamEnable;
|
|
public boolean debugWorld;
|
|
public boolean zooming;
|
|
public boolean sprint;
|
|
public boolean renderOutlines;
|
|
public boolean setGamma;
|
|
public boolean xrayActive;
|
|
public boolean tileOverlay;
|
|
public boolean itemCheat;
|
|
public boolean cameraUsed;
|
|
public boolean charEditor;
|
|
public boolean fullscreen;
|
|
public boolean interrupted;
|
|
public boolean freecam;
|
|
public boolean servercam;
|
|
public boolean shaders;
|
|
public volatile boolean worldLight;
|
|
|
|
private int leftClickCounter;
|
|
private int rightClickTimer;
|
|
private int chunkLoadTimer;
|
|
private int tickTarget;
|
|
private int tickFrame;
|
|
private int mouseRawX;
|
|
private int mouseRawY;
|
|
private int scale = 1;
|
|
private int lastTickTime = -1;
|
|
private int tickIndex;
|
|
private int lastIndex;
|
|
private int frameCounter;
|
|
private int frameIndex;
|
|
public int thirdPersonView;
|
|
public int chunksUpdated;
|
|
public int selectedCharacter = -1;
|
|
public int fbRawX;
|
|
public int fbRawY;
|
|
public int fbX;
|
|
public int fbY;
|
|
public int mouseX;
|
|
public int mouseY;
|
|
|
|
private long lastTicked = 0L;
|
|
private long debugUpdateTime = System.currentTimeMillis();
|
|
private long tickStart;
|
|
private long frameLast;
|
|
private long frameWait;
|
|
private long startNanoTime = System.nanoTime();
|
|
private long tmr_timer;
|
|
private long tmr_start;
|
|
private long tmr_current;
|
|
private long tmr_last;
|
|
private long tmr_delta;
|
|
private long tmr_update;
|
|
private long tmr_frames;
|
|
private long tmr_iters;
|
|
private long tick_torun;
|
|
private long tick_done;
|
|
private long tick_total;
|
|
private long tick_time;
|
|
private long tick_stime;
|
|
private long tick_ftime;
|
|
private long tick_ttime;
|
|
private long tick_update;
|
|
private long syncLimit;
|
|
|
|
private float deltaX;
|
|
private float deltaY;
|
|
private float framerate;
|
|
private float tickrate;
|
|
private float fdelta;
|
|
public float moveStrafe;
|
|
public float moveForward;
|
|
public float zoomLevel;
|
|
|
|
private double tickFraction;
|
|
|
|
private TextureManager textureManager;
|
|
private RenderManager renderManager;
|
|
private RenderItem renderItem;
|
|
private ItemRenderer itemRenderer;
|
|
private TextureMap textureMap;
|
|
private ModelManager modelManager;
|
|
public EffectRenderer effectRenderer;
|
|
public Renderer renderer;
|
|
public Gui open;
|
|
|
|
private SoundManager soundManager;
|
|
|
|
private NetConnection connection;
|
|
private Entity viewEntity;
|
|
private Entity pointedEntity;
|
|
private String serverInfo;
|
|
private AudioInterface audio;
|
|
private String buffer = "";
|
|
public PlayerController controller;
|
|
public World world;
|
|
public EntityNPC player;
|
|
public HitPosition pointed;
|
|
public LocalPos pointedLiquid;
|
|
public DisplayMode vidMode;
|
|
public String dimensionName;
|
|
public ItemCategory itemSelection = ItemCategory.USEABLE;
|
|
private ChunkClient emptyChunk;
|
|
private ChunkClient outsideChunk;
|
|
|
|
private List<Entity> entities;
|
|
private List<Entity> unloaded;
|
|
private List<TileEntity> tiles;
|
|
private IntHashMap<Entity> entityIds;
|
|
|
|
|
|
@Variable(name = "chunk_view_distance", category = CVarCategory.RENDER, min = 2, max = 32, callback = DistanceFunction.class, display = "Sichtweite", unit = "Chunks")
|
|
public int renderDistance = 8;
|
|
@Variable(name = "chunk_build_time", category = CVarCategory.RENDER, min = 1, max = 100, display = "Zeit für Chunk-Bau", unit = "ms")
|
|
public int maxBuildTime = 8;
|
|
@Variable(name = "chunk_light_updates", category = CVarCategory.RENDER, min = 0, max = 10000, display = "Licht-Updates / Frame")
|
|
private int lightUpdates = 300;
|
|
@Variable(name = "chunk_light_range", category = CVarCategory.RENDER, min = 5, max = 512, display = "Radius Licht-Updates")
|
|
private int lightRange = 32;
|
|
@Variable(name = "draw_fov", category = CVarCategory.RENDER, min = 20.0f, max = 160.0f, display = "Sichtfeld (FOV)", unit = "°", precision = 1)
|
|
public float fov = 70.0f;
|
|
@Variable(name = "draw_wireframe", category = CVarCategory.RENDER, display = "Gitter-Render-Modus")
|
|
private boolean wireframe = false;
|
|
|
|
@Variable(name = "con_timestamps", category = CVarCategory.CONSOLE, display = "Zeiten")
|
|
private boolean conTimestamps = false;
|
|
@Variable(name = "con_loglevel", category = CVarCategory.CONSOLE, display = "Ausgabe", callback = LevelFunction.class)
|
|
private LogLevel level = LogLevel.INFO;
|
|
|
|
@Variable(name = "win_sync", category = CVarCategory.WINDOW, min = -1, max = 16384, callback = SyncFunction.class, display = "Maximale Bildrate")
|
|
public int sync = 0;
|
|
|
|
@Variable(name = "win_width", category = CVarCategory.WINDOW, min = MIN_WIDTH, max = 65536, display = "Fensterbreite")
|
|
private int sizeX = 1280;
|
|
@Variable(name = "win_height", category = CVarCategory.WINDOW, min = MIN_HEIGHT, max = 65536, display = "Fensterhöhe")
|
|
private int sizeY = 800;
|
|
@Variable(name = "win_pos_x", category = CVarCategory.WINDOW, min = -65536, max = 65536, display = "Fenster X-Position")
|
|
private int savedX = 0x80000000;
|
|
@Variable(name = "win_pos_y", category = CVarCategory.WINDOW, min = -65536, max = 65536, display = "Fenster Y-Position")
|
|
private int savedY = 0x80000000;
|
|
|
|
@Variable(name = "gui_scale", category = CVarCategory.GUI, min = 1, max = 5, display = "Skalierung", unit = "x", callback = RedrawFunction.class)
|
|
private int scaleVar = 1;
|
|
@Variable(name = "hud_margin", category = CVarCategory.GUI, min = 0, max = 120, unit = "px", display = "Seitenabstand der HUD")
|
|
private int hudMargin = 4;
|
|
@Variable(name = "phy_sensitivity", category = CVarCategory.INPUT, min = 0.01f, max = 10.0f, display = "Mausempfindlichkeit", precision = 2, unit = "%")
|
|
private float sensitivity = 1.0f;
|
|
@Variable(name = "gui_dclick_delay", category = CVarCategory.INPUT, min = 150, max = 750, display = "Doppelklick bei", unit = "ms")
|
|
public int dclickDelay = 250;
|
|
@Variable(name = "console_size", category = CVarCategory.CONSOLE, min = 0, max = 128, callback = ConsoleFunction.class, display = "Nachrichten in Konsole")
|
|
private int consoleSize = 32;
|
|
@Variable(name = "chat_size", category = CVarCategory.CONSOLE, min = 0, max = 128, callback = ChatFunction.class, display = "Nachrichten im Chat")
|
|
private int chatSize = 32;
|
|
@Variable(name = "feed_size", category = CVarCategory.CONSOLE, min = 0, max = 128, callback = FeedFunction.class, display = "Nachrichten im Feed")
|
|
private int feedSize = 8;
|
|
@Variable(name = "hotbar_size", category = CVarCategory.CONSOLE, min = 0, max = 16, callback = HotbarFunction.class, display = "Nachrichten in Hotbar")
|
|
private int hotbarSize = 2;
|
|
@Variable(name = "overlay_fadeout", category = CVarCategory.CONSOLE, min = 1, max = 60, display = "Anzeigedauer", unit = "s")
|
|
private int hudFadeout = 8;
|
|
@Variable(name = "overlay_enabled", category = CVarCategory.CONSOLE, display = "Nachrichten-Overlay")
|
|
private boolean hudOverlay = true;
|
|
@Variable(name = "chat_permanent", category = CVarCategory.CONSOLE, display = "Chat immer einblenden")
|
|
private boolean chatPermanent = false;
|
|
@Variable(name = "overlay_opacity", category = CVarCategory.CONSOLE, min = 0x00, max = 0xff, display = "Deckkraft Hintergrund")
|
|
private int hudOpacity = 0x40;
|
|
@Variable(name = "vsync_flush", category = CVarCategory.RENDER, display = "Puffer leeren")
|
|
private boolean glFlush = false;
|
|
@Variable(name = "con_autoclose", category = CVarCategory.CONSOLE, display = "Schließen")
|
|
public boolean conAutoclose = true;
|
|
@Variable(name = "gui_theme", category = CVarCategory.GUI, display = "Design", callback = StyleFunction.class)
|
|
public Style style = Style.DEFAULT;
|
|
@Variable(name = "gui_scroll_lines", category = CVarCategory.GUI, min = 1, max = 10, display = "Scrollbreite", unit = "Zeilen")
|
|
public int scrollLines = 3;
|
|
@Variable(name = "gui_font", category = CVarCategory.GUI, display = "Schriftart", callback = FontFunction.class)
|
|
private Font font = Font.LARGE;
|
|
|
|
@Variable(name = "draw_downfall_range", category = CVarCategory.RENDER, min = 0, max = 15, display = "Niederschlag-Radius")
|
|
public int downfallRange = 4;
|
|
@Variable(name = "draw_rain_particle_range", category = CVarCategory.RENDER, min = 0, max = 25, display = "Regen-Partikel-Radius")
|
|
public int rainParticleRange = 10;
|
|
@Variable(name = "draw_void_particles", category = CVarCategory.RENDER, display = "Partikel in der Tiefe")
|
|
private boolean voidParticles = true;
|
|
@Variable(name = "draw_void_fog", category = CVarCategory.RENDER, display = "Nebel in der Tiefe")
|
|
public boolean voidFog = true;
|
|
@Variable(name = "draw_player_firstperson", category = CVarCategory.RENDER, display = "Spieler in 1. Person")
|
|
public boolean showPlayerFirstPerson = false;
|
|
@Variable(name = "crosshair_size", category = CVarCategory.GUI, min = 0, max = 32, display = "Größe des Fadenkreuzes")
|
|
private int crosshairSize = 6;
|
|
@Variable(name = "crosshair_color_notarget", type = IntType.COLOR, category = CVarCategory.GUI, display = "Fadenkreuz-Farbe (ohne Ziel)")
|
|
private int crosshairColorBase = 0xffcfcfcf;
|
|
@Variable(name = "crosshair_color_target", type = IntType.COLOR, category = CVarCategory.GUI, display = "Fadenkreuz-Farbe (mit Ziel)")
|
|
private int crosshairColorTarget = 0xffffffff;
|
|
@Variable(name = "crosshair_simple", category = CVarCategory.GUI, display = "Einfaches Fadenkreuz")
|
|
private boolean crosshairSimple = false;
|
|
@Variable(name = "info_overlay", category = CVarCategory.GUI, display = "Informations-Overlay")
|
|
private boolean infoOverlay = true;
|
|
|
|
@Variable(name = "tic_target", category = CVarCategory.SYSTEM, min = 1.0f, max = 1200.0f, callback = TickFunction.class, display = "Tickrate")
|
|
private float tpsTarget = 20.0f;
|
|
@Variable(name = "tic_timeout", category = CVarCategory.SYSTEM, min = 1, max = 60000, display = "Tick-Timeout-Zeit")
|
|
private int tickTimeout = 2000;
|
|
|
|
@Variable(name = "snd_enabled", category = CVarCategory.SOUND, display = "Tonausgabe")
|
|
private boolean soundEnabled = true;
|
|
@Variable(name = "snd_buffer_size", category = CVarCategory.SOUND, min = 0, max = 1048576, display = "Puffer")
|
|
private int soundBufferSize = 16384;
|
|
@Variable(name = "snd_frame_size", category = CVarCategory.SOUND, min = 2, max = 8192, display = "Intervall")
|
|
private int soundFrameSize = 32;
|
|
|
|
@Variable(name = "mid_dont_fade", category = CVarCategory.SOUND, display = "Nicht ausklingen", callback = MidiFlagFunction.class)
|
|
public boolean midiNoWait = false;
|
|
@Variable(name = "mid_opl_voices", category = CVarCategory.SOUND, min = 4, max = 192, display = "OPL-Stimmen")
|
|
public int midiVoices = 64;
|
|
@Variable(name = "mid_pitchbend_range", category = CVarCategory.SOUND, min = 0, max = 24, display = "Pitch-Bend-Bereich", callback = MidiIntFunction.class)
|
|
public int midiPitchBendRange = 2;
|
|
@Variable(name = "mid_keep_notes", category = CVarCategory.SOUND, display = "Stimmen behalten", callback = MidiFlagFunction.class)
|
|
public boolean midiKeep = false;
|
|
@Variable(name = "mid_play_unknown", category = CVarCategory.SOUND, display = "Unbekannte Banken", callback = MidiFlagFunction.class)
|
|
public boolean midiUnknown = true;
|
|
// STR(MID_VELO_LOG, "", "Log.+Minimum [m+nlog(x)]")
|
|
// STR(MID_VELO_ATTN, "", "Log. Gedämpft [nlog(x)]")
|
|
// STR(MID_VELO_LIN, "", "Linear [x]")
|
|
// STR(MID_VELO_ONE, "", "Vollklang [1]")
|
|
@Variable(name = "mid_velocity_func", category = CVarCategory.SOUND, min = -128, max = 127, display = "Anschlag", callback = MidiIntFunction.class)
|
|
public int midiVelocity = 1;
|
|
@Variable(name = "mid_opl_bank", category = CVarCategory.SOUND, display = "Bank", callback = MidiBankFunction.class)
|
|
public MidiBank midiBank = MidiBank.DMX_DMX;
|
|
@Variable(name = "mid_debug_events", category = CVarCategory.SOUND, display = "MIDI-Debug", callback = MidiDebugFunction.class)
|
|
public boolean midiDebug = false;
|
|
@Variable(name = "mid_visualizer", category = CVarCategory.SOUND, display = "Visualisation", callback = MidiVisFunction.class)
|
|
public boolean midiVisualizer = true;
|
|
@Variable(name = "mid_ch_16_workaround", category = CVarCategory.SOUND, display = "Kanal 16 als Perkussion", callback = MidiFlagFunction.class)
|
|
public boolean midiCh16Drums = false;
|
|
@Variable(name = "mid_allow_switch_perc_ch", category = CVarCategory.SOUND, display = "Perk.-Kanäle änderbar", callback = MidiFlagFunction.class)
|
|
public boolean midiDrumProgs = false;
|
|
|
|
@Variable(name = "draw_use_shader", category = CVarCategory.RENDER, display = "Shader verwenden")
|
|
public boolean useShader = false;
|
|
|
|
public static final Client CLIENT = new Client();
|
|
|
|
public static void main(String[] args) {
|
|
long time = System.currentTimeMillis();
|
|
Util.checkPlatform();
|
|
Thread.currentThread().setName("Render thread");
|
|
Locale.setDefault(Locale.ROOT);
|
|
Util.setupHandlers();
|
|
Log.init();
|
|
Log.SYSTEM.info("Java " + System.getProperty("java.version"));
|
|
Log.SYSTEM.info("Starte " + VERSION + " (Protokoll #" + Util.PROTOCOL + ")");
|
|
if(Util.DEVMODE)
|
|
Log.SYSTEM.warn("Entwicklungsmodus aktiv - Debugging-Features sind verfügbar");
|
|
Window.init();
|
|
Registry.register();
|
|
Log.setSync(CLIENT);
|
|
CLIENT.run(time);
|
|
Window.end();
|
|
}
|
|
|
|
private Client() {
|
|
}
|
|
|
|
private NetConnection connect(InetAddress address, int port) {
|
|
final NetConnection connection = new NetConnection();
|
|
new Bootstrap().group(this.eventGroup).handler(new ChannelInitializer<Channel>() {
|
|
protected void initChannel(Channel channel) throws Exception {
|
|
try {
|
|
channel.config().setOption(ChannelOption.TCP_NODELAY, true);
|
|
}
|
|
catch(ChannelException e) {
|
|
}
|
|
channel.pipeline().addLast("timeout", new ReadTimeoutHandler(30)).addLast("splitter", new PacketSplitter())
|
|
.addLast("decoder", new PacketDecoder(false)).addLast("prepender", new PacketPrepender())
|
|
.addLast("encoder", new PacketEncoder(true)).addLast("packet_handler", connection);
|
|
}
|
|
}).channel(NioSocketChannel.class).connect(address, port).syncUninterruptibly();
|
|
return connection;
|
|
}
|
|
|
|
public void displayConnecting(ServerInfo server) {
|
|
this.show(new GuiLoading("Verbinde zu " + (server.getAddress() == null ? "localhost" : server.getAddress()) + ":" + server.getPort() + " ..."));
|
|
}
|
|
|
|
public void connect(final ServerInfo server) {
|
|
this.displayConnecting(server);
|
|
Log.NETWORK.info("Verbinde zu " + (server.getAddress() == null ? "localhost" : server.getAddress()) + ":" + server.getPort());
|
|
new Thread(new Runnable() {
|
|
public void run() {
|
|
final NetConnection connection;
|
|
try
|
|
{
|
|
connection = Client.this.connect(server.getAddress() == null ? InetAddress.getLoopbackAddress() : InetAddress.getByName(IDN.toASCII(server.getAddress())), server.getPort());
|
|
connection.setNetHandler(new ClientLoginHandler(connection, Client.this, server));
|
|
connection.sendPacket(new HPacketHandshake(Util.PROTOCOL), new GenericFutureListener<Future<? super Void>>() {
|
|
public void operationComplete(Future<? super Void> u) throws Exception {
|
|
connection.setConnectionState(PacketRegistry.LOGIN);
|
|
}
|
|
});
|
|
}
|
|
catch (UnknownHostException u)
|
|
{
|
|
Log.NETWORK.error(u, "Konnte nicht zu Server verbinden");
|
|
Client.this.schedule(new Runnable() {
|
|
public void run() {
|
|
Client.this.disconnected("Unbekannter Hostname: " + (server.getAddress() == null ? "localhost" : server.getAddress()));
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Log.NETWORK.error(e, "Konnte nicht zu Server verbinden");
|
|
Client.this.schedule(new Runnable() {
|
|
public void run() {
|
|
Client.this.disconnected((e instanceof RuntimeException && !(e.getCause() instanceof RuntimeException) ? e.getCause() : e).toString());
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
Client.this.schedule(new Runnable() {
|
|
public void run() {
|
|
Client.this.connection = connection;
|
|
}
|
|
});
|
|
}
|
|
}, "Server connector").start();
|
|
}
|
|
|
|
public void joinDebugWorld() {
|
|
ClientPlayer player = new ClientPlayer(this, new DummyConnection());
|
|
this.debugWorld = true;
|
|
this.charEditor = false;
|
|
this.dimensionName = "debug";
|
|
Space.INSTANCE.setDisplay("Debug-Welt");
|
|
this.controller = new PlayerController(this, player);
|
|
this.loadWorld(Space.INSTANCE, EntityRegistry.getEntityID(EntityCameraHolder.class));
|
|
this.player.setId(0);
|
|
this.show(null);
|
|
this.player.flying = true;
|
|
this.player.noclip = true;
|
|
this.player.addEffect(new StatusEffect(Effect.FLYING, Integer.MAX_VALUE, 1));
|
|
this.player.setHeight(2.0f);
|
|
}
|
|
|
|
public void unloadWorld() {
|
|
this.worldLight = false;
|
|
ClientPlayer netHandler = this.getNetHandler();
|
|
if(netHandler != null)
|
|
netHandler.cleanup();
|
|
EntityTexManager.clearTextures();
|
|
DimensionMapping.clear();
|
|
this.dimensionName = null;
|
|
Space.INSTANCE.setDisplay(null);
|
|
this.debugWorld = false;
|
|
this.charEditor = false;
|
|
this.viewEntity = null;
|
|
this.freecam = this.servercam = false;
|
|
this.connection = null;
|
|
this.world = null;
|
|
this.resetWorld();
|
|
this.player = null;
|
|
this.serverInfo = null;
|
|
Arrays.fill(this.lastSelection, 0);
|
|
this.itemSelection = ItemCategory.USEABLE;
|
|
this.lastTickTime = -1;
|
|
this.selectedCharacter = -1;
|
|
this.playerList.clear();
|
|
this.characterList.clear();
|
|
this.soundManager.stopSounds();
|
|
}
|
|
|
|
public void refreshResources()
|
|
{
|
|
this.logFeed("Lade Texturen neu");
|
|
Font.unloadFonts();
|
|
Font.loadFonts();
|
|
Font.select(this.font);
|
|
if(this.shaders)
|
|
ShaderContext.loadShaders();
|
|
this.textureManager.onReload();
|
|
this.modelManager.onReload();
|
|
this.renderItem.onReload();
|
|
this.renderer.cacheSprites();
|
|
EntityTexManager.loadNpcTextures();
|
|
this.textureManager.bindTexture(TextureMap.BLOCKS);
|
|
TextureUtil.setParams();
|
|
this.renderer.loadRenderers();
|
|
this.logFeed("Texturen wurden neu geladen");
|
|
}
|
|
|
|
public void init()
|
|
{
|
|
this.textureManager = new TextureManager();
|
|
this.textureManager.onReload();
|
|
this.soundManager = new SoundManager(this);
|
|
Log.RENDER.debug("Maximale Texturgröße: %d", GL15.glGetInteger(GL15.GL_MAX_TEXTURE_SIZE));
|
|
Log.RENDER.debug("Shader verfügbar: %s", (this.shaders = GL.getCapabilities().OpenGL20) ? "Ja (OpenGL 2.0+)" : "Nein (OpenGL 1.5)");
|
|
GlState.enableTexture2D();
|
|
GlState.shadeModel(GL15.GL_SMOOTH);
|
|
GL15.glClearDepth(1.0D);
|
|
GlState.enableDepth();
|
|
GlState.depthFunc(GL15.GL_LEQUAL);
|
|
GlState.enableAlpha();
|
|
GlState.alphaFunc(GL15.GL_GREATER, 0.1F);
|
|
GlState.cullFace(GL15.GL_BACK);
|
|
GlState.enableCull();
|
|
GL15.glMatrixMode(GL15.GL_PROJECTION);
|
|
GL15.glLoadIdentity();
|
|
GL15.glMatrixMode(GL15.GL_MODELVIEW);
|
|
this.textureMap = new TextureMap();
|
|
this.textureManager.loadTexture(TextureMap.BLOCKS, this.textureMap);
|
|
this.modelManager = new ModelManager(this.textureMap);
|
|
this.modelManager.onReload();
|
|
this.renderItem = new RenderItem(this.textureManager, this.modelManager);
|
|
this.renderManager = new RenderManager(this.textureManager, this.renderItem);
|
|
this.itemRenderer = new ItemRenderer(this);
|
|
this.renderItem.onReload();
|
|
this.renderer = new Renderer(this, this.modelManager);
|
|
this.renderer.cacheSprites();
|
|
EntityTexManager.loadNpcTextures();
|
|
this.effectRenderer = new EffectRenderer(this.textureManager);
|
|
|
|
for(Field field : Vars.class.getDeclaredFields()) {
|
|
if(field.isAnnotationPresent(Var.class)) {
|
|
if(!Modifier.isStatic(field.getModifiers()) || Modifier.isFinal(field.getModifiers()))
|
|
throw new IllegalArgumentException("Feld für Variable " + field + " muss statisch und änderbar sein!");
|
|
Var value = field.getAnnotation(Var.class);
|
|
if(value.name().isEmpty())
|
|
throw new IllegalArgumentException("Variablenname von " + field + " kann nicht leer sein!");
|
|
if(this.synced.containsKey(value.name()))
|
|
throw new IllegalArgumentException("Variable " + value.name() + " existiert bereits!");
|
|
this.synced.put(value.name(), field);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void start()
|
|
{
|
|
this.tickStart = System.nanoTime();
|
|
synchronized (this.tasks)
|
|
{
|
|
while (!this.tasks.isEmpty())
|
|
{
|
|
Runnable task = this.tasks.poll();
|
|
try {
|
|
task.run();
|
|
}
|
|
catch(Throwable e) {
|
|
if(!(e instanceof ThreadQuickExitException))
|
|
Log.SYSTEM.error(e, "Fehler beim Ausführen von Render-Task " + task);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void inputGui() {
|
|
if (this.open != null)
|
|
{
|
|
if(!(this.open.selected instanceof client.gui.element.Field || this.open.selected instanceof Area)) {
|
|
if(Bind.THROW.isPressed())
|
|
this.open.dropItem();
|
|
else if(Bind.RENAME.isPressed())
|
|
this.open.renameItem();
|
|
for(int z = 0; z < this.keyBindsHotbar.length; z++) {
|
|
if(this.keyBindsHotbar[z].isPressed())
|
|
this.open.useHotbar(z);
|
|
}
|
|
}
|
|
|
|
this.primary = this.secondary = this.tertiary = this.quarternary = false;
|
|
this.zooming = false;
|
|
}
|
|
|
|
else
|
|
{
|
|
if (Bind.PERSPECTIVE.isPressed() && this.viewEntity == this.player)
|
|
{
|
|
++this.thirdPersonView;
|
|
|
|
if (this.thirdPersonView > 2)
|
|
{
|
|
this.thirdPersonView = 0;
|
|
}
|
|
if (this.debugCamEnable && this.thirdPersonView == 2)
|
|
{
|
|
this.thirdPersonView = 0;
|
|
}
|
|
|
|
this.renderer.setDisplayListEntitiesDirty();
|
|
}
|
|
|
|
if (Bind.ITEMMODE.isPressed() && this.viewEntity == this.player)
|
|
{
|
|
this.category(this.shift() ? -1 : 1);
|
|
}
|
|
|
|
boolean hadZoom = this.zooming;
|
|
this.zooming = Bind.ZOOM.isDown() || this.viewEntity != this.player;
|
|
if(this.zooming && !hadZoom) {
|
|
this.zoomLevel = this.viewEntity != this.player ? 1.0f : 2.0f;
|
|
}
|
|
|
|
if(this.viewEntity == this.player) {
|
|
for (int l = 0; l < this.keyBindsHotbar.length && l < this.player.getHotbarSize(); ++l)
|
|
{
|
|
if (this.keyBindsHotbar[l].isPressed())
|
|
{
|
|
int n = 0;
|
|
for(int z = 0; z < this.player.getHotbarSize(); z++) {
|
|
if(this.player.getStackInSlot(z) == null || this.player.getStackInSlot(z).getItem().getCategory() != this.itemSelection)
|
|
continue;
|
|
if(l == n) {
|
|
if(this.player.getSelectedIndex() != z)
|
|
this.controller.resetUseCooldown();
|
|
this.player.setSelectedIndex(z);
|
|
break;
|
|
}
|
|
++n;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Bind.THROW.isPressed())
|
|
{
|
|
this.player.dropOneItem(this.ctrl());
|
|
}
|
|
else if(Bind.RENAME.isPressed()) {
|
|
ItemStack stack = this.player.getHeldItem();
|
|
if(stack != null)
|
|
this.show(new GuiRename(-1, stack, null));
|
|
}
|
|
|
|
this.primary |= Bind.PRIMARY.isPressed();
|
|
this.secondary |= Bind.SECONDARY.isPressed();
|
|
this.tertiary |= Bind.TERTIARY.isPressed();
|
|
this.quarternary |= Bind.QUARTERNARY.isPressed();
|
|
}
|
|
}
|
|
}
|
|
|
|
public void tick() {
|
|
if (this.rightClickTimer > 0)
|
|
{
|
|
--this.rightClickTimer;
|
|
}
|
|
this.renderer.getMouseOver(1.0F);
|
|
if (this.world != null)
|
|
{
|
|
this.controller.update();
|
|
}
|
|
this.textureMap.update();
|
|
if (this.open != null)
|
|
{
|
|
this.open.updateScreen();
|
|
}
|
|
|
|
if (this.open == null && this.player != null)
|
|
{
|
|
if (this.player.getHealth() <= 0)
|
|
{
|
|
this.show(null);
|
|
}
|
|
}
|
|
|
|
if (this.open != null)
|
|
{
|
|
this.leftClickCounter = 10000;
|
|
}
|
|
else if (this.leftClickCounter > 0)
|
|
{
|
|
--this.leftClickCounter;
|
|
}
|
|
|
|
if (this.open == null && this.player != null) {
|
|
if (this.player.isUsingItem())
|
|
{
|
|
if (!Bind.SECONDARY.isDown() || this.viewEntity != this.player)
|
|
{
|
|
this.controller.stopUsing(this.player);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (this.primary)
|
|
{
|
|
this.primary();
|
|
}
|
|
|
|
if (this.secondary)
|
|
{
|
|
this.secondary();
|
|
}
|
|
|
|
if (this.tertiary)
|
|
{
|
|
this.tertiary();
|
|
}
|
|
|
|
if (this.quarternary)
|
|
{
|
|
this.quarternary();
|
|
}
|
|
}
|
|
|
|
if (Bind.SECONDARY.isDown() && this.rightClickTimer == 0 && !this.player.isUsingItem() && this.viewEntity == this.player)
|
|
{
|
|
this.secondary();
|
|
}
|
|
|
|
this.sendClickBlockToController(this.open == null && Bind.PRIMARY.isDown() && this.viewEntity == this.player);
|
|
}
|
|
|
|
this.primary = this.secondary = this.tertiary = this.quarternary = false;
|
|
|
|
if (this.world != null)
|
|
{
|
|
if (this.player != null)
|
|
{
|
|
++this.chunkLoadTimer;
|
|
|
|
if (this.chunkLoadTimer == 30)
|
|
{
|
|
this.chunkLoadTimer = 0;
|
|
this.ensureAreaLoaded(this.player);
|
|
}
|
|
}
|
|
this.renderer.update();
|
|
this.world.updateEntities();
|
|
}
|
|
this.soundManager.update();
|
|
GuiPlayer.INSTANCE.updatePlayer();
|
|
if (this.world != null)
|
|
{
|
|
this.world.updatePhysics();
|
|
this.markReload();
|
|
|
|
if (Vars.timeFlow > 0)
|
|
{
|
|
if(this.world.dimension.hasOrbit())
|
|
this.world.setOrbit((this.world.getOrbit() + (long)Vars.timeFlow) % this.world.dimension.getOrbitalPeriod());
|
|
if(this.world.dimension.hasRotation())
|
|
this.world.setRotation((this.world.getRotation() + (long)Vars.timeFlow) % this.world.dimension.getRotationalPeriod());
|
|
this.world.dimension.setEpoch(this.world.dimension.getEpoch() + (long)Vars.timeFlow);
|
|
}
|
|
|
|
this.displayTick(ExtMath.floord(this.player.posX), ExtMath.floord(this.player.posY), ExtMath.floord(this.player.posZ));
|
|
this.effectRenderer.update();
|
|
if(this.player != null && (this.player.getHeldItem() == null || this.player.getHeldItem().getItem().getCategory() != this.itemSelection))
|
|
this.select(1);
|
|
}
|
|
else if (this.connection != null)
|
|
{
|
|
if(this.connection.isChannelOpen())
|
|
this.connection.processReceivedPackets();
|
|
else
|
|
this.connection.checkDisconnected();
|
|
}
|
|
}
|
|
|
|
public void render() {
|
|
GlState.tryBlendFuncSeparate(GL15.GL_SRC_ALPHA, GL15.GL_ONE_MINUS_SRC_ALPHA, GL15.GL_SRC_ALPHA, GL15.GL_ONE_MINUS_SRC_ALPHA);
|
|
GlState.enableDepth();
|
|
GlState.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
|
GL15.glClear(GL15.GL_COLOR_BUFFER_BIT | GL15.GL_DEPTH_BUFFER_BIT);
|
|
if(this.wireframe) {
|
|
GL15.glLineWidth(1.0f);
|
|
GL15.glPolygonMode(GL15.GL_FRONT_AND_BACK, GL15.GL_LINE);
|
|
}
|
|
if(this.open == null) {
|
|
if(this.player != null && this.viewEntity == this.player)
|
|
this.player.setAngles(this.deltaX, this.deltaY);
|
|
else if(this.player != null && this.viewEntity instanceof EntityCamera camera)
|
|
camera.setAnglesClamped(this.deltaX, this.deltaY);
|
|
this.deltaX = this.deltaY = 0.0f;
|
|
}
|
|
if(this.player != null)
|
|
this.soundManager.setListener(this.player, (float)this.tickFraction);
|
|
if(this.player != null && (this.player.isEntityInsideOpaqueBlock() || this.viewEntity != this.player))
|
|
this.thirdPersonView = 0;
|
|
GL15.glPushMatrix();
|
|
GL15.glClear(GL15.GL_COLOR_BUFFER_BIT | GL15.GL_DEPTH_BUFFER_BIT);
|
|
GlState.enableTexture2D();
|
|
if(this.world != null)
|
|
this.renderer.renderWorld((float)this.tickFraction, System.nanoTime() - this.tickStart);
|
|
GL15.glPopMatrix();
|
|
|
|
GlState.disableTexture2D();
|
|
GlState.disableCull();
|
|
GlState.enableBlend();
|
|
if(this.wireframe)
|
|
GL15.glPolygonMode(GL15.GL_FRONT_AND_BACK, GL15.GL_FILL);
|
|
}
|
|
|
|
private int drawStat(int x, int y, String name, int value, int max, int color) {
|
|
int w = (int)(246.0f * (float)value / (float)max);
|
|
Drawing.drawTextboxRight(name, x + 250, y, 0x3f000000);
|
|
Drawing.drawTextbox(String.format(Color.GREEN + "%d " + Color.GRAY + "/ " + Color.NEON + "%d", value, max), x, y, 0x3f000000);
|
|
Drawing.drawRectBorder(x, y + 20, 250, 10, 0xff000000, 0xff202020, 0xffcfcfcf, 0xff6f6f6f);
|
|
Drawing.drawGradient(x + 2 + 246 - w, y + 20 + 2, w, 6, color | 0xff000000, Util.mixColor(color | 0xff000000, 0xff000000));
|
|
return y + 40;
|
|
}
|
|
|
|
private int drawBar(int x, int y, String name, float fill, int color) {
|
|
Drawing.drawTextbox(name, x, y, 0x3f000000);
|
|
Drawing.drawRectBorder(x, y + 20, 250, 10, 0xff000000, 0xff202020, 0xffcfcfcf, 0xff6f6f6f);
|
|
Drawing.drawGradient(x + 2, y + 20 + 2, (int)(246.0f * fill), 6, color | 0xff000000, Util.mixColor(color | 0xff000000, 0xff000000));
|
|
return y + 40;
|
|
}
|
|
|
|
public void renderHud() {
|
|
final int selected = this.world != null && this.player != null && this.viewEntity == this.player ? this.player.getSelectedIndex() : -1;
|
|
final int scale = 2;
|
|
final int size = this.world != null && this.player != null && this.viewEntity == this.player ? this.player.getHotbarSize() : 1;
|
|
int total = 1;
|
|
if(this.world != null && this.player != null && this.viewEntity == this.player) {
|
|
total = 0;
|
|
for(int z = 0; z < this.player.getHotbarSize(); z++) {
|
|
if(this.player.getStackInSlot(z) != null && this.player.getStackInSlot(z).getItem().getCategory() == this.itemSelection)
|
|
++total;
|
|
}
|
|
if(total == 0)
|
|
total = 1;
|
|
}
|
|
final int width = (this.fbX / scale - 20) / total;
|
|
// final int bx = this.fbX / 2 - size * (width >= 20 ? 10 : width / 2) * scale + 2 * scale;
|
|
final int by = this.fbY - 20 * scale;
|
|
final int xoff = (this.fbX / scale - (width < 20 ? ((total - 2) * width + 40 + width / 2) : (total * 20 - 2))) / 2 + (width < 20 && selected == 0 ? 20 - width : 0) - 2;
|
|
this.setupOverlay();
|
|
if(this.world != null && !(this.open instanceof GuiConsole) && this.player != null && this.viewEntity == this.player) {
|
|
if(this.open == null) {
|
|
if(this.thirdPersonView == 0) {
|
|
if(this.drawDebug) {
|
|
this.renderWorldDirections((float)this.tickFraction);
|
|
}
|
|
else if(this.crosshairSize > 0) {
|
|
final int color = this.pointed != null && this.pointed.type != ObjectType.MISS ? this.crosshairColorTarget : this.crosshairColorBase;
|
|
if(this.crosshairSimple) {
|
|
Drawing.drawRect(this.fbX / 2 - 1, this.fbY / 2 - this.crosshairSize, 2, this.crosshairSize * 2, color);
|
|
Drawing.drawRect(this.fbX / 2 - this.crosshairSize, this.fbY / 2 - 1, this.crosshairSize * 2, 2, color);
|
|
}
|
|
else {
|
|
GlState.color(color);
|
|
Drawing.drawTexturedRect(this, "textures/crosshair.png", 32, 32, this.fbX / 2 - 16, this.fbY / 2 - 16, 0, 0, 32, 32);
|
|
}
|
|
}
|
|
}
|
|
|
|
int x = xoff * scale;
|
|
for(int n = 0; n < size; n++) {
|
|
if(this.player.getStackInSlot(n) == null || this.player.getStackInSlot(n).getItem().getCategory() != this.itemSelection)
|
|
continue;
|
|
if(selected == n)
|
|
Drawing.drawRect(x - scale * 2, by - scale * 2, 20 * scale, 20 * scale, 0xffffffff);
|
|
InventoryButton.drawButton(this, x - scale, by - scale, 18 * scale, 18 * scale);
|
|
x += (width >= 20 || selected == n || selected == n + 1 ? 20 : width) * scale;
|
|
}
|
|
|
|
ItemStack itemstack = this.player.getHeldItem();
|
|
String current = itemstack != null && itemstack.getItem().getCategory() != null ? itemstack.getItem().getHotbarText(this.player, itemstack) : "";
|
|
if(!current.isEmpty())
|
|
Drawing.drawTextUpward(current, this.fbX / 2, this.fbY - 60, 0xffffffff);
|
|
}
|
|
|
|
int x = this.fbX / 2;
|
|
int y = 0;
|
|
Iterator<Entry<Integer, Long>> iter = this.bars.entrySet().iterator();
|
|
long now = System.currentTimeMillis();
|
|
while(iter.hasNext()) {
|
|
Entry<Integer, Long> status = iter.next();
|
|
Entity ent;
|
|
if(this.player != null && now - status.getValue() < 10000L && (ent = this.player.worldObj.getEntityByID(status.getKey())) instanceof EntityLiving) {
|
|
EntityLiving entity = (EntityLiving)ent;
|
|
String s = entity.getName() + Color.GRAY + " [" +
|
|
EntityLiving.getHealthColor(entity.getHealth(), entity.getMaxHealth()) +
|
|
entity.getHealth() + Color.GRAY + " / " + EntityLiving.getMaxHpColor(entity.getMaxHealth()) +
|
|
entity.getMaxHealth() + Color.GRAY + "]";
|
|
Drawing.drawTextboxCentered(s, x, y, 0x3f000000);
|
|
Drawing.drawRectBorder(x - 200, y + 20, 400, 10, 0xff000000, 0xff202020, 0xffcfcfcf, 0xff6f6f6f);
|
|
Drawing.drawGradient(x - 200 + 2, y + 20 + 2, (int)(396.0f * ((float)entity.getHealth() / (float)entity.getMaxHealth())), 6, entity.getColor() | 0xff000000, Util.mixColor(entity.getColor() | 0xff000000, 0xff000000));
|
|
y += 40;
|
|
}
|
|
else {
|
|
iter.remove();
|
|
}
|
|
}
|
|
|
|
if(!this.drawDebug || this.open != null) {
|
|
x = this.hudMargin;
|
|
y = this.hudMargin;
|
|
for(StatusEffect effect : this.player.getEffects()) {
|
|
Effect potion = effect.getPotion();
|
|
int color = potion.getColor();
|
|
String name = (potion.isBadEffect() ? Color.ORANGE : Color.ACID) + effect.getEffectName();
|
|
String desc = Color.NEON + effect.getDurationString();
|
|
Drawing.drawRectBorder(x, y, 250, Font.HEIGHT + 6, 0xff000000, 0xff202020, 0xffcfcfcf, 0xff6f6f6f);
|
|
Drawing.drawGradient(x + 2, y + 2, effect.isInfinite() ? 246 : ((int)(246.0f * ((float)effect.getRemaining() / (float)effect.getDuration()))), Font.HEIGHT + 2, color | 0xff000000, Util.mixColor(color | 0xff000000, 0xff000000));
|
|
Drawing.drawText(name, x + 4, y + 3, 0xffffffff);
|
|
Drawing.drawTextRight(desc, x + 250 - 4, y + 3, 0xffffffff);
|
|
y += 24;
|
|
}
|
|
}
|
|
|
|
EntityNPC entity = this.player;
|
|
int absorb = entity.getAbsorptionAmount();
|
|
int armor = entity.getTotalArmorValue();
|
|
int stats = 1 + (absorb > 0 ? 1 : 0) + (armor > 0 ? 1 : 0) + (entity.vehicle instanceof EntityLiving ? 1 : 0)
|
|
+ (entity.getManaPoints() > 0 ? 1 : 0) + (entity instanceof EntityWaterNPC ? 1 : 0);
|
|
for(Energy energy : Energy.values()) {
|
|
if(entity.getEnergy(energy) > 0)
|
|
stats += 1;
|
|
}
|
|
x = this.fbX - this.hudMargin - 250;
|
|
y = this.fbY - this.hudMargin - 14 - 24 - stats * 40;
|
|
int hp = entity.getHealth();
|
|
int max = entity.getMaxHealth();
|
|
y = this.drawStat(x, y, Color.RED + "Schaden", hp, max, 0xff0000);
|
|
if(absorb > 0)
|
|
y = this.drawStat(x, y, Color.YELLOW + "Schadenspuffer", absorb, 1024, 0xffff00);
|
|
if(entity instanceof EntityWaterNPC npc) {
|
|
int moist = npc.getMoisture();
|
|
int maxm = npc.getMaxMoisture();
|
|
y = this.drawStat(x, y, Color.BLUE + "Feuchtigkeit", moist, maxm, 0x4f4fff);
|
|
}
|
|
if(armor > 0)
|
|
y = this.drawStat(x, y, Color.GRAY + "Rüstung", armor, 1024, 0x707070);
|
|
if(entity.vehicle instanceof EntityLiving living) {
|
|
int vh = living.getHealth();
|
|
int vhMax = living.getMaxHealth();
|
|
y = this.drawStat(x, y, living.getLabel(), vh, vhMax, 0xff6060);
|
|
}
|
|
if(entity.getManaPoints() > 0) {
|
|
int mana = entity.getManaPoints();
|
|
int maxm = entity.getMaxMana();
|
|
y = this.drawStat(x, y, Color.CYAN + "Mana", mana, maxm, 0x0000ff);
|
|
}
|
|
for(int z = 0; z < Energy.values().length; z++) {
|
|
Energy type = Energy.values()[z];
|
|
int energy = entity.getEnergy(type);
|
|
if(energy > 0) {
|
|
int emax = entity.getEnergyCap(type);
|
|
y = this.drawStat(x, y, Color.LIGHT_GRAY + type.display, energy, emax, entity.hasEnergyEffect(type) ? type.effect : type.color);
|
|
}
|
|
}
|
|
|
|
x = this.hudMargin;
|
|
y = this.fbY - this.hudMargin - 14 - 24 - (this.player.isRidingHorse() && this.player.getHorseJumpPower() != 0.0f ? 2 : 1) * 40;
|
|
if(this.player.isRidingHorse() && this.player.getHorseJumpPower() != 0.0f) // {
|
|
y = this.drawBar(x, y, String.format(Color.NEON + "Sprungkraft: " + Color.CYAN + "%d %%", (int)(this.player.getHorseJumpPower() * 100.0f)),
|
|
this.player.getHorseJumpPower(), 0x4040ff);
|
|
y = this.drawBar(x, y, String.format(Color.ACID + "EXP: " + Color.GREEN + "Level %d, %d/%d", this.player.experienceLevel, (int)((float)this.player.xpBarCap() * this.player.experience), this.player.xpBarCap()), this.player.experience, 0x40ff40);
|
|
}
|
|
|
|
if(this.infoOverlay && this.world != null && this.open == null && this.player != null && this.viewEntity == this.player) {
|
|
String desc = null;
|
|
String line1 = null;
|
|
String line2 = null;
|
|
int color = 0x000000;
|
|
float bar = -1.0f;
|
|
if((this.pointed != null && this.pointed.type == ObjectType.BLOCK && this.pointed.block != null) || this.pointedLiquid != null) {
|
|
LocalPos pos = this.pointedLiquid != null ? this.pointedLiquid : this.pointed.block;
|
|
State state = this.world.getState(pos);
|
|
Block block = state.getBlock();
|
|
if(this.pointedLiquid != null ? block.getMaterial().isLiquid() : block != Blocks.air) {
|
|
desc = block.getDisplay();
|
|
line1 = block.getInfo(this.world, pos, state, this.player);
|
|
boolean toolReq = block.getMaterial().isToolRequired();
|
|
boolean harvestable = this.player.canHarvestBlock(block);
|
|
line2 = Color.BLUE + "Werkzeug" + Color.DARK_GRAY + ": " + (block.getMiningTool() != null ? (toolReq ? (harvestable ? Color.GREEN : Color.RED) : Color.LIGHT_GRAY) + block.getMiningTool().getDisplay() + (block.getMiningTool().isLevelled() ? (toolReq ? (harvestable ? Color.ORK : Color.CRIMSON) : Color.DARK_GRAY) + " Level " + (toolReq ? (harvestable ? Color.DARK_GREEN : Color.DARK_RED) : Color.GRAY) + (block.getMiningLevel() + 1) : "") : Color.GRAY + "Keins");
|
|
if(this.controller.isHittingBlock()) {
|
|
bar = 1.0f - this.controller.getDamage(pos);
|
|
color = (int)(bar * 255.0f) << 8 | (int)((1.0f - bar) * 255.0f) << 16;
|
|
}
|
|
}
|
|
}
|
|
else if(this.pointed != null && this.pointed.type == ObjectType.ENTITY && this.pointed.entity != null) {
|
|
Entity entity = this.pointed.entity;
|
|
desc = (entity instanceof EntityNPC npc ? (!npc.canCounter(this.player) ? Color.GREEN : (npc.canAttack(this.player) ? Color.RED : Color.BLUE)) : Color.LIGHT_GRAY) + entity.getRawName();
|
|
line1 = entity.getInfo(this.player);
|
|
line2 = Color.CYAN + EntityRegistry.getEntityName(EntityRegistry.getEntityString(entity));
|
|
if(entity instanceof EntityLiving living) {
|
|
bar = (float)living.getHealth() / (float)living.getMaxHealth();
|
|
color = living.getColor();
|
|
}
|
|
}
|
|
if(desc != null) {
|
|
Drawing.drawRectBorder(this.fbX / 2 - 180, this.hudMargin, 360, 60, 0xff6f6f6f, 0xff000000, 0xffafafaf, 0xff4f4f4f);
|
|
Drawing.drawTextCentered(desc, this.fbX / 2, this.hudMargin + 4, 0xffffffff);
|
|
if(line1 != null)
|
|
Drawing.drawTextCentered(line1, this.fbX / 2, this.hudMargin + 60 - 4 - Font.HEIGHT * 2 - 2, 0xffffffff);
|
|
if(line2 != null)
|
|
Drawing.drawTextCentered(line2, this.fbX / 2, this.hudMargin + 60 - 4 - Font.HEIGHT, 0xffffffff);
|
|
if(bar >= 0.0f) {
|
|
Drawing.drawRect(this.fbX / 2 - 140, this.hudMargin + 4 + Font.HEIGHT + 2, 280, 6, 0xff202020, 0xffcfcfcf, 0xff3f3f3f);
|
|
Drawing.drawGradient(this.fbX / 2 - 140 + 1, this.hudMargin + 4 + Font.HEIGHT + 2 + 1, (int)(278.0f * bar), 4, color | 0xff000000, Util.mixColor(color | 0xff000000, 0xff000000));
|
|
}
|
|
}
|
|
}
|
|
|
|
GlState.bindTexture(0);
|
|
GlState.setActiveTexture(GL15.GL_TEXTURE0);
|
|
GlState.enableTexture2D();
|
|
if(this.world != null && this.open == null && this.player != null && this.viewEntity == this.player) {
|
|
GlState.enableRescaleNormal();
|
|
GlState.enableBlend();
|
|
GlState.color(1.0F, 1.0F, 1.0F, 1.0F);
|
|
ItemRenderer.enableGUIStandardItemLighting();
|
|
GL15.glPushMatrix();
|
|
GL15.glTranslatef(0.0f, (float)by, 0.0f);
|
|
GL15.glScalef(2.0f, 2.0f, 2.0f);
|
|
|
|
int xPos = xoff;
|
|
int cnt = 0;
|
|
for(int index = 0; index < size; ++index) {
|
|
ItemStack itemstack = this.player.getStackInSlot(index);
|
|
if(itemstack != null && itemstack.getItem().getCategory() == this.itemSelection) {
|
|
if(width < 20 && selected != index && selected != index + 1 && cnt != total - 1) {
|
|
this.scissor(xPos * scale, this.fbY - (by + 16 * scale), (width - 1) * scale, 16 * scale);
|
|
GL15.glEnable(GL15.GL_SCISSOR_TEST);
|
|
}
|
|
GlState.enableDepth();
|
|
this.renderItem.renderItemAndEffectIntoGUI(itemstack, xPos, 0);
|
|
if(width < 20 && selected != index && selected != index + 1 && cnt != total - 1)
|
|
GL15.glDisable(GL15.GL_SCISSOR_TEST);
|
|
xPos += width >= 20 || selected == index || selected == index + 1 ? 20 : width;
|
|
++cnt;
|
|
}
|
|
}
|
|
|
|
if(this.infoOverlay) {
|
|
Item item = null;
|
|
if((this.pointed != null && this.pointed.type == ObjectType.BLOCK && this.pointed.block != null) || this.pointedLiquid != null)
|
|
item = this.pointedLiquid != null ? (this.world.getState(this.pointedLiquid).getBlock() instanceof BlockLiquid liquid ? ItemBucket.getByFluid(liquid) : null) : this.world.getState(this.pointed.block).getBlock().getItem();
|
|
else if(this.pointed != null && this.pointed.type == ObjectType.ENTITY && this.pointed.entity != null)
|
|
item = this.pointed.entity.getItem();
|
|
if(item != null) {
|
|
GL15.glPopMatrix();
|
|
GL15.glPushMatrix();
|
|
GL15.glTranslatef((float)(this.fbX / 2 - 180 + 4 + 1), (float)(this.hudMargin + 20 + 1), 0.0f);
|
|
GL15.glScalef(2.0f, 2.0f, 2.0f);
|
|
GlState.enableDepth();
|
|
this.renderItem.renderItemAndEffectIntoGUI(new ItemStack(item), 0, 0);
|
|
}
|
|
}
|
|
|
|
GL15.glPopMatrix();
|
|
ItemRenderer.disableStandardItemLighting();
|
|
GlState.disableRescaleNormal();
|
|
GlState.disableBlend();
|
|
}
|
|
|
|
GlState.disableTexture2D();
|
|
GlState.disableCull();
|
|
GlState.enableBlend();
|
|
GlState.disableDepth();
|
|
if(this.world != null && this.open == null && this.player != null && this.viewEntity == this.player) {
|
|
int xPos = xoff * scale;
|
|
for(int index = 0; index < size; ++index) {
|
|
ItemStack itemstack = this.player.getStackInSlot(index);
|
|
if(itemstack != null && itemstack.getItem().getCategory() == this.itemSelection) {
|
|
if(width >= 17 || index == selected) {
|
|
GuiContainer.renderItemOverlay(itemstack,
|
|
xPos, by, null, index == this.player.getSelectedIndex() ? this.controller.getUseCooldown() : 0, this.controller.getUseCooldownMax());
|
|
}
|
|
xPos += (width >= 20 || selected == index || selected == index + 1 ? 20 : width) * scale;
|
|
}
|
|
}
|
|
}
|
|
if(this.open != null)
|
|
this.open.render();
|
|
else if(this.world == null || this.charEditor)
|
|
Drawing.drawScaled(this, Gui.BACKGROUND);
|
|
if(Bind.INFO.isDown() && (this.open == null || !(this.open.selected instanceof client.gui.element.Field || this.open.selected instanceof Area)))
|
|
this.drawInfo();
|
|
if(this.hudOverlay && !(this.open instanceof GuiConsole)) {
|
|
this.drawOverlay(this.feed, this.feedSize, false, 1, 0, 0);
|
|
this.drawOverlay(this.console, this.consoleSize, true, 1, 0, this.fbY);
|
|
this.drawOverlay(this.hotbar, this.hotbarSize, true, 0, this.fbX / 2, this.fbY - 120);
|
|
this.drawOverlay(this.chat, this.chatSize, true, -1, this.fbX, this.fbY);
|
|
}
|
|
if(this.drawFps) {
|
|
if(this.drawDebug) {
|
|
if(this.open == null) {
|
|
this.renderStats();
|
|
this.renderLagometer();
|
|
}
|
|
else {
|
|
Drawing.drawText(String.format("%s%.2f" + Color.RESET + " %s [%s" + Color.RESET + "], %.3f ms, W %d x %d%s",
|
|
this.framecode(), this.framerate < 1.0f ? 1.0f / this.framerate : this.framerate, this.framerate < 1.0f ? "SPF" : "FPS",
|
|
this.vsync ? Color.DARK_GRAY + "VSYNC" : (this.syncLimited ? Color.GREEN + "" + this.syncLimit : Color.RED + "UNL"),
|
|
(float)PerfSection.getTotal(false) / 1000.0f, this.fbRawX, this.fbRawY,
|
|
this.fullscreen ? " @ " + (this.vidMode == null ? "?" : this.vidMode.refresh()) + " Hz" : ""),
|
|
0, 0, 0xffffffff);
|
|
}
|
|
}
|
|
else {
|
|
Drawing.drawText(String.format("%s%.2f", framecode(), this.framerate), 0, 0, 0xffffffff);
|
|
}
|
|
}
|
|
GlState.enableBlend();
|
|
}
|
|
|
|
public void renderStats() {
|
|
int offset = 5;
|
|
int x1 = this.fbX - 320;
|
|
int y1 = 0;
|
|
int y2 = this.fbY;
|
|
String str = this.getLeft();
|
|
offset += str != null ? 18 : 0;
|
|
String draw = String.format(
|
|
"OpenGL: %s\n" +
|
|
"Renderer: %s (%s)\n" +
|
|
"Bildrate: %s%.2f" + Color.RESET + " %s [%s" + Color.RESET + "], %.3f ms, W %d x %d%s\n" +
|
|
"Tickrate: %s%.2f" + Color.RESET + " %s [" + Color.GREEN + "%.1f" + Color.RESET + "], %.3f ms, E %d ms" +
|
|
"%s%s"
|
|
,
|
|
GL15.glGetString(GL15.GL_VERSION),
|
|
GL15.glGetString(GL15.GL_RENDERER), GL15.glGetString(GL15.GL_VENDOR),
|
|
this.framecode(), this.framerate < 1.0f ? 1.0f / this.framerate : this.framerate, this.framerate < 1.0f ? "SPF" : "FPS",
|
|
this.vsync ? Color.DARK_GRAY + "VSYNC" : (this.syncLimited ? Color.GREEN + "" + this.syncLimit : Color.RED + "UNL"),
|
|
(float)PerfSection.getTotal(false) / 1000.0f, this.fbRawX, this.fbRawY,
|
|
this.fullscreen ? " @ " + (this.vidMode == null ? "?" : this.vidMode.refresh()) + " Hz" : "",
|
|
this.tpscode(), this.tickrate < 1.0f ? 1.0f / this.tickrate : this.tickrate,
|
|
this.tickrate < 1.0f ? "SPT" : "TPS", (float)this.tickTarget / 1000.0f,
|
|
(float)this.tick_time / 1000.0f, this.tickTimeout,
|
|
str != null ? "\n" : "", str != null ? str : ""
|
|
);
|
|
Drawing.drawText(draw, 0, 0, 0xffffffff);
|
|
|
|
str = this.getRight(this.debugPlayer);
|
|
StringBuilder sb = new StringBuilder();
|
|
for(PerfSection perf : PerfSection.values()) {
|
|
if(sb.length() > 0)
|
|
sb.append('\n');
|
|
sb.append(perf.getName());
|
|
}
|
|
Drawing.drawText(sb.toString(), x1 + 0, y1, 0xffffffff);
|
|
sb.setLength(0);
|
|
for(PerfSection perf : PerfSection.values()) {
|
|
if(sb.length() > 0)
|
|
sb.append('\n');
|
|
sb.append(String.format("%.3f ms", (float)perf.getLast() / 1000.0f));
|
|
}
|
|
Drawing.drawText(sb.toString(), x1 + 120, y1, 0xffffffff);
|
|
sb.setLength(0);
|
|
long total = PerfSection.getTotal(true);
|
|
for(PerfSection perf : PerfSection.values()) {
|
|
if(sb.length() > 0)
|
|
sb.append('\n');
|
|
sb.append(String.format("%.2f %%", ((float)perf.getLast() / (float)total) * 100.0f));
|
|
}
|
|
Drawing.drawText(sb.toString(), x1 + 240, y1, 0xffffffff);
|
|
if(str != null) {
|
|
y1 = Font.HEIGHT * 10;
|
|
Drawing.drawText(str, x1, y1, 0xffffffff);
|
|
}
|
|
}
|
|
|
|
public void finish() {
|
|
if(this.screenshot) {
|
|
this.screenshot = false;
|
|
screenshot();
|
|
}
|
|
if(this.cameraUsed) {
|
|
this.cameraUsed = false;
|
|
if(this.world != null)
|
|
this.renderer.setLastLightning(1, 0xffffff);
|
|
}
|
|
if(this.isDirty())
|
|
this.save();
|
|
Thread.yield();
|
|
while(System.currentTimeMillis() >= this.debugUpdateTime + 1000L) {
|
|
this.chunksUpdated = RenderChunk.renderChunksUpdated;
|
|
RenderChunk.renderChunksUpdated = 0;
|
|
this.debugUpdateTime += 1000L;
|
|
}
|
|
}
|
|
|
|
public void scroll(int dir) {
|
|
if(this.zooming)
|
|
this.zoomLevel = ExtMath.clampf(this.zoomLevel + (dir < 0 ? -0.25f : 0.25f), this.viewEntity != this.player ? 1.0f : 2.0f, 16.0f);
|
|
else if(this.player != null)
|
|
this.select(-dir);
|
|
}
|
|
|
|
private void select(int dir) {
|
|
int last = this.player.getSelectedIndex();
|
|
int n = 0;
|
|
if(last < 0) {
|
|
last = 0;
|
|
this.player.setSelectedIndex(0);
|
|
}
|
|
boolean any = false;
|
|
do {
|
|
this.player.setSelectedIndex(this.player.getSelectedIndex() + dir);
|
|
if(this.player.getSelectedIndex() < 0)
|
|
this.player.setSelectedIndex(this.player.getHotbarSize() - 1);
|
|
else if(this.player.getSelectedIndex() >= this.player.getHotbarSize())
|
|
this.player.setSelectedIndex(0);
|
|
any |= this.player.getHeldItem() != null && this.player.getHeldItem().getItem().getCategory() == this.itemSelection;
|
|
++n;
|
|
}
|
|
while((this.player.getHeldItem() == null || this.player.getHeldItem().getItem().getCategory() != this.itemSelection) && n < this.player.getHotbarSize());
|
|
if(last != this.player.getSelectedIndex())
|
|
this.controller.resetUseCooldown();
|
|
else if(!any)
|
|
this.category(dir);
|
|
}
|
|
|
|
private void category(int dir) {
|
|
ItemCategory last = this.itemSelection;
|
|
this.lastSelection[last.ordinal()] = this.player.getSelectedIndex() >= 0 ? this.player.getSelectedIndex() : 0;
|
|
int total;
|
|
int n = 0;
|
|
boolean any = false;
|
|
do {
|
|
this.itemSelection = ItemCategory.values()[(ItemCategory.values().length + this.itemSelection.ordinal() + dir) % ItemCategory.values().length];
|
|
total = 0;
|
|
for(int z = 0; z < this.player.getHotbarSize(); z++) {
|
|
if(this.player.getStackInSlot(z) != null && this.player.getStackInSlot(z).getItem().getCategory() == this.itemSelection)
|
|
++total;
|
|
}
|
|
any |= total > 0;
|
|
++n;
|
|
}
|
|
while(total <= 0 && n < ItemCategory.values().length);
|
|
if(this.itemSelection != last) {
|
|
if(this.player.getSelectedIndex() != this.lastSelection[this.itemSelection.ordinal()])
|
|
this.controller.resetUseCooldown();
|
|
this.player.setSelectedIndex(Math.min(this.lastSelection[this.itemSelection.ordinal()], this.player.getHotbarSize() - 1));
|
|
}
|
|
else if(!any) {
|
|
this.player.setSelectedIndex(-1);
|
|
}
|
|
}
|
|
|
|
public void moveCamera(float x, float y) {
|
|
this.deltaX += x;
|
|
this.deltaY += y;
|
|
}
|
|
|
|
public void show(Gui gui)
|
|
{
|
|
if(!this.refreshing)
|
|
this.waitingForFile = false;
|
|
if(this.player != null) {
|
|
if(this.getNetHandler() != null)
|
|
this.getNetHandler().addToSendQueue(new CPacketAction(CPacketAction.Action.CLOSE_CONTAINER, this.player.openContainer.windowId));
|
|
this.player.setMouseItem(null);
|
|
this.player.openContainer = this.player.inventoryContainer;
|
|
}
|
|
if (this.open != null)
|
|
{
|
|
this.open.onGuiClosed();
|
|
}
|
|
if (gui == null && this.world != null && this.player.getHealth() <= 0)
|
|
{
|
|
gui = GuiGameOver.INSTANCE;
|
|
}
|
|
|
|
this.open = gui;
|
|
if (gui != null)
|
|
{
|
|
this.menu(true);
|
|
gui.init();
|
|
Window.setTitle(String.format("%s - %s", VERSION, gui.getTitle()));
|
|
}
|
|
else
|
|
{
|
|
this.menu(false);
|
|
this.leftClickCounter = 10000;
|
|
Bind.disableMouse();
|
|
Window.setTitle(String.format("%s - %s%s", VERSION, "Welt / Render", this.nograb ? "" : " (Maus gefangen)"));
|
|
}
|
|
}
|
|
|
|
private void sendClickBlockToController(boolean leftClick)
|
|
{
|
|
if (!leftClick)
|
|
{
|
|
this.leftClickCounter = 0;
|
|
this.controller.resetInteraction();
|
|
}
|
|
|
|
if (this.leftClickCounter <= 0 && !this.player.isUsingItem())
|
|
{
|
|
if (leftClick && this.pointed != null && this.pointed.type == HitPosition.ObjectType.BLOCK)
|
|
{
|
|
LocalPos blockpos = this.pointed.block;
|
|
|
|
if (this.world.getState(blockpos).getBlock() != Blocks.air && this.controller.damageBlock(blockpos, this.pointed.side))
|
|
{
|
|
this.effectRenderer.damageBlock(blockpos, this.pointed.side);
|
|
this.player.swingItem();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
this.controller.resetProgress();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void primary()
|
|
{
|
|
if (this.leftClickCounter <= 0)
|
|
{
|
|
if (this.pointed == null)
|
|
{
|
|
this.player.swingItem();
|
|
Log.TICK.warn("Null zurückgegeben als 'hitResult', das sollte niemals passieren!");
|
|
this.leftClickCounter = 10;
|
|
}
|
|
else
|
|
{
|
|
ItemStack itemstack = this.player.getHeldItem();
|
|
if ((this.pointed.type != ObjectType.BLOCK || this.world.getState(this.pointed.block).getBlock() == Blocks.air) && itemstack != null && itemstack.getItem().onAction(itemstack, this.player, this.world, ItemControl.PRIMARY, null))
|
|
{
|
|
this.player.swingItem();
|
|
this.player.client.addToSendQueue(new CPacketAction(Action.ITEM_ACTION, ItemControl.PRIMARY.ordinal()));
|
|
if(this.player.getHeldItem() != null && this.player.getHeldItem().isEmpty())
|
|
this.player.clearHeldItem();
|
|
this.leftClickCounter = 10;
|
|
return;
|
|
}
|
|
|
|
switch (this.pointed.type)
|
|
{
|
|
case ENTITY:
|
|
this.player.swingItem();
|
|
this.controller.attackEntity(this.player, this.pointed.entity);
|
|
break;
|
|
case BLOCK:
|
|
this.player.swingItem();
|
|
LocalPos blockpos = this.pointed.block;
|
|
if (this.world.getState(blockpos).getBlock() != Blocks.air)
|
|
{
|
|
this.controller.clickBlock(blockpos, this.pointed.side);
|
|
break;
|
|
}
|
|
this.leftClickCounter = 10;
|
|
break;
|
|
case MISS:
|
|
default:
|
|
this.player.swingItem();
|
|
this.leftClickCounter = 10;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void secondary()
|
|
{
|
|
if (!this.controller.isHittingBlock())
|
|
{
|
|
this.rightClickTimer = 4;
|
|
boolean flag = true;
|
|
ItemStack itemstack = this.player.getHeldItem();
|
|
|
|
if (itemstack != null && itemstack.getItem() == Items.camera && !this.saving)
|
|
{
|
|
this.screenshot = this.cameraUsed = true;
|
|
}
|
|
|
|
if (this.pointed == null)
|
|
{
|
|
Log.TICK.warn("Null zurückgegeben als 'hitResult', das sollte niemals passieren!");
|
|
}
|
|
else
|
|
{
|
|
if ((this.pointed.type != ObjectType.BLOCK || this.world.getState(this.pointed.block).getBlock() == Blocks.air) && itemstack != null && itemstack.getItem().onAction(itemstack, this.player, this.world, ItemControl.SECONDARY, null))
|
|
{
|
|
this.player.swingItem();
|
|
this.player.client.addToSendQueue(new CPacketAction(Action.ITEM_ACTION, ItemControl.SECONDARY.ordinal()));
|
|
if(this.player.getHeldItem() != null && this.player.getHeldItem().isEmpty())
|
|
this.player.clearHeldItem();
|
|
return;
|
|
}
|
|
|
|
switch (this.pointed.type)
|
|
{
|
|
case ENTITY:
|
|
if (this.controller.interact(this.player, this.pointed.entity))
|
|
{
|
|
flag = false;
|
|
}
|
|
|
|
break;
|
|
|
|
case BLOCK:
|
|
LocalPos blockpos = this.pointed.block;
|
|
|
|
if (this.world.getState(blockpos).getBlock() != Blocks.air)
|
|
{
|
|
int i = itemstack != null ? itemstack.getSize() : 0;
|
|
|
|
if (this.controller.clickRight(this.player, this.world, itemstack, blockpos, this.pointed.side, this.pointed.vec))
|
|
{
|
|
flag = false;
|
|
this.player.swingItem();
|
|
}
|
|
|
|
if (itemstack == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (itemstack.isEmpty())
|
|
{
|
|
this.player.clearHeldItem();
|
|
}
|
|
else if (itemstack.getSize() != i)
|
|
{
|
|
this.itemRenderer.resetProgress();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (flag)
|
|
{
|
|
ItemStack itemstack1 = this.player.getHeldItem();
|
|
|
|
if (itemstack1 != null && this.controller.sendUseItem(this.player, this.world, itemstack1))
|
|
{
|
|
this.itemRenderer.resetProgress();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void tertiary()
|
|
{
|
|
if (this.pointed != null)
|
|
{
|
|
if(this.player.getHeldItem() != null && this.player.getHeldItem().getItem().onAction(this.player.getHeldItem(), this.player, this.world, ItemControl.TERTIARY, null)) {
|
|
this.player.client.addToSendQueue(new CPacketAction(Action.ITEM_ACTION, ItemControl.TERTIARY.ordinal()));
|
|
if(this.player.getHeldItem() != null && this.player.getHeldItem().isEmpty())
|
|
this.player.clearHeldItem();
|
|
return;
|
|
}
|
|
|
|
Item item = null;
|
|
if (this.pointed.type == HitPosition.ObjectType.BLOCK)
|
|
item = this.world.getState(this.pointed.block).getBlock().getItem();
|
|
else if (this.pointed.type == HitPosition.ObjectType.ENTITY && this.pointed.entity != null && this.itemCheat)
|
|
item = this.pointed.entity.getItem();
|
|
if(item == null)
|
|
return;
|
|
|
|
int idx = this.player.getInventorySlotContainItem(item);
|
|
if(idx >= 0 && idx < this.player.getHotbarSize()) {
|
|
this.player.setSelectedIndex(idx);
|
|
this.controller.resetUseCooldown();
|
|
}
|
|
if(this.itemCheat && this.player.getSelectedIndex() >= 0) {
|
|
this.player.client.addToSendQueue(new CPacketCheat(item, -2 - this.player.getSelectedIndex(), this.ctrl()));
|
|
}
|
|
}
|
|
}
|
|
|
|
private void quarternary()
|
|
{
|
|
if (this.pointed != null)
|
|
{
|
|
if(this.player.getHeldItem() != null && this.player.getHeldItem().getItem().onAction(this.player.getHeldItem(), this.player, this.world, ItemControl.QUARTERNARY, null)) {
|
|
this.player.client.addToSendQueue(new CPacketAction(Action.ITEM_ACTION, ItemControl.QUARTERNARY.ordinal()));
|
|
if(this.player.getHeldItem() != null && this.player.getHeldItem().isEmpty())
|
|
this.player.clearHeldItem();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
public World loadWorld(Dimension dim, int type)
|
|
{
|
|
this.worldLight = false;
|
|
this.resetWorld();
|
|
this.viewEntity = null;
|
|
this.freecam = this.servercam = false;
|
|
this.connection = null;
|
|
this.soundManager.stopSounds();
|
|
this.world = new WorldClient(dim);
|
|
this.entities = this.world.entities;
|
|
this.unloaded = this.world.unloaded;
|
|
this.tiles = this.world.tiles;
|
|
this.entityIds = this.world.entityIds;
|
|
this.initWorld();
|
|
this.worldLight = true;
|
|
|
|
this.renderer.setWorldAndLoadRenderers(this.world);
|
|
|
|
if (this.effectRenderer != null)
|
|
{
|
|
this.effectRenderer.setWorld(this.world);
|
|
}
|
|
|
|
if (this.player == null)
|
|
{
|
|
this.player = this.controller.createPlayerEntity(this.world, type);
|
|
this.player.rotYaw = -180.0F;
|
|
}
|
|
|
|
this.player.preparePlayerToSpawn();
|
|
this.spawnEntity(this.player);
|
|
this.viewEntity = this.player;
|
|
|
|
System.gc();
|
|
return this.world;
|
|
}
|
|
|
|
public void setDimensionAndSpawnPlayer(int type)
|
|
{
|
|
this.removeAllEntities();
|
|
int i = 0;
|
|
|
|
if (this.player != null)
|
|
{
|
|
i = this.player.getId();
|
|
this.world.removeEntity(this.player);
|
|
this.entityList.remove(this.player);
|
|
}
|
|
|
|
this.viewEntity = null;
|
|
EntityNPC entityplayersp = this.player;
|
|
this.player = this.controller.createPlayerEntity(this.world, type);
|
|
this.player.getDataWatcher().updateWatchedObjectsFromList(entityplayersp.getDataWatcher().getAllWatched());
|
|
this.viewEntity = this.player;
|
|
this.freecam = this.servercam = false;
|
|
this.player.preparePlayerToSpawn();
|
|
this.spawnEntity(this.player);
|
|
this.player.rotYaw = -180.0F;
|
|
this.player.setId(i);
|
|
}
|
|
|
|
public ClientPlayer getNetHandler()
|
|
{
|
|
return this.player != null ? (ClientPlayer)this.player.client : null;
|
|
}
|
|
|
|
public TextureManager getTextureManager()
|
|
{
|
|
return this.textureManager;
|
|
}
|
|
|
|
public TextureMap getTextureMapBlocks()
|
|
{
|
|
return this.textureMap;
|
|
}
|
|
|
|
public SoundManager getSoundManager()
|
|
{
|
|
return this.soundManager;
|
|
}
|
|
|
|
public void performAction(Action action) {
|
|
if(this.player != null)
|
|
this.player.client.addToSendQueue(new CPacketAction(action));
|
|
}
|
|
|
|
public void performAction(Action action, int data) {
|
|
if(this.player != null)
|
|
this.player.client.addToSendQueue(new CPacketAction(action, data));
|
|
}
|
|
|
|
public void setBossStatus(EntityLiving entity) {
|
|
if(this.bars.size() < 5 || this.bars.containsKey(entity.getId()))
|
|
this.bars.put(entity.getId(), System.currentTimeMillis());
|
|
}
|
|
|
|
public Entity getRenderViewEntity()
|
|
{
|
|
return this.viewEntity;
|
|
}
|
|
|
|
public Entity getPointedEntity()
|
|
{
|
|
return this.pointedEntity;
|
|
}
|
|
|
|
public void setPointedEntity(Entity entity)
|
|
{
|
|
this.pointedEntity = entity;
|
|
}
|
|
|
|
public void setRenderViewEntity(Entity viewingEntity)
|
|
{
|
|
this.viewEntity = viewingEntity;
|
|
this.freecam = false;
|
|
this.servercam = viewingEntity != this.player;
|
|
}
|
|
|
|
public void schedule(Runnable task) {
|
|
if(!this.isMainThread()) {
|
|
synchronized(this.tasks) {
|
|
this.tasks.add(task);
|
|
}
|
|
}
|
|
else {
|
|
try {
|
|
task.run();
|
|
}
|
|
catch(Throwable e) {
|
|
Log.SYSTEM.error(e, "Fehler beim sofortigen Ausführen von Render-Task " + task);
|
|
}
|
|
}
|
|
}
|
|
|
|
public boolean isMainThread()
|
|
{
|
|
return Thread.currentThread() == this.thread;
|
|
}
|
|
|
|
public RenderManager getRenderManager()
|
|
{
|
|
return this.renderManager;
|
|
}
|
|
|
|
public RenderItem getRenderItem()
|
|
{
|
|
return this.renderItem;
|
|
}
|
|
|
|
public ItemRenderer getItemRenderer()
|
|
{
|
|
return this.itemRenderer;
|
|
}
|
|
|
|
public void setTicked(String info) {
|
|
this.lastTicked = System.currentTimeMillis();
|
|
this.serverInfo = info;
|
|
}
|
|
|
|
public void setLastTick(int time) {
|
|
if(this.lastTickTime >= 0) {
|
|
this.lastTicked = System.currentTimeMillis();
|
|
this.lastTickTime = time;
|
|
}
|
|
}
|
|
|
|
public void updatePlayerMoveState()
|
|
{
|
|
this.moveStrafe = 0.0F;
|
|
this.moveForward = 0.0F;
|
|
|
|
if (this.open == null && Bind.FORWARD.isDown())
|
|
{
|
|
++this.moveForward;
|
|
}
|
|
|
|
if (this.open == null && Bind.BACKWARD.isDown())
|
|
{
|
|
--this.moveForward;
|
|
}
|
|
|
|
if (this.open == null && Bind.LEFT.isDown())
|
|
{
|
|
++this.moveStrafe;
|
|
}
|
|
|
|
if (this.open == null && Bind.RIGHT.isDown())
|
|
{
|
|
--this.moveStrafe;
|
|
}
|
|
|
|
this.jump = this.open == null && Bind.UP.isDown();
|
|
this.sneak = this.open == null && Bind.DOWN.isDown();
|
|
this.sprint = this.open == null && Bind.FAST.isDown();
|
|
|
|
if (this.sneak)
|
|
{
|
|
this.moveStrafe = (float)((double)this.moveStrafe * 0.3D);
|
|
this.moveForward = (float)((double)this.moveForward * 0.3D);
|
|
}
|
|
|
|
if(this.viewEntity instanceof EntityCamera camera) {
|
|
camera.onUpdate();
|
|
camera.setMovement(this.moveStrafe, this.moveForward, this.jump, this.sneak);
|
|
if(!this.freecam && this.servercam) {
|
|
this.getNetHandler().addToSendQueue(new CPacketInput(this.moveStrafe, this.moveForward, this.jump, this.sneak, true));
|
|
this.getNetHandler().addToSendQueue(new CPacketPlayerPosLook(camera.posX, camera.posY, camera.posZ, camera.rotYaw, camera.rotPitch, this.sprint).setCamera());
|
|
if(this.player != null)
|
|
this.player.setPositionAndRotation(camera.posX, camera.posY, camera.posZ, camera.rotYaw, camera.rotPitch);
|
|
}
|
|
// if(!camera.fixed && this.sprint)
|
|
// this.viewEntity = this.player;
|
|
}
|
|
}
|
|
|
|
public String getLeft() {
|
|
long maxMem = Runtime.getRuntime().maxMemory();
|
|
long totalMem = Runtime.getRuntime().totalMemory();
|
|
long freeMem = Runtime.getRuntime().freeMemory();
|
|
long usedMem = totalMem - freeMem;
|
|
|
|
String mem = String.format("JVM-Speicher: %d%% %d/%dMB", usedMem * 100L / maxMem, usedMem / 1024L / 1024L, maxMem / 1024L / 1024L)
|
|
+ "\n" +
|
|
String.format("JVM-Reserviert: %d%% %dMB", totalMem * 100L / maxMem, totalMem / 1024L / 1024L);
|
|
if(this.world == null)
|
|
return mem;
|
|
|
|
LocalPos pos = new LocalPos(this.viewEntity.posX, this.viewEntity.getEntityBoundingBox().minY, this.viewEntity.posZ);
|
|
String dirStr;
|
|
switch(this.viewEntity.getHorizontalFacing()) {
|
|
case NORTH:
|
|
default:
|
|
dirStr = "Norden (Nach negativer Z)";
|
|
break;
|
|
case SOUTH:
|
|
dirStr = "Süden (Nach positiver Z)";
|
|
break;
|
|
case WEST:
|
|
dirStr = "Westen (Nach negativer X)";
|
|
break;
|
|
case EAST:
|
|
dirStr = "Osten (Nach positiver X)";
|
|
break;
|
|
}
|
|
ChunkClient chunk = this.getChunk(pos.getX() >> 4, pos.getZ() >> 4);
|
|
long ticked = System.currentTimeMillis() - this.lastTicked;
|
|
|
|
return
|
|
mem + "\n" +
|
|
// (this.debugWorld ? "Debug-Welt" :
|
|
// (this.isServer() ? "ES: " + this.server.getFolderName() :
|
|
// "MS: " + (
|
|
// this.connected != null ? this.connected : "[???]"))),
|
|
this.renderer.getDebugInfoRenders() + "\n" +
|
|
"Objekte: " + this.entities.size() + ", P: " + this.effectRenderer.getParticleCount() + ", C: " + this.chunkMapping.getNumHashElements() + ", " +
|
|
this.renderer.getDebugInfoEntities() + "\n" +
|
|
String.format("XYZ: %.3f / %.3f / %.3f", this.viewEntity.posX,
|
|
this.viewEntity.getEntityBoundingBox().minY, this.viewEntity.posZ) + "\n" +
|
|
String.format("Block: %d %d %d, R: '%s/%s'", pos.getX(), pos.getY(), pos.getZ(),
|
|
Util.getRegionFolder(pos.getX() >> 4, pos.getZ() >> 4),
|
|
Util.getRegionName(pos.getX() >> 4, pos.getZ() >> 4)) + "\n" +
|
|
String.format("Chunk: %d %d %d + %d %d %d, FOV: %.1f °%s", pos.getX() >> 4, pos.getY() >> 4, pos.getZ() >> 4,
|
|
pos.getX() & 15, pos.getY() & 15, pos.getZ() & 15, this.zooming ?
|
|
(this.fov / this.zoomLevel) : this.fov, this.zooming ?
|
|
String.format(" (Zoom x%.1f)", this.zoomLevel) : "") + "\n" +
|
|
String.format("Richtung: %s (%.1f / %.1f)", dirStr,
|
|
ExtMath.wrapf(this.viewEntity.rotYaw), ExtMath.wrapf(this.viewEntity.rotPitch)) + "\n" +
|
|
String.format("Biom: %.2f K, N: %.2f K, D: %s (%s)", chunk.getTemperature(pos), chunk.getOffset(pos),
|
|
Color.stripCodes(this.world.dimension.getDisplay()),
|
|
this.dimensionName) + "\n" +
|
|
String.format("Licht: %06x", chunk.getLight(pos)) + " (" + (this.world.dimension.hasSkyLight() ? + Renderer.getSkyLightFor(pos.getY()) + " Himmel, " : "")
|
|
+ chunk.getLight(pos) + " Blöcke, " + String.format(
|
|
"%.1f", this.renderer.getSunBrightness(1.0f) * 15.0f) + " Welt), A: " + String.format("%.1f °", this.renderer.getCelestialAngle(1.0f)) + "\n" +
|
|
String.format("Zeit: %s" + (this.world.dimension.hasRotation() ? ", R %d / %d T" : "") + (this.world.dimension.hasOrbit() ? ", U %d / %d T" : ""),
|
|
this.world.formatEpochSimple(),
|
|
this.world.getRotation(),
|
|
this.world.dimension.getRotationalPeriod(),
|
|
this.world.getOrbit(),
|
|
this.world.dimension.getOrbitalPeriod()
|
|
) + "\n" +
|
|
String.format("Laub: %s, T: %.2f K / %.2f °C, %s%s (R %.1f, %.1f)",
|
|
!this.world.dimension.hasSeasons() ? "*" : this.world.getLeavesType().getDisplay(),
|
|
this.world.getTemperatureK(pos), this.world.getTemperatureC(pos),
|
|
this.world.dimension.hasWeather() ? "" : "*", !this.world.dimension.hasWeather() && this.world.getWeather() == Weather.CLEAR ? "" :
|
|
this.world.getWeather().getDisplay(), this.world.getRainStrength(),
|
|
this.world.getDarkness()
|
|
) + "\n" +
|
|
String.format("Zeitfaktor: %dx, Schwerkraft: %.2f m/s²",
|
|
Vars.timeFlow, this.world.getGravity(this.viewEntity) * 10.0
|
|
) + "\n" +
|
|
String.format("Letzte Zeitsynch.: + %d.%d s, Größe: %d .. %d",
|
|
ticked / 1000L, (ticked / 100L) % 10L, -this.world.dimension.getSize(), this.world.dimension.getSize()
|
|
) + "\n" +
|
|
"Startwert: " + this.world.dimension.getSeed() +
|
|
(this.serverInfo != null ? "\n" + this.serverInfo : "")
|
|
;
|
|
}
|
|
|
|
private String formatState(LocalPos pos, String desc) {
|
|
State block = this.world.getState(pos);
|
|
|
|
if(!this.debugWorld) {
|
|
block = block.getBlock().getState(block, this.world, pos);
|
|
}
|
|
|
|
StringBuilder str = new StringBuilder(
|
|
desc + ": " + BlockRegistry.getName(block.getBlock()) + "\n" +
|
|
String.format("Position: %d %d %d", pos.getX(), pos.getY(), pos.getZ())
|
|
);
|
|
for(Entry<Property, Comparable> entry : block.getProperties().entrySet()) {
|
|
str.append("\n" + (block.getBlock().getSavedProperties().contains(entry.getKey()) ? Color.NEON : Color.LIGHT_GRAY) + entry.getKey().getName() + Color.RESET + ": " + (entry.getValue() instanceof Boolean bool ? (bool ? Color.GREEN : Color.RED) + "" + entry.getValue() + Color.RESET : entry.getValue()));
|
|
}
|
|
|
|
return str.toString();
|
|
}
|
|
|
|
public String getRight(boolean showPlayerInfo) {
|
|
if(this.world == null) {
|
|
return null;
|
|
}
|
|
|
|
if(!showPlayerInfo && ((this.pointed != null && this.pointed.type == HitPosition.ObjectType.BLOCK
|
|
&& this.pointed.block != null) || this.pointedLiquid != null)) {
|
|
return (this.pointed != null && this.pointed.type == HitPosition.ObjectType.BLOCK
|
|
&& this.pointed.block != null ? this.formatState(this.pointed.block, "Schaue auf") : "") + (this.pointed != null && this.pointed.type == HitPosition.ObjectType.BLOCK
|
|
&& this.pointed.block != null && this.pointedLiquid != null ? "\n" : "") + (this.pointedLiquid != null ? this.formatState(this.pointedLiquid, "Flüssigkeit") : "");
|
|
}
|
|
else if((this.pointed != null && this.pointed.type == HitPosition.ObjectType.ENTITY && this.pointed.entity != null) || showPlayerInfo) {
|
|
Entity entity = showPlayerInfo ? this.player : this.pointed.entity;
|
|
ItemStack held = entity instanceof EntityNPC && ((EntityNPC)entity).getHeldItem() != null ? ((EntityNPC)entity).getHeldItem() : null;
|
|
|
|
return
|
|
(showPlayerInfo ? "Charakter: " : "Schaue auf: ") + EntityRegistry.getEntityString(entity) + " (" + entity.getId() + ")" + "\n" +
|
|
String.format("Position: %.3f %.3f %.3f", entity.posX, entity.posY, entity.posZ) + "\n" +
|
|
"Geladen: " + entity.ticksExisted + "t" + (entity instanceof EntityLiving ? (", Alter: " + ((EntityLiving)entity).getGrowingAge()) + "t" : "") + "\n" +
|
|
String.format("Größe: %.2fx%.2f, A: %.2f", entity.width, entity.height, entity.getEyeHeight()) + "\n" +
|
|
String.format("Bewegung: %.3f %.3f %.3f", entity.motionX, entity.motionY, entity.motionZ) + "\n" +
|
|
String.format("Drehung: %.1f %.1f, K: %.1f", entity.rotYaw, entity.rotPitch, entity.getRotationYawHead()) + "\n" +
|
|
(entity instanceof EntityLiving
|
|
? String.format("Leben: %d/%d, A: %d", ((EntityLiving)entity).getHealth(), ((EntityLiving)entity).getMaxHealth(),
|
|
((EntityLiving)entity).getAbsorptionAmount()) : "Leben: n/a") + "\n" +
|
|
"Schaden: " + entity.hurtResistance + "t" + (showPlayerInfo ? String.format(", Fallh.: %.3f", entity.fallDistance) : "") + "\n" +
|
|
(entity instanceof EntityLiving ?
|
|
(((EntityLiving)entity).deathTime != 0 ? "Tod: " + ((EntityLiving)entity).deathTime + "t, " : "") + "Rüstung: " + ((EntityLiving)entity).getTotalArmorValue() + ", Pfeile: " + ((EntityLiving)entity).getArrowCountInEntity()
|
|
: "Rüstung: n/a, Pfeile: n/a") + "\n" +
|
|
(held != null ?
|
|
"Gegens.: " + ItemRegistry.getName(held.getItem()) + " x" + held.getSize() : "Gegens.: n/a") + "\n" +
|
|
"Eigens.: " + (entity.dead ? "D" : "") + (entity.noClip ? "N" : "") + (entity.onGround ? "G" : "")
|
|
+ (entity.canBeCollidedWith() ? "C" : "") + (entity.canBePushed() ? "P" : "")
|
|
+ (entity.isBurning() ? "B" : "") + (entity.isPlayer() ? "S" : "")
|
|
+ (entity.isWet() ? "W" : "") + (entity.canAttackWithItem() ? "A" : "")
|
|
+ (entity.passenger != null ? "H" : "") + (entity.vehicle != null ? "R" : "")
|
|
+ (entity.doesEntityNotTriggerPressurePlate() ? "L" : "") + "\n" +
|
|
(entity instanceof EntityLiving living && living.hasCustomName() ? "Name: '" + Color.stripCodes(living.getCustomNameTag()) + "'" : "Name: n/a")
|
|
;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public boolean canRenderHud() {
|
|
return (this.showHud || this.open != null) && !this.cameraUsed;
|
|
}
|
|
|
|
public boolean shift() {
|
|
return Bind.isWindowActive() && (Keysym.LEFT_SHIFT.read() || Keysym.RIGHT_SHIFT.read());
|
|
}
|
|
|
|
public boolean ctrl() {
|
|
return Bind.isWindowActive() && (Keysym.LEFT_CONTROL.read() || Keysym.RIGHT_CONTROL.read());
|
|
}
|
|
|
|
private void fbsize(int x, int y) {
|
|
GL15.glViewport(0, 0, x, y);
|
|
this.fbRawX = x;
|
|
this.fbRawY = y;
|
|
this.rescale();
|
|
if(!this.fullscreen) {
|
|
this.sizeX = x;
|
|
this.sizeY = y;
|
|
}
|
|
}
|
|
|
|
private void pos(int x, int y) {
|
|
if(!this.fullscreen) {
|
|
this.savedX = x;
|
|
this.savedY = y;
|
|
}
|
|
}
|
|
|
|
private void mouse(int x, int y) {
|
|
if(!this.mouseFirst && this.open == null)
|
|
this.moveCamera((float)(x - this.mouseRawX) * this.sensitivity, (float)(this.mouseRawY - y) * this.sensitivity);
|
|
this.mouseRawX = x;
|
|
this.mouseRawY = y;
|
|
this.mouseX = x / this.scale;
|
|
this.mouseY = y / this.scale;
|
|
this.mouseFirst = false;
|
|
if(this.open != null && Bind.isInputEnabled() && Button.isMouseDown() && !ctrl()) {
|
|
this.open.drag(this.mouseX, this.mouseY);
|
|
}
|
|
}
|
|
|
|
private void scroll(int x, int y) {
|
|
x *= -1;
|
|
if(this.open != null && Bind.isInputEnabled()) {
|
|
this.open.scroll(x, y, this.mouseX, this.mouseY, ctrl(), shift());
|
|
}
|
|
else if(this.open != null) {
|
|
if((x != 0) || (y != 0))
|
|
Bind.setBind((x < 0) ? Wheel.SCROLL_LEFT : ((x > 0) ? Wheel.SCROLL_RIGHT : ((y < 0) ? Wheel.SCROLL_DOWN : Wheel.SCROLL_UP)), false);
|
|
}
|
|
else if(Bind.isInputEnabled()) {
|
|
if(y != 0)
|
|
this.scroll(ExtMath.clampi(y, -1, 1));
|
|
}
|
|
else {
|
|
if(x < 0)
|
|
Wheel.SCROLL_LEFT.setUsed();
|
|
else if(x > 0)
|
|
Wheel.SCROLL_RIGHT.setUsed();
|
|
if(y < 0)
|
|
Wheel.SCROLL_DOWN.setUsed();
|
|
else if(y > 0)
|
|
Wheel.SCROLL_UP.setUsed();
|
|
}
|
|
}
|
|
|
|
private void button(Button btn, boolean press) {
|
|
boolean prev = btn.isDown();
|
|
if(this.open != null && prev != press && Bind.isInputEnabled() && !Button.isMouseDown()) {
|
|
this.open.mouse(btn, this.mouseX, this.mouseY, ctrl(), shift());
|
|
}
|
|
else if(this.open != null && press) {
|
|
Bind.setBind(btn, false);
|
|
}
|
|
btn.setDown(press);
|
|
if(this.open != null && prev != press && Bind.isInputEnabled() && !Button.isMouseDown()) {
|
|
this.open.mouserel(btn, this.mouseX, this.mouseY);
|
|
}
|
|
}
|
|
|
|
private void key(Keysym key, KeyEvent act) {
|
|
if((act == KeyEvent.PRESS) && Bind.isInputEnabled() && Bind.CHEAT.isDown() && this.handleDebugKey(key))
|
|
return;
|
|
if(this.open != null && (act != KeyEvent.RELEASE) && Bind.isInputEnabled()) {
|
|
this.open.key(key, ctrl(), shift());
|
|
}
|
|
else if(this.open != null && (act != KeyEvent.REPEAT)) {
|
|
Bind.setBind(key, act == KeyEvent.RELEASE);
|
|
}
|
|
}
|
|
|
|
private void character(char code) {
|
|
if(this.open != null && Bind.isInputEnabled()) {
|
|
this.open.character(code);
|
|
}
|
|
}
|
|
|
|
private void focus(boolean focus) {
|
|
Bind.setWindowActive(focus);
|
|
if(this.open != null)
|
|
this.open.mouse(Button.MOUSE_LEFT, -1, -1, false, false);
|
|
}
|
|
|
|
private void rescale() {
|
|
this.scale = this.scaleVar;
|
|
while(this.scale > 1 && (this.fbRawX / this.scale < MIN_WIDTH || this.fbRawY / this.scale < MIN_HEIGHT)) {
|
|
this.scale--;
|
|
}
|
|
this.fbX = Math.max(this.fbRawX / this.scale, MIN_WIDTH);
|
|
this.fbY = Math.max(this.fbRawY / this.scale, MIN_HEIGHT);
|
|
if(this.open != null) {
|
|
this.refreshing = true;
|
|
this.show(this.open);
|
|
this.refreshing = false;
|
|
}
|
|
}
|
|
|
|
private void closed() {
|
|
this.interrupted = true;
|
|
}
|
|
|
|
public void poll() {
|
|
for(WindowEvent event : Window.poll()) {
|
|
switch(event.action()) {
|
|
case BUTTON:
|
|
if(event.param1() >= 0 && event.param1() < Button.values().length)
|
|
button(Button.values()[event.param1()], event.param2() != 0);
|
|
break;
|
|
case CHARACTER:
|
|
if(event.param1() >= (int)Log.CHR_SPC && event.param1() <= (int)Character.MAX_VALUE)
|
|
character((char)event.param1());
|
|
break;
|
|
case CLOSED:
|
|
closed();
|
|
break;
|
|
case CURSOR:
|
|
mouse(event.param1(), event.param2());
|
|
break;
|
|
case FOCUS:
|
|
focus(event.param1() != 0);
|
|
break;
|
|
case KEY:
|
|
if(event.param1() >= 0 && event.param1() < Keysym.values().length)
|
|
key(Keysym.values()[event.param1()], KeyEvent.values()[event.param2() % KeyEvent.values().length]);
|
|
break;
|
|
case POSITION:
|
|
pos(event.param1(), event.param2());
|
|
break;
|
|
case RESIZE:
|
|
fbsize(event.param1(), event.param2());
|
|
break;
|
|
case SCROLL:
|
|
if(event.param1() != 0 || event.param2() != 0)
|
|
scroll(event.param1(), event.param2());
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public void menu(boolean menu) {
|
|
Window.grabCursor(!menu && !this.nograb);
|
|
this.mouseFirst = true;
|
|
}
|
|
|
|
public void full(boolean full) {
|
|
if((full != this.fullscreen || full) && (!full || this.vidMode != null)) {
|
|
if(full) {
|
|
Window.setFullscreen(this.vidMode.width(), this.vidMode.height(), this.vidMode.refresh());
|
|
}
|
|
else {
|
|
Window.setWindowed(this.savedX, this.savedY, this.sizeX, this.sizeY);
|
|
}
|
|
Window.setVSync(this.vsync);
|
|
this.fullscreen = full;
|
|
}
|
|
}
|
|
|
|
public void sync(int sync) {
|
|
this.vsync = sync == 0;
|
|
this.syncLimited = sync > 0;
|
|
if(sync > 0) {
|
|
this.syncLimit = sync;
|
|
}
|
|
else {
|
|
DisplayMode mode = Window.getDisplayMode();
|
|
this.syncLimit = mode != null ? mode.refresh() : 60;
|
|
}
|
|
Window.setVSync(this.vsync);
|
|
}
|
|
|
|
public void setupOverlay() {
|
|
GlState.disableDepth();
|
|
GlState.tryBlendFuncSeparate(GL15.GL_SRC_ALPHA, GL15.GL_ONE_MINUS_SRC_ALPHA, GL15.GL_ONE, GL15.GL_ONE_MINUS_SRC_ALPHA);
|
|
GlState.setActiveTexture(GL15.GL_TEXTURE0);
|
|
GlState.color(1.0f, 1.0f, 1.0f, 1.0f);
|
|
GL15.glClear(GL15.GL_DEPTH_BUFFER_BIT);
|
|
GL15.glMatrixMode(GL15.GL_PROJECTION);
|
|
GL15.glLoadIdentity();
|
|
GL15.glOrtho(0.0D, (double)this.fbRawX, (double)this.fbRawY, 0.0D, 1000.0D, 3000.0D);
|
|
GL15.glMatrixMode(GL15.GL_MODELVIEW);
|
|
GL15.glLoadIdentity();
|
|
GL15.glTranslatef(0.0F, 0.0F, -2000.0F);
|
|
if(this.scale != 1)
|
|
GL15.glScalef((float)this.scale, (float)this.scale, 1.0f);
|
|
}
|
|
|
|
public void scissor(int x, int y, int width, int height) {
|
|
GL15.glScissor(x * this.scale, y * this.scale, width * this.scale, height * this.scale);
|
|
}
|
|
|
|
private void addFrame(long runningTime)
|
|
{
|
|
this.frames[this.frameIndex] = runningTime;
|
|
++this.frameIndex;
|
|
|
|
if (this.frameIndex == 240)
|
|
{
|
|
this.frameIndex = 0;
|
|
}
|
|
|
|
if (this.frameCounter < 240)
|
|
{
|
|
this.lastIndex = 0;
|
|
++this.frameCounter;
|
|
}
|
|
else
|
|
{
|
|
this.lastIndex = (this.frameIndex + 1) % 240;
|
|
}
|
|
}
|
|
|
|
private void updateTick() {
|
|
long n = System.nanoTime();
|
|
if(n < this.frameLast + this.frameWait)
|
|
return;
|
|
this.frameWait = 50000000L - ((n - (this.frameLast + this.frameWait)) < 50000000L ? (n - (this.frameLast + this.frameWait)) : 0L);
|
|
this.frameLast = n;
|
|
this.tickTimes[this.tickIndex++] = this.lastTickTime;
|
|
if(this.tickIndex == 240) {
|
|
this.tickIndex = 0;
|
|
}
|
|
}
|
|
|
|
public void run(long time) {
|
|
if(!Window.createWindow(VERSION, System.getProperty("opengl.debug") != null))
|
|
System.exit(1);
|
|
GL.createCapabilities();
|
|
if(!GL.getCapabilities().OpenGL15) {
|
|
Window.destroyWindow();
|
|
Util.panic("Inkompatible OpenGL-Version", "OpenGL 1.5 oder höher ist erforderlich, um dieses Programm auszuführen.");
|
|
}
|
|
Log.SYSTEM.info("OpenGL %s", GL15.glGetString(GL15.GL_VERSION));
|
|
Log.SYSTEM.info("GL_VENDOR: %s", GL15.glGetString(GL15.GL_VENDOR));
|
|
Log.SYSTEM.info("GL_RENDERER: %s", GL15.glGetString(GL15.GL_RENDERER));
|
|
Log.SYSTEM.info("Starte ...");
|
|
|
|
this.init();
|
|
this.registerDebug();
|
|
System.gc();
|
|
System.gc();
|
|
Font.loadFonts();
|
|
Font.select(this.font);
|
|
GlState.enableBlend();
|
|
GlState.blendFunc(GL15.GL_SRC_ALPHA, GL15.GL_ONE_MINUS_SRC_ALPHA);
|
|
this.initConsole();
|
|
this.textureManager.bindTexture(TextureMap.BLOCKS);
|
|
TextureUtil.setParams();
|
|
if(this.shaders)
|
|
ShaderContext.loadShaders();
|
|
this.startSound(true);
|
|
this.vidMode = Window.getDisplayMode();
|
|
if(this.vidMode != null && (this.vidMode.width() < MIN_WIDTH || this.vidMode.height() < MIN_HEIGHT))
|
|
this.vidMode = null;
|
|
Window.initWindow(this.savedX, this.savedY, this.sizeX, this.sizeY, MIN_WIDTH, MIN_HEIGHT);
|
|
Window.setIcon(genTriwave(64, 64, 0x00000000, 0xffff0000, 0xff00ff00, 0xff0000ff, 0xff7f00ff, 0xff000000), 64, 64);
|
|
this.sync(this.sync);
|
|
this.getVar("tic_target").setDefault();
|
|
this.show(GuiMenu.INSTANCE);
|
|
Log.SYSTEM.info("Client gestartet in " + String.format("%.1f", (double)(System.currentTimeMillis() - time) / 1000.0) + " Sekunden");
|
|
|
|
while(!this.interrupted) {
|
|
PerfSection.swap();
|
|
PerfSection.TIMING.enter();
|
|
this.tmr_current = Util.rtime();
|
|
this.tmr_delta = this.tmr_current - this.tmr_last;
|
|
this.tmr_last = this.tmr_current;
|
|
this.fdelta = ((float)this.tmr_delta) / 1000000.0f;
|
|
if((this.tmr_current - this.tmr_update) >= 1000000L) {
|
|
this.framerate = ((float)this.tmr_frames) * 1000000.0f / ((float)(long)(this.tmr_current - this.tmr_update));
|
|
this.tmr_frames = 0L;
|
|
this.tmr_update = this.tmr_current;
|
|
}
|
|
this.start();
|
|
PerfSection.INPUT.enter();
|
|
Bind.updateBinds();
|
|
this.input();
|
|
Bind.enableInput();
|
|
GlState.setActiveTexture(GL15.GL_TEXTURE0);
|
|
GlState.bindTexture(0);
|
|
this.inputGui();
|
|
if(this.open != null)
|
|
this.open.update();
|
|
PerfSection.TICK.enter();
|
|
this.doTicks();
|
|
PerfSection.UPDATE.enter();
|
|
this.update();
|
|
PerfSection.RENDER.enter();
|
|
this.render();
|
|
PerfSection.GUI.enter();
|
|
if(this.canRenderHud())
|
|
this.renderHud();
|
|
PerfSection.REST.enter();
|
|
this.finish();
|
|
PerfSection.SWAP.enter();
|
|
if(this.glFlush)
|
|
GL15.glFlush();
|
|
Window.swapBuffers();
|
|
PerfSection.EVENTS.enter();
|
|
Log.flushLog();
|
|
this.poll();
|
|
PerfSection.WAIT.enter();
|
|
long now = System.nanoTime();
|
|
this.addFrame(now - this.startNanoTime);
|
|
this.startNanoTime = now;
|
|
while(this.syncLimited && (Util.rtime() - this.tmr_current) < (1000000L / this.syncLimit)) {
|
|
;
|
|
}
|
|
this.tmr_frames += 1L;
|
|
}
|
|
|
|
Log.SYSTEM.info("Beende ...");
|
|
unload(false);
|
|
this.getSoundManager().unload();
|
|
this.renderer.stopChunkBuilders();
|
|
if(this.audio.end())
|
|
Log.SOUND.info("Audiogerät geschlossen");
|
|
Log.flushLog();
|
|
this.save();
|
|
Font.unloadFonts();
|
|
if(this.shaders)
|
|
ShaderContext.unloadShaders();
|
|
Window.destroyWindow();
|
|
Log.SYSTEM.info("Beendet.");
|
|
}
|
|
|
|
|
|
public void disconnected(String msg) {
|
|
Log.NETWORK.info("Getrennt: %s", msg);
|
|
this.unload(true);
|
|
this.show(new GuiInfo("Von Server getrennt", Color.RED + "Verbindung zum Server wurde getrennt\n\n" + Color.RESET + msg));
|
|
}
|
|
|
|
|
|
|
|
private void input() {
|
|
if(!this.saving && Bind.SCREENSHOT.isPressed()) {
|
|
this.screenshot = true;
|
|
}
|
|
if(Bind.isWindowActive()) {
|
|
if(Bind.FULLSCREEN.isPressed()) {
|
|
this.full(!this.fullscreen);
|
|
}
|
|
if(!(this.open instanceof GuiLoading)) {
|
|
if(!(this.open instanceof GuiConsole) && Bind.CONSOLE.isPressed()) {
|
|
this.show(GuiConsole.INSTANCE.setFull(true));
|
|
}
|
|
else if(this.open == null && Bind.COMMAND.isPressed()) {
|
|
this.show(GuiConsole.INSTANCE.setFull(false));
|
|
}
|
|
// if(this.theWorld != null && this.open == null && Bind.COMMAND.isPressed()) {
|
|
// this.displayGuiScreen(GuiChat.INSTANCE);
|
|
// }
|
|
if(this.world != null && Bind.MENU.isPressed()) {
|
|
if(this.open != (this.charEditor ? GuiChar.INSTANCE : null))
|
|
this.show(this.charEditor ? GuiChar.INSTANCE : null);
|
|
else
|
|
this.show(GuiMenu.INSTANCE);
|
|
}
|
|
else if(this.world == null && !(this.open instanceof GuiMenu) && Bind.MENU.isPressed()) {
|
|
this.show(GuiMenu.INSTANCE);
|
|
}
|
|
if(this.world != null && !this.charEditor && Bind.INVENTORY.isPressed()) {
|
|
if(this.open instanceof GuiContainer && !(this.open.selected instanceof client.gui.element.Field || this.open.selected instanceof Area)) {
|
|
this.show(null);
|
|
}
|
|
else if(this.open == null) {
|
|
if(this.player.isRiding() && this.player.vehicle instanceof EntityHorse)
|
|
this.player.sendHorseInventory();
|
|
else
|
|
this.show(new GuiInventory(this.player));
|
|
}
|
|
}
|
|
}
|
|
if(Bind.SHOW.isPressed()) {
|
|
if(this.drawDebug) {
|
|
this.drawDebug = this.drawFps = false;
|
|
}
|
|
else {
|
|
this.drawDebug = this.drawFps;
|
|
this.drawFps = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void screenshot() {
|
|
if(this.saving)
|
|
return;
|
|
this.saving = true;
|
|
final int stride = ((this.fbRawX * 3) & 3) != 0 ? 4 + ((this.fbRawX * 3) & ~3) : (this.fbRawX * 3);
|
|
final ByteBuffer data = ByteBuffer.allocateDirect(stride * this.fbRawY).order(ByteOrder.nativeOrder());
|
|
GL15.glReadPixels(0, 0, this.fbRawX, this.fbRawY, GL15.GL_RGB, GL15.GL_UNSIGNED_BYTE, data);
|
|
new Thread(new Runnable() {
|
|
public void run() {
|
|
byte[] pixels = new byte[stride * Client.this.fbRawY];
|
|
data.get(pixels);
|
|
byte[] conv = new byte[Client.this.fbRawX * Client.this.fbRawY * 3];
|
|
for(int l = 0; l < Client.this.fbRawY; l++) {
|
|
System.arraycopy(pixels, l * stride, conv, (Client.this.fbRawY - 1 - l) * Client.this.fbRawX * 3, Client.this.fbRawX * 3);
|
|
}
|
|
BufferedImage image = new BufferedImage(Client.this.fbRawX, Client.this.fbRawY, BufferedImage.TYPE_INT_ARGB);
|
|
int[] img = new int[Client.this.fbRawX * Client.this.fbRawY];
|
|
for(int z = 0; z < img.length; z++) {
|
|
img[z] = (int)(conv[(z * 3) + 2] & 0xff) | ((int)(conv[(z * 3) + 1] & 0xff) << 8) | ((int)(conv[(z * 3) + 0] & 0xff) << 16) | 0xff000000;
|
|
}
|
|
image.setRGB(0, 0, Client.this.fbRawX, Client.this.fbRawY, img, 0, Client.this.fbRawX);
|
|
|
|
File dir = new File("screenshots");
|
|
dir.mkdirs();
|
|
int n = 0;
|
|
File file;
|
|
Date date = new Date();
|
|
do {
|
|
file = new File(dir, "screen_" + new SimpleDateFormat("dd-MM-yyyy_HH-mm-ss").format(date) + (n != 0 ? "_" + n : "") + ".png");
|
|
n++;
|
|
}
|
|
while(file.exists());
|
|
final File saved = file;
|
|
try {
|
|
ImageIO.write(image, "png", file);
|
|
}
|
|
catch(IOException e) {
|
|
Client.this.schedule(new Runnable() {
|
|
public void run() {
|
|
Client.this.saving = false;
|
|
Log.IO.error(e, "Konnte Textur '" + saved + "' nicht speichern");
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
Client.this.schedule(new Runnable() {
|
|
public void run() {
|
|
Client.this.saving = false;
|
|
Client.this.logFeed("Bildschirmfoto als '%s' gespeichert", saved.getName());
|
|
}
|
|
});
|
|
}
|
|
}, "Screenshot writer").start();
|
|
}
|
|
|
|
public Color framecode() {
|
|
return (this.framerate >= 59.0f) ? Color.GREEN : ((this.framerate >= 29.0f) ? Color.YELLOW : ((this.framerate >= 14.0f) ? Color.ORANGE : Color.RED));
|
|
}
|
|
|
|
public Color tpscode() {
|
|
return (this.tickrate >= (((float)this.tickTarget / 1000.0f) - 1.0f)) ? Color.GREEN : ((this.tickrate >= (((float)this.tickTarget / 1000.0f) / 2.0f - 1.0f)) ? Color.YELLOW :
|
|
((this.tickrate >= (((float)this.tickTarget / 1000.0f) / 4.0f - 1.0f)) ? Color.ORANGE : Color.RED));
|
|
}
|
|
|
|
private void doTicks() {
|
|
this.tick_stime = Util.rtime();
|
|
if((this.tick_stime - this.tick_update) >= 1000000L) {
|
|
this.tickrate = ((float)this.tick_done) * 1000000.0f / ((float)(long)(this.tick_stime - this.tick_update));
|
|
this.tick_done = 0;
|
|
this.tick_update = this.tick_stime;
|
|
}
|
|
this.tick_torun += (((long)this.tickTarget) * this.tmr_delta) / 1000L;
|
|
this.tickFrame = 0;
|
|
this.tick_torun = this.tick_torun > 2000000L ? 1000000L : this.tick_torun;
|
|
while(this.tick_torun >= 1000000L) {
|
|
this.tick();
|
|
this.tick_done += 1L;
|
|
this.tickFrame += 1;
|
|
this.tick_total += 1L;
|
|
this.tick_torun -= 1000000L;
|
|
if((this.tick_ftime = (Util.rtime() - this.tick_stime)) >= (((long)this.tickTimeout) * 1000L)) {
|
|
Log.TICK.warn("Ticks benötigten %d ms dieses Frame (maximal %d ms), überspringe %d Ticks", this.tick_ftime / 1000L, this.tickTimeout, this.tick_torun / 1000000L);
|
|
this.tick_torun = 0L;
|
|
break;
|
|
}
|
|
}
|
|
this.tickFraction = ((double)this.tick_torun) / 1000000.0;
|
|
this.tick_ttime += this.tick_ftime;
|
|
this.tick_time = this.tickFrame != 0 ? (this.tick_ftime / (long)this.tickFrame) : 0L;
|
|
}
|
|
|
|
private void update() {
|
|
if(this.player != null) {
|
|
int radius = Math.min(this.renderDistance * 16, this.lightRange);
|
|
for(int n = 0; n < this.lightUpdates; n++) {
|
|
int x = ExtMath.floord(this.player.posX) + this.world.rand.range(-radius, radius);
|
|
int y = ExtMath.floord(this.player.posY) + this.world.rand.range(-radius, radius);
|
|
int z = ExtMath.floord(this.player.posZ) + this.world.rand.range(-radius, radius);
|
|
this.world.checkBlockLight(new LocalPos(x, y, z));
|
|
}
|
|
}
|
|
}
|
|
|
|
public void tick_target(float tps) {
|
|
this.tickTarget = (int)(tps * 1000.0f);
|
|
this.tick_torun = 0L;
|
|
this.tick_done = 0L;
|
|
this.tick_update = Util.rtime();
|
|
}
|
|
|
|
public void unload(boolean loading) {
|
|
if(this.world != null && this.getNetHandler() != null)
|
|
this.getNetHandler().getConnection().closeChannel("Quitting");
|
|
this.unloadWorld();
|
|
this.show(GuiMenu.INSTANCE);
|
|
}
|
|
|
|
private void startSound(boolean load) {
|
|
if(load) {
|
|
SoundManager.loadSounds();
|
|
MidiBank.loadBanks();
|
|
}
|
|
this.audio = new AudioInterface(this.soundFrameSize, this.soundBufferSize, !this.soundEnabled);
|
|
boolean started = this.audio.start();
|
|
Log.flushLog();
|
|
if(started)
|
|
Log.SOUND.info("Audiogerät geöffnet");
|
|
else if(this.soundEnabled)
|
|
Log.SOUND.info("Audiogerät konnte nicht geöffnet werden");
|
|
for(Volume volume : Volume.values()) {
|
|
volume.apply();
|
|
}
|
|
}
|
|
|
|
public void restartSound(boolean load) {
|
|
Client.this.logFeed("Lade Sound-System " + (load ? "und alle Sounds " : "") + "neu");
|
|
GuiPlayer.INSTANCE.stop();
|
|
this.soundManager.unload();
|
|
if(this.audio.end())
|
|
Log.SOUND.info("Audiogerät geschlossen");
|
|
this.startSound(load);
|
|
Client.this.logFeed("Das Sound-System " + (load ? "und alle Sounds wurden" : "wurde") + " neu geladen");
|
|
}
|
|
|
|
public AudioInterface getAudioInterface() {
|
|
return this.audio;
|
|
}
|
|
|
|
public void applyDistance() {
|
|
if(this.renderer != null)
|
|
this.renderer.setDisplayListEntitiesDirty();
|
|
}
|
|
|
|
public void setMidiDebug() {
|
|
if(this.audio != null) {
|
|
MidiDecoder midi = this.audio.alGetMidi();
|
|
if(midi != null)
|
|
midi.setDebug(this.midiDebug);
|
|
}
|
|
}
|
|
|
|
private void registerDebug(Keysym key, String help, DebugRunner runner) {
|
|
if(this.debug.containsKey(key))
|
|
throw new IllegalStateException("Debug-Taste " + key.getDisplay() + " ist bereits registriert");
|
|
this.debug.put(key, new DebugFunction(key, runner, help));
|
|
}
|
|
|
|
private void registerDebug() {
|
|
this.registerDebug(Keysym.H, "Hilfe zu Tastenkombinationen anzeigen", new DebugRunner() {
|
|
public void execute(Keysym key) {
|
|
String bind = Bind.CHEAT.getInput() == null ? "n/a" : Bind.CHEAT.getInput().getDisplay();
|
|
Client.this.show(new GuiInfo("Hilfe zu Tastenkombinationen", Color.DARK_GREEN + "" + Client.this.debug.size() + " Tastenkombinationen stehen zur Verfügung:\n" +
|
|
Util.buildLines(new Function<DebugFunction, String>() {
|
|
public String apply(DebugFunction func) {
|
|
return Color.CYAN + bind + Color.RED + "+" + Color.GREEN + func.key.getDisplay() + Color.GRAY + " - " + Color.YELLOW + func.help;
|
|
}
|
|
}, Client.this.debug.values())));
|
|
}
|
|
});
|
|
this.registerDebug(Keysym.N, "NoClip umschalten", new DebugRunner() {
|
|
public void execute(Keysym key) {
|
|
Client.this.performAction(Action.NOCLIP);
|
|
}
|
|
});
|
|
this.registerDebug(Keysym.G, "Unsterblichkeit umschalten", new DebugRunner() {
|
|
public void execute(Keysym key) {
|
|
Client.this.performAction(Action.GOD);
|
|
}
|
|
});
|
|
this.registerDebug(Keysym.F, "Geschwindigkeit umschalten", new DebugRunner() {
|
|
public void execute(Keysym key) {
|
|
Client.this.performAction(Action.SPEED);
|
|
}
|
|
});
|
|
this.registerDebug(Keysym.R, "Gegenstand in Hand / Alle (+Shift) reparieren und auffüllen", new DebugRunner() {
|
|
public void execute(Keysym key) {
|
|
Client.this.performAction(Action.REPAIR, Client.this.shift() ? 1 : 0);
|
|
}
|
|
});
|
|
this.registerDebug(Keysym.E, "Gegenstands-Cheat-Menü umschalten", new DebugRunner() {
|
|
public void execute(Keysym key) {
|
|
Client.this.logFeed("Cheat-Menü: %s", (Client.this.itemCheat ^= true) ? "an" : "aus");
|
|
if(Client.this.open instanceof GuiContainer)
|
|
Client.this.open.init();
|
|
}
|
|
});
|
|
if(Util.DEVMODE)
|
|
this.registerDebug(Keysym.L, "Maximale Helligkeit umschalten", new DebugRunner() {
|
|
public void execute(Keysym key) {
|
|
Client.this.setGamma ^= true;
|
|
Client.this.renderer.loadRenderers();
|
|
Client.this.logFeed("Maximale Helligkeit: %s", Client.this.setGamma ? "an" : "aus");
|
|
}
|
|
});
|
|
this.registerDebug(Keysym.J, "JVM GC ausführen", new DebugRunner() {
|
|
public void execute(Keysym key) {
|
|
Client.this.logFeed("Führe JVM GC aus");
|
|
long mem = Runtime.getRuntime().freeMemory();
|
|
System.gc();
|
|
System.gc();
|
|
mem = Runtime.getRuntime().freeMemory() - mem;
|
|
mem = mem < 0L ? 0L : mem;
|
|
Client.this.logFeed("JVM GC ausgeführt: %d MB freigegeben", (int)(mem / 1024L / 1024L));
|
|
}
|
|
});
|
|
if(Util.DEVMODE)
|
|
this.registerDebug(Keysym.B, "Hitbox-Overlay umschalten", new DebugRunner() {
|
|
public void execute(Keysym key) {
|
|
Client.this.getRenderManager().setDebugBoundingBox(!Client.this.getRenderManager().isDebugBoundingBox());
|
|
Client.this.logFeed("Objekt-Grenzen: %s", Client.this.getRenderManager().isDebugBoundingBox() ? "an" : "aus");
|
|
}
|
|
});
|
|
this.registerDebug(Keysym.K, "Debug-Kamera in 3. Person umschalten", new DebugRunner() {
|
|
public void execute(Keysym key) {
|
|
Client.this.logFeed("Debug-Kamera 3. Person: %s", (Client.this.debugCamEnable ^= true) ? "an" : "aus");
|
|
}
|
|
});
|
|
if(Util.DEVMODE)
|
|
this.registerDebug(Keysym.X, "Röntgenblick umschalten", new DebugRunner() {
|
|
public void execute(Keysym key) {
|
|
Client.this.xrayActive ^= true;
|
|
Client.this.renderer.loadRenderers();
|
|
Client.this.logFeed("Röntgenblick: %s", Client.this.xrayActive ? "an" : "aus");
|
|
}
|
|
});
|
|
if(Util.DEVMODE)
|
|
this.registerDebug(Keysym.O, "Objekt-Overlay umschalten", new DebugRunner() {
|
|
public void execute(Keysym key) {
|
|
Client.this.logFeed("Objekt-Umrahmung: %s", (Client.this.renderOutlines ^= true) ? "an" : "aus");
|
|
}
|
|
});
|
|
if(Util.DEVMODE)
|
|
this.registerDebug(Keysym.I, "Block-Objekt-Overlay umschalten", new DebugRunner() {
|
|
public void execute(Keysym key) {
|
|
Client.this.logFeed("Block-Objekte anzeigen: %s", (Client.this.tileOverlay ^= true) ? "an" : "aus");
|
|
}
|
|
});
|
|
this.registerDebug(Keysym.Y, "Alle Chunks neu kompilieren", new DebugRunner() {
|
|
public void execute(Keysym key) {
|
|
Client.this.logFeed("Kompiliere alle Chunks neu");
|
|
Client.this.renderer.loadRenderers();
|
|
Client.this.logFeed("Alle Chunks wurden neu kompiliert");
|
|
}
|
|
});
|
|
this.registerDebug(Keysym.T, "Alle Texturen neu laden", new DebugRunner() {
|
|
public void execute(Keysym key) {
|
|
Client.this.refreshResources();
|
|
}
|
|
});
|
|
this.registerDebug(Keysym.S, "Sound neu starten / Alle Sounds neu laden (+Shift)", new DebugRunner() {
|
|
public void execute(Keysym key) {
|
|
Client.this.restartSound(Client.this.shift());
|
|
}
|
|
});
|
|
if(Util.DEVMODE)
|
|
this.registerDebug(Keysym.W, "Server-Tick-Limit umschalten (Welt beschleunigen / Warpmodus)", new DebugRunner() {
|
|
public void execute(Keysym key) {
|
|
Client.this.performAction(Action.WARP_MODE);
|
|
}
|
|
});
|
|
this.registerDebug(Keysym.M, "Alle Gegenstände herbei ziehen (Magnetmodus)", new DebugRunner() {
|
|
public void execute(Keysym key) {
|
|
Client.this.performAction(Action.MAGNET);
|
|
}
|
|
});
|
|
this.registerDebug(Keysym.Z, "Den Spieler heilen", new DebugRunner() {
|
|
public void execute(Keysym key) {
|
|
Client.this.performAction(Action.HEAL);
|
|
}
|
|
});
|
|
if(Util.DEVMODE)
|
|
this.registerDebug(Keysym.P, "Server Performance-Anfrage senden", new DebugRunner() {
|
|
public void execute(Keysym key) {
|
|
Client.this.performAction(Action.PERF);
|
|
}
|
|
});
|
|
if(Util.DEVMODE)
|
|
this.registerDebug(Keysym.C, "Debug-Crash auslösen (2x schnell hintereinander)", new DebugRunner() {
|
|
long lastUsed;
|
|
|
|
public void execute(Keysym key) {
|
|
if(System.currentTimeMillis() - this.lastUsed <= 1000L) {
|
|
throw new RuntimeException("Manuell herbeigerufener Debugging-Absturz");
|
|
}
|
|
else {
|
|
this.lastUsed = System.currentTimeMillis();
|
|
Client.this.logFeed(Color.RED + "VORSICHT: Debug-Absturz nach mehrmaligem Drücken innerhalb einer Sekunde");
|
|
}
|
|
}
|
|
});
|
|
this.registerDebug(Keysym.V, "Alle Sounds stoppen", new DebugRunner() {
|
|
public void execute(Keysym key) {
|
|
Client.this.soundManager.stopSounds();
|
|
}
|
|
});
|
|
if(Util.DEVMODE)
|
|
this.registerDebug(Keysym.Q, "Programm sofort beenden und trennen", new DebugRunner() {
|
|
public void execute(Keysym key) {
|
|
Client.this.interrupted = true;
|
|
}
|
|
});
|
|
this.registerDebug(Keysym.A, "Bild-Synchonisation umschalten (VSync - begrenzt - unbegrenzt)", new DebugRunner() {
|
|
public void execute(Keysym key) {
|
|
Client.this.getVar("win_sync").parse("" + (Client.this.vsync ? Client.this.syncLimit : (Client.this.syncLimited ? -1 : 0)));
|
|
Client.this.setDirty();
|
|
}
|
|
});
|
|
this.registerDebug(Keysym.D, "Konsole und Chat leeren", new DebugRunner() {
|
|
public void execute(Keysym key) {
|
|
GuiConsole.INSTANCE.reset();
|
|
if(Client.this.open instanceof GuiConsole)
|
|
((GuiConsole)Client.this.open).setLog(Client.this.buffer);
|
|
}
|
|
});
|
|
this.registerDebug(Keysym.U, "HUD umschalten", new DebugRunner() {
|
|
public void execute(Keysym key) {
|
|
Client.this.showHud ^= true;
|
|
}
|
|
});
|
|
this.registerDebug(Keysym.UE, "Spieler in Overlay umschalten", new DebugRunner() {
|
|
public void execute(Keysym key) {
|
|
Client.this.logFeed("Spieler-Info in Overlay: %s", (Client.this.debugPlayer ^= true) ? "an" : "aus");
|
|
}
|
|
});
|
|
this.registerDebug(Keysym.OE, "Tick-Profiler umschalten", new DebugRunner() {
|
|
public void execute(Keysym key) {
|
|
if(Client.this.lastTickTime >= 0) {
|
|
Client.this.performAction(Action.STOP_PROFILING);
|
|
Client.this.lastTickTime = -1;
|
|
}
|
|
else {
|
|
Client.this.performAction(Action.START_PROFILING);
|
|
Client.this.lastTickTime = 0;
|
|
}
|
|
}
|
|
});
|
|
if(Util.DEVMODE)
|
|
this.registerDebug(Keysym.SPACE, "Kamera umschalten", new DebugRunner() {
|
|
public void execute(Keysym key) {
|
|
if(Client.this.world != null && Client.this.player != null && !Client.this.servercam) {
|
|
Client.this.viewEntity = Client.this.viewEntity == Client.this.player ? new EntityCamera(Client.this.world,
|
|
Client.this.player.posX, Client.this.player.posY, Client.this.player.posZ, Client.this.player.rotYaw, Client.this.player.rotPitch, 256, 2.5f, CameraType.FREE, false) : Client.this.player;
|
|
Client.this.freecam = Client.this.viewEntity != Client.this.player;
|
|
}
|
|
}
|
|
});
|
|
if(Util.DEVMODE)
|
|
this.registerDebug(Keysym.AE, "Programm sofort beenden und server beenden", new DebugRunner() {
|
|
public void execute(Keysym key) {
|
|
if(Client.this.getNetHandler() != null) {
|
|
Client.this.getNetHandler().getConnection().sendPacket(new CPacketMessage(CPacketMessage.Type.COMMAND, "shutdown"), new GenericFutureListener<Future<? super Void>>() {
|
|
public void operationComplete(Future<? super Void> u) throws Exception {
|
|
try {
|
|
Thread.sleep(1000L);
|
|
}
|
|
catch(InterruptedException e) {
|
|
}
|
|
Client.this.interrupted = true;
|
|
}
|
|
});
|
|
}
|
|
else {
|
|
Client.this.interrupted = true;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
private boolean handleDebugKey(Keysym key) {
|
|
DebugFunction func = this.debug.get(key);
|
|
if(func != null) {
|
|
Bind.disableInput(key);
|
|
if(!(this.open instanceof GuiLoading)) {
|
|
this.soundManager.playSound(new PositionedSound(SoundEvent.PRESS, EventType.UI_INTERFACE));
|
|
func.runner.execute(key);
|
|
}
|
|
}
|
|
return func != null;
|
|
}
|
|
|
|
public <T extends CVar> T getVar(String name) {
|
|
return (T)this.cvars.get(name);
|
|
}
|
|
|
|
public Iterable<String> getVars() {
|
|
return this.cvars.keySet();
|
|
}
|
|
|
|
public void setDirty() {
|
|
this.cfgDirty = true;
|
|
}
|
|
|
|
public boolean isDirty() {
|
|
return this.cfgDirty;
|
|
}
|
|
|
|
public String getBuffer() {
|
|
return this.buffer;
|
|
}
|
|
|
|
public float getTickFraction() {
|
|
return (float)this.tickFraction;
|
|
}
|
|
|
|
public long getPassedTime() {
|
|
return this.tmr_delta;
|
|
}
|
|
|
|
private void regVar(CVar cv) {
|
|
if(this.cvars.containsKey(cv.getCVarName()))
|
|
throw new IllegalArgumentException("Variable " + cv.getCVarName() + " existiert bereits!");
|
|
this.cvars.put(cv.getCVarName(), cv);
|
|
}
|
|
|
|
private void regVars(Class clazz, Object object) {
|
|
for(Field field : clazz.getDeclaredFields()) {
|
|
if(field.isAnnotationPresent(Variable.class)) {
|
|
if(Modifier.isStatic(field.getModifiers()) != (object == null))
|
|
continue;
|
|
if(Modifier.isFinal(field.getModifiers()))
|
|
throw new IllegalArgumentException("Feld für Variable " + field + " muss änderbar sein!");
|
|
Variable value = field.getAnnotation(Variable.class);
|
|
if(value.name().isEmpty())
|
|
throw new IllegalArgumentException("Variablenname von " + field + " kann nicht leer sein!");
|
|
field.setAccessible(true);
|
|
CVar cv;
|
|
VarFunction func = null;
|
|
if(value.callback() != VarFunction.class) {
|
|
try {
|
|
func = value.callback().getConstructor().newInstance();
|
|
}
|
|
catch(InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
|
|
| NoSuchMethodException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
CharValidator validator = null;
|
|
if(value.validator() != CharValidator.class) {
|
|
try {
|
|
validator = value.validator().getConstructor().newInstance();
|
|
}
|
|
catch(InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
|
|
| NoSuchMethodException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
if(field.getType() == int.class)
|
|
cv = value.type() != IntType.INT ? new ColorVar(value.name(), value.display(), field, object, value.category(), value.type() == IntType.ALPHA, (IntFunction)func) :
|
|
new IntVar(value.name(), value.display(), field, object, value.category(), (int)value.min(), (int)value.max(), (IntFunction)func, value.unit(), value.precision());
|
|
else if(field.getType() == float.class)
|
|
cv = new FloatVar(value.name(), value.display(), field, object, value.category(), value.min(), value.max(), (FloatFunction)func, value.unit(), value.precision());
|
|
else if(field.getType() == boolean.class)
|
|
cv = new BoolVar(value.name(), value.display(), field, object, value.category(), (BoolFunction)func);
|
|
else if(field.getType() == String.class)
|
|
cv = new StringVar(value.name(), value.display(), field, object, value.category(), (int)value.max(), (StringFunction)func, validator, (int)value.min() <= 0);
|
|
else if(field.getType().isEnum())
|
|
cv = new EnumVar(value.name(), value.display(), field, object, value.category(), (EnumFunction)func, value.switched());
|
|
else
|
|
throw new IllegalArgumentException(value.name() + ": Unbekannter Variablen-Typ - " + field.getType());
|
|
regVar(cv);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void regVars(Object object) {
|
|
regVars(object.getClass(), object);
|
|
}
|
|
|
|
private void regVars(Class clazz) {
|
|
regVars(clazz, null);
|
|
}
|
|
|
|
public void initConsole() {
|
|
reset();
|
|
for(Bind bind : Bind.values()) {
|
|
regVar(bind);
|
|
}
|
|
for(Volume volume : Volume.values()) {
|
|
regVar(volume);
|
|
}
|
|
regVars(this);
|
|
regVars(Style.CUSTOM);
|
|
regVars(GuiServer.INSTANCE);
|
|
regVars(GuiChar.INSTANCE);
|
|
|
|
if(!this.config.exists())
|
|
return;
|
|
String data;
|
|
try {
|
|
data = FileUtils.read(this.config);
|
|
}
|
|
catch(IOException e) {
|
|
Log.IO.error(e, "Konnte Konfigurationsdatei nicht laden");
|
|
return;
|
|
}
|
|
if(data == null)
|
|
return;
|
|
for(String line : data.split("\n")) {
|
|
if(line.startsWith("#"))
|
|
continue;
|
|
String[] tok = line.split("=", 2);
|
|
if(tok.length != 2)
|
|
continue;
|
|
CVar cv = getVar(tok[0]);
|
|
if(cv == null) {
|
|
Log.CONSOLE.error("CVAR '%s' existiert nicht", tok[0]);
|
|
continue;
|
|
}
|
|
if(cv.parse(tok[1])) {
|
|
Log.CONSOLE.trace("%s = %s", cv.getCVarName(), cv.format());
|
|
}
|
|
else {
|
|
Log.CONSOLE.error("Kann CVAR '%s' nicht auf '%s' setzen", cv.getCVarName(), tok[1]);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void save() {
|
|
this.cfgDirty = false;
|
|
StringBuilder sb = new StringBuilder();
|
|
for(CVar cv : this.cvars.values()) {
|
|
if(sb.length() > 0)
|
|
sb.append('\n');
|
|
sb.append(cv.getCVarName() + "=" + cv.format());
|
|
}
|
|
try {
|
|
FileUtils.write(this.config, sb.toString());
|
|
}
|
|
catch(IOException e) {
|
|
Log.IO.error(e, "Konnte Konfigurationsdatei nicht speichern");
|
|
}
|
|
}
|
|
|
|
private void printVar(CVar cv) {
|
|
String values = cv.getValues();
|
|
this.logConsole("%s " + Color.NEON + "%s " + Color.DARK_GRAY + "[%s" + Color.DARK_GRAY + "]" + Color.GRAY + " = " + Color.WHITE + "%s " + Color.DARK_GRAY +
|
|
"[" + Color.GRAY + "D " + Color.CRIMSON + "%s" + Color.DARK_GRAY + "]%s", cv.getType(), cv.getCVarName(), cv.getCategory(), cv.format(), cv.getDefault(),
|
|
values != null ? " [" + Color.LIGHT_GRAY + values + Color.DARK_GRAY + "]" : "");
|
|
}
|
|
|
|
public void exec(String line) {
|
|
if(line.equals("#")) {
|
|
for(CVar cv : this.cvars.values()) {
|
|
printVar(cv);
|
|
}
|
|
this.logConsole(Color.GREEN + "CVARs insgesamt registriert: %d", this.cvars.size());
|
|
return;
|
|
}
|
|
else if(line.startsWith("#")) {
|
|
String tok = line.substring(1);
|
|
int space = tok.indexOf(' ');
|
|
CVar cv = getVar(space >= 0 ? tok.substring(0, space) : tok);
|
|
if(cv != null) {
|
|
if(space < 0 || space >= tok.trim().length()) {
|
|
this.logConsole("%s = %s", cv.getCVarName(), cv.format());
|
|
return;
|
|
}
|
|
String value = tok.substring(space + 1).trim();
|
|
if(cv.parse(value)) {
|
|
this.cfgDirty = true;
|
|
this.logConsole("%s -> %s", cv.getCVarName(), cv.format());
|
|
}
|
|
else {
|
|
this.logConsole(Color.RED + "Kann CVAR '%s' nicht auf '%s' setzen", cv.getCVarName(), value);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
if(this.player != null && this.getNetHandler() != null)
|
|
this.getNetHandler().addToSendQueue(new CPacketMessage(line.startsWith("/") ? CPacketMessage.Type.COMMAND : CPacketMessage.Type.CHAT, line.startsWith("/") ? line.substring(1) : line));
|
|
}
|
|
|
|
public void reset() {
|
|
this.buffer = Color.NEON + "*** " + VERSION + " ***";
|
|
this.console.clear();
|
|
this.chat.clear();
|
|
this.feed.clear();
|
|
this.hotbar.clear();
|
|
}
|
|
|
|
private void resize(List<Message> log, int size) {
|
|
while(log.size() > size) {
|
|
log.remove(log.size() - 1);
|
|
}
|
|
}
|
|
|
|
public void resizeConsole() {
|
|
this.resize(this.console, this.consoleSize);
|
|
}
|
|
|
|
public void resizeChat() {
|
|
this.resize(this.chat, this.chatSize);
|
|
}
|
|
|
|
public void resizeFeed() {
|
|
this.resize(this.feed, this.feedSize);
|
|
}
|
|
|
|
public void resizeHotbar() {
|
|
this.resize(this.hotbar, this.hotbarSize);
|
|
}
|
|
|
|
public void log(String prefixed, String line) {
|
|
String msg = this.conTimestamps ? prefixed : line;
|
|
if((this.buffer.length() + msg.length() + 1) > LOG_BUFFER) {
|
|
int offset = (msg.length() + 1) > 1024 ? (msg.length() + 1) : 1024;
|
|
int nl = this.buffer.indexOf('\n', offset);
|
|
this.buffer = nl >= 0 ? this.buffer.substring(nl + 1) : "";
|
|
}
|
|
this.buffer = this.buffer + "\n" + msg;
|
|
if(this.open instanceof GuiConsole) {
|
|
((GuiConsole)this.open).setLog(this.buffer);
|
|
}
|
|
}
|
|
|
|
private void addMessage(List<Message> log, int size, String msg) {
|
|
Log.CONSOLE.user(msg);
|
|
if(size > 0) {
|
|
for(String line : msg.split("\n")) {
|
|
Message lmsg = new Message(line, this.tmr_current);
|
|
while(log.size() >= size) {
|
|
log.remove(log.size() - 1);
|
|
}
|
|
log.add(0, lmsg);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void logConsole(String line) {
|
|
this.addMessage(this.console, this.consoleSize, line);
|
|
}
|
|
|
|
public void logConsole(String fmt, Object ... args) {
|
|
this.logConsole(String.format(fmt, args));
|
|
}
|
|
|
|
public void logChat(String line) {
|
|
this.addMessage(this.chat, this.chatSize, line);
|
|
}
|
|
|
|
public void logChat(String fmt, Object ... args) {
|
|
this.logChat(String.format(fmt, args));
|
|
}
|
|
|
|
public void logFeed(String line) {
|
|
this.addMessage(this.feed, this.feedSize, line);
|
|
}
|
|
|
|
public void logFeed(String fmt, Object ... args) {
|
|
this.logFeed(String.format(fmt, args));
|
|
}
|
|
|
|
public void logHotbar(String line) {
|
|
this.addMessage(this.hotbar, this.hotbarSize, line);
|
|
}
|
|
|
|
public void logHotbar(String fmt, Object ... args) {
|
|
this.logHotbar(String.format(fmt, args));
|
|
}
|
|
|
|
private void drawOverlay(List<Message> log, int size, boolean up, int align, int x, int y) {
|
|
if(size > 0) {
|
|
long fade = 1000000L * (long)this.hudFadeout;
|
|
int bg = (this.hudOpacity << 24) | 0x000000;
|
|
y = up ? y - Font.HEIGHT - 2 : y;
|
|
for(Iterator<Message> iter = log.iterator(); iter.hasNext();) {
|
|
Message msg = iter.next();
|
|
if((this.tmr_current - msg.time()) <= fade || (log == this.chat && this.chatPermanent)) {
|
|
if(align > 0)
|
|
Drawing.drawTextbox(msg.message(), x, y, bg);
|
|
else if(align < 0)
|
|
Drawing.drawTextboxRight(msg.message(), x, y, bg);
|
|
else
|
|
Drawing.drawTextboxCentered(msg.message(), x, y, bg);
|
|
y += up ? -(Font.HEIGHT + 2) : Font.HEIGHT + 2;
|
|
}
|
|
else {
|
|
iter.remove();
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
log.clear();
|
|
}
|
|
}
|
|
|
|
private void drawPing(int x, int y, int ping) {
|
|
int bars;
|
|
Color color;
|
|
if(ping < 0 || ping >= 20000) {
|
|
bars = 0;
|
|
color = ping < 0 ? Color.GRAY : Color.DARK_RED;
|
|
}
|
|
else if(ping < 80) {
|
|
bars = ping < 50 ? 8 : 7;
|
|
color = Color.GREEN;
|
|
}
|
|
else if(ping < 160) {
|
|
bars = ping < 120 ? 6 : 5;
|
|
color = Color.DARK_GREEN;
|
|
}
|
|
else if(ping < 350) {
|
|
bars = ping < 220 ? 4 : 3;
|
|
color = Color.YELLOW;
|
|
}
|
|
else if(ping < 700) {
|
|
bars = ping < 500 ? 2 : 1;
|
|
color = Color.RED;
|
|
}
|
|
else {
|
|
bars = 1;
|
|
color = Color.DARK_RED;
|
|
}
|
|
Drawing.drawTextRight(color + (ping < 10000 ? String.format("%d", ping) + "ms" : String.format("%.1f", ((float)ping) / 1000.0f) + "s"), x - 18, y, 0xffffffff);
|
|
for(int z = 0; z < bars; z++) {
|
|
Drawing.drawRect(x - 15 + z * 2, y + 8 - z + Font.HEIGHT - 10 + (Font.HEIGHT < 8 ? 1 : 0), 1, z + 1, 0xff000000 | color.color);
|
|
}
|
|
}
|
|
|
|
public void drawInfo() {
|
|
ClientPlayer netHandler = this.getNetHandler();
|
|
if(netHandler != null) {
|
|
int size = this.playerList.size();
|
|
int w = size > 80 ? 4 : (size > 40 ? 3 : (size > 10 ? 2 : 1));
|
|
w = Math.min(w, Math.max(1, this.fbX / 300));
|
|
int bx = 0;
|
|
int by = 0;
|
|
for(Entry<String, Integer> elem : this.playerList.entrySet()) {
|
|
int x = this.fbX / 2 - (w * 300) / 2 + bx * 300;
|
|
int y = this.hudMargin + by * (Font.HEIGHT + 2);
|
|
Drawing.drawGradient(x, y, 300, Font.HEIGHT + 2, 0x7f404040, 0x7f101010, 0x7f5f5f5f, 0x7f000000);
|
|
Drawing.drawText(elem.getKey(), x + 4, y + 1, 0xffffffff);
|
|
drawPing(x + 300 - 4, y + 1, elem.getValue());
|
|
if(++bx >= w) {
|
|
bx = 0;
|
|
++by;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void renderWorldDirections(float partialTicks) {
|
|
GlState.enableBlend();
|
|
GlState.tryBlendFuncSeparate(GL15.GL_SRC_ALPHA, GL15.GL_ONE_MINUS_SRC_ALPHA, GL15.GL_ONE, GL15.GL_ZERO);
|
|
GL15.glLineWidth(1.0F);
|
|
GlState.disableTexture2D();
|
|
GlState.depthMask(false);
|
|
GL15.glPushMatrix();
|
|
GL15.glTranslatef((float)(this.fbX / 2), (float)(this.fbY / 2), 0.0F);
|
|
this.renderer.rotateCamera(this.viewEntity, partialTicks, true);
|
|
Renderer.drawOutlinedBoundingBox(new BoundingBox(0.0D, 0.0D, 0.0D, 24D, 1D, 1D), 255, 0, 0, 255);
|
|
Renderer.drawOutlinedBoundingBox(new BoundingBox(0.0D, 0.0D, 0.0D, 1D, 1D, 24D), 0, 0, 255, 255);
|
|
Renderer.drawOutlinedBoundingBox(new BoundingBox(0.0D, 0.0D, 0.0D, 1D, -20D, 1D), 0, 255, 0, 255);
|
|
GL15.glPopMatrix();
|
|
GlState.depthMask(true);
|
|
GlState.enableTexture2D();
|
|
GlState.disableBlend();
|
|
}
|
|
|
|
private int blendColors(int color1, int color2, float value) {
|
|
int i = color1 >> 24 & 255;
|
|
int j = color1 >> 16 & 255;
|
|
int k = color1 >> 8 & 255;
|
|
int l = color1 & 255;
|
|
int i1 = color2 >> 24 & 255;
|
|
int j1 = color2 >> 16 & 255;
|
|
int k1 = color2 >> 8 & 255;
|
|
int l1 = color2 & 255;
|
|
int i2 = ExtMath.clampi((int)((float)i + (float)(i1 - i) * value), 0, 255);
|
|
int j2 = ExtMath.clampi((int)((float)j + (float)(j1 - j) * value), 0, 255);
|
|
int k2 = ExtMath.clampi((int)((float)k + (float)(k1 - k) * value), 0, 255);
|
|
int l2 = ExtMath.clampi((int)((float)l + (float)(l1 - l) * value), 0, 255);
|
|
return i2 << 24 | j2 << 16 | k2 << 8 | l2;
|
|
}
|
|
|
|
private int getFrameColor(int value, int base, int mid, int high) {
|
|
value = ExtMath.clampi(value, base, high);
|
|
return value < mid ? this.blendColors(-16711936, -256, (float)value / (float)mid)
|
|
: this.blendColors(-256, -65536, (float)(value - mid) / (float)(high - mid));
|
|
}
|
|
|
|
private void renderLagometer() {
|
|
int w = this.fbX;
|
|
int h = this.fbY;
|
|
int shifted = this.lastIndex;
|
|
int x = 0;
|
|
Drawing.drawRect(0, h - 74, 240, 60, 0x90505050);
|
|
|
|
Drawing.drawRect(0, h - 44, 240, 1, 0x5fffffff);
|
|
Drawing.drawRect(0, h - 74, 240, 1, 0x5fffffff);
|
|
|
|
while(shifted != this.frameIndex) {
|
|
int value = (int) (this.frames[shifted] / 1000000L); // , 30);
|
|
int color = this.getFrameColor(value, 0, 17, 67);
|
|
if(value > 0)
|
|
Drawing.drawRect(x, h - 14 - value, 1, value, color & 0xc0ffffff);
|
|
++x;
|
|
shifted = (shifted + 1) % 240;
|
|
}
|
|
|
|
Drawing.drawText("30ms", 2, h - 30 - 14, 0xffE0E0E0);
|
|
Drawing.drawText("60ms", 2, h - 60 - 14, 0xffE0E0E0);
|
|
Drawing.drawTextRight("ms/Frame", 238, h - 60 - 14, 0xffE0E0E0);
|
|
|
|
if(this.lastTickTime >= 0) {
|
|
this.updateTick();
|
|
Drawing.drawRect(w - 240, h - 74, 240, 60, 0x90505050);
|
|
x = w - 240;
|
|
|
|
Drawing.drawRect(w - 240, h - 44, 240, 1, 0x5fffffff);
|
|
Drawing.drawRect(w - 240, h - 74, 240, 1, 0x5fffffff);
|
|
|
|
for (int n = 0; n < 240; ++n)
|
|
{
|
|
int value = this.tickTimes[(n + this.tickIndex) % 240];
|
|
int color = this.getFrameColor(value, 0, 50, 250);
|
|
if(value > 0)
|
|
Drawing.drawRect(x, h - 14 - value, 1, value, color & 0xc0ffffff);
|
|
++x;
|
|
shifted = (shifted + 1) % 240;
|
|
}
|
|
|
|
Drawing.drawText("30ms", w - 240 + 2, h - 30 - 14, 0xffE0E0E0);
|
|
Drawing.drawText("60ms", w - 240 + 2, h - 60 - 14, 0xffE0E0E0);
|
|
Drawing.drawTextRight("ms/Tick", w - 2, h - 60 - 14, 0xffE0E0E0);
|
|
}
|
|
}
|
|
|
|
public static enum FileMode {
|
|
DIRECTORY_LOAD,
|
|
DIRECTORY_SAVE,
|
|
FILE_LOAD,
|
|
FILE_LOAD_MULTI,
|
|
FILE_SAVE;
|
|
}
|
|
|
|
public void showFileDialog(final FileMode mode, final String title, final File def, final FileCallback callback) {
|
|
if(this.waitingForFile)
|
|
return;
|
|
this.waitingForFile = true;
|
|
new Thread(new Runnable() {
|
|
public void run() {
|
|
String output = null;
|
|
JFileChooser chooser = null;
|
|
try {
|
|
if(Util.WINDOWS)
|
|
throw new RuntimeException("Windows wird von Zenity nicht unterstützt");
|
|
List<String> list = Lists.newArrayList("zenity", "--file-selection");
|
|
switch(mode) {
|
|
case DIRECTORY_SAVE:
|
|
list.add("--save");
|
|
case DIRECTORY_LOAD:
|
|
list.add("--directory");
|
|
break;
|
|
case FILE_SAVE:
|
|
list.add("--save");
|
|
break;
|
|
case FILE_LOAD_MULTI:
|
|
list.add("--multiple");
|
|
list.add("--separator");
|
|
list.add(":");
|
|
break;
|
|
}
|
|
list.add("--title");
|
|
list.add(title);
|
|
if(def != null) {
|
|
list.add("--filename");
|
|
list.add(def.isDirectory() ? def.getAbsolutePath() + File.separator + "__THISFILEDOESNOTEXIST__" : def.getAbsolutePath());
|
|
}
|
|
Process proc = Runtime.getRuntime().exec(list.toArray(new String[list.size()]));
|
|
BufferedReader buf = new BufferedReader(new InputStreamReader(new BufferedInputStream(proc.getInputStream())));
|
|
proc.waitFor();
|
|
output = buf.readLine();
|
|
try {
|
|
buf.close();
|
|
}
|
|
catch(Throwable e) {
|
|
}
|
|
}
|
|
catch(Throwable e) {
|
|
Log.SYSTEM.error(e, "Konnte Dateibrowser nicht starten");
|
|
chooser = new JFileChooser(def.isDirectory() ? def : def.getParentFile());
|
|
chooser.setDialogTitle(title);
|
|
chooser.setMultiSelectionEnabled(mode == FileMode.FILE_LOAD_MULTI);
|
|
chooser.setFileSelectionMode(mode == FileMode.DIRECTORY_LOAD || mode == FileMode.DIRECTORY_SAVE ? JFileChooser.DIRECTORIES_ONLY : JFileChooser.FILES_ONLY);
|
|
int result;
|
|
if(mode == FileMode.FILE_SAVE || mode == FileMode.DIRECTORY_SAVE)
|
|
result = chooser.showSaveDialog(null);
|
|
else
|
|
result = chooser.showOpenDialog(null);
|
|
if(result != JFileChooser.APPROVE_OPTION) {
|
|
Client.this.waitingForFile = false;
|
|
return;
|
|
}
|
|
}
|
|
if(output == null && chooser == null) {
|
|
Client.this.waitingForFile = false;
|
|
return;
|
|
}
|
|
if(mode == FileMode.FILE_LOAD_MULTI) {
|
|
final List<File> files = Lists.newArrayList();
|
|
if(chooser != null) {
|
|
for(File file : chooser.getSelectedFiles()) {
|
|
if(file.isFile())
|
|
files.add(file);
|
|
}
|
|
}
|
|
else {
|
|
for(String out : output.split(":")) {
|
|
File file = new File(out);
|
|
if(file.isFile())
|
|
files.add(file);
|
|
}
|
|
}
|
|
if(files.isEmpty()) {
|
|
Client.this.waitingForFile = false;
|
|
return;
|
|
}
|
|
Client.this.schedule(new Runnable() {
|
|
public void run() {
|
|
if(Client.this.waitingForFile) {
|
|
for(File file : files) {
|
|
callback.selected(file);
|
|
}
|
|
}
|
|
Client.this.waitingForFile = false;
|
|
}
|
|
});
|
|
}
|
|
else {
|
|
File file = chooser != null ? chooser.getSelectedFile() : new File(output);
|
|
switch(mode) {
|
|
case DIRECTORY_LOAD:
|
|
if(!file.isDirectory()) {
|
|
Client.this.waitingForFile = false;
|
|
return;
|
|
}
|
|
break;
|
|
case DIRECTORY_SAVE:
|
|
if(file.exists() && !file.isDirectory()) {
|
|
Client.this.waitingForFile = false;
|
|
return;
|
|
}
|
|
break;
|
|
case FILE_LOAD:
|
|
if(!file.isFile()) {
|
|
Client.this.waitingForFile = false;
|
|
return;
|
|
}
|
|
break;
|
|
case FILE_SAVE:
|
|
if(file.exists() && !file.isFile()) {
|
|
Client.this.waitingForFile = false;
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
Client.this.schedule(new Runnable() {
|
|
public void run() {
|
|
if(Client.this.waitingForFile)
|
|
callback.selected(file);
|
|
Client.this.waitingForFile = false;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}, "File Browser listener").start();
|
|
}
|
|
|
|
public Object getSyncedVar(String name) {
|
|
Field field = this.synced.get(name);
|
|
if(field != null) {
|
|
try {
|
|
return field.get(null);
|
|
}
|
|
catch(IllegalArgumentException | IllegalAccessException e) {
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public void setSyncedVar(String name, Object value) {
|
|
Field field = this.synced.get(name);
|
|
if(field != null) {
|
|
try {
|
|
field.set(null, value);
|
|
}
|
|
catch(Throwable e) {
|
|
return;
|
|
}
|
|
Log.NETWORK.debug("Variable %s = %s", name, value);
|
|
}
|
|
}
|
|
|
|
private void displayTick(int posX, int posY, int posZ) {
|
|
int range = 16;
|
|
Random rand = new Random();
|
|
MutablePos pos = new MutablePos();
|
|
for(int n = 0; n < 1000; n++) {
|
|
int x = posX + rand.zrange(range) - rand.zrange(range);
|
|
int y = posY + rand.zrange(range) - rand.zrange(range);
|
|
int z = posZ + rand.zrange(range) - rand.zrange(range);
|
|
pos.set(x, y, z);
|
|
State state = this.world.getState(pos);
|
|
state.getBlock().displayTick(this.world, pos, state, rand);
|
|
}
|
|
if(this.world.dimension.hasVoidFog() && this.voidParticles && posY < 32) {
|
|
for(int n = 0; n < 1000; n++) {
|
|
float x = ((float)posX) + (rand.floatv() - rand.floatv() - 0.5f) * 32.0f;
|
|
float y = (posY < -32 ? (float)posY - 32.0f : -64.0f) + rand.floatv() * 65.0f;
|
|
float z = ((float)posZ) + (rand.floatv() - rand.floatv() - 0.5f) * 32.0f;
|
|
if(y < -64.0f || rand.floatv() >= (64.0f + y) / 64.0f)
|
|
this.world.clientParticle(ParticleType.DEPTH, (double)x, (double)y, (double)z);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void initWorld() {
|
|
this.emptyChunk = new ChunkEmpty(this.world, false, this.debugWorld);
|
|
this.outsideChunk = new ChunkEmpty(this.world, true, this.debugWorld);
|
|
}
|
|
|
|
private void resetWorld() {
|
|
this.entityList.clear();
|
|
this.chunkMapping.clear();
|
|
this.emptyChunkListing.clear();
|
|
this.nextEmptyChunkListing.clear();
|
|
this.emptyChunk = null;
|
|
this.outsideChunk = null;
|
|
this.renderer.resetLightning();
|
|
this.entities = null;
|
|
this.unloaded = null;
|
|
this.tiles = null;
|
|
this.entityIds = null;
|
|
}
|
|
|
|
public ChunkClient getChunk(int x, int z) {
|
|
ChunkClient chunk = this.chunkMapping.getValueByKey(LongHashMap.packInt(x, z));
|
|
return chunk == null ? this.getEmptyChunk(x, z) : chunk;
|
|
}
|
|
|
|
private ChunkClient getEmptyChunk(int x, int z) {
|
|
int size = this.world.dimension.getSize() / 16;
|
|
return x < -size || z < -size || x >= size || z >= size ? this.outsideChunk : this.emptyChunk;
|
|
}
|
|
|
|
public void markBlockRangeForRenderUpdate(int x1, int y1, int z1, int x2, int y2, int z2) {
|
|
this.renderer.markUpdate(x1 - 1, y1 - 1, z1 - 1, x2 + 1, y2 + 1, z2 + 1);
|
|
}
|
|
|
|
private void markReload(int cx, int cz, int range) {
|
|
this.nextEmptyChunkListing.clear();
|
|
for(int x = cx - range; x <= cx + range; x++) {
|
|
for(int z = cz - range; z <= cz + range; z++) {
|
|
long id = LongHashMap.packInt(x, z);
|
|
if(this.chunkMapping.getValueByKey(id) != null) {
|
|
if(this.emptyChunkListing.contains(id)) {
|
|
this.emptyChunkListing.remove(id);
|
|
this.nextEmptyChunkListing.add(id);
|
|
}
|
|
continue;
|
|
}
|
|
this.chunkMapping.add(id, this.getEmptyChunk(x, z));
|
|
this.emptyChunkListing.remove(id);
|
|
this.nextEmptyChunkListing.add(id);
|
|
this.markBlockRangeForRenderUpdate(x << 4, -World.MAX_SIZE_Y, z << 4, (x << 4) + 15, World.MAX_SIZE_Y, (z << 4) + 15);
|
|
}
|
|
}
|
|
for(Long id : this.emptyChunkListing) {
|
|
this.chunkMapping.remove(id);
|
|
int x = LongHashMap.getX(id);
|
|
int z = LongHashMap.getZ(id);
|
|
this.markBlockRangeForRenderUpdate(x << 4, -World.MAX_SIZE_Y, z << 4, (x << 4) + 15, World.MAX_SIZE_Y, (z << 4) + 15);
|
|
}
|
|
this.emptyChunkListing.clear();
|
|
this.emptyChunkListing.addAll(this.nextEmptyChunkListing);
|
|
}
|
|
|
|
public void markReload() {
|
|
if(this.player != null && !this.charEditor)
|
|
this.markReload((int)this.player.posX >> 4, (int)this.player.posZ >> 4, this.renderDistance + 4);
|
|
}
|
|
|
|
public void setExterminated(boolean exterminated) {
|
|
this.world.dimension.setExterminated(exterminated);
|
|
this.initWorld();
|
|
this.markReload();
|
|
for(Long id : this.emptyChunkListing) {
|
|
int x = LongHashMap.getX(id);
|
|
int z = LongHashMap.getZ(id);
|
|
this.chunkMapping.add(id, this.getEmptyChunk(x, z));
|
|
this.markBlockRangeForRenderUpdate(x << 4, -World.MAX_SIZE_Y, z << 4, (x << 4) + 15, World.MAX_SIZE_Y, (z << 4) + 15);
|
|
}
|
|
}
|
|
|
|
public void doPreChunk(int x, int z, boolean load)
|
|
{
|
|
long id = LongHashMap.packInt(x, z);
|
|
if (load)
|
|
{
|
|
if(this.chunkMapping.getValueByKey(id) != null)
|
|
this.doPreChunk(x, z, false);
|
|
ChunkClient chunk = new ChunkClient(this.world, x, z);
|
|
this.chunkMapping.add(id, chunk);
|
|
chunk.setLoaded();
|
|
}
|
|
else
|
|
{
|
|
ChunkClient chunk = this.getChunk(x, z);
|
|
chunk.onChunkUnload();
|
|
this.chunkMapping.remove(id);
|
|
this.emptyChunkListing.remove(id);
|
|
}
|
|
|
|
if (!load)
|
|
{
|
|
this.markBlockRangeForRenderUpdate(x * 16, -World.MAX_SIZE_Y, z * 16, x * 16 + 15, World.MAX_SIZE_Y, z * 16 + 15);
|
|
}
|
|
}
|
|
|
|
public void addEntityToWorld(int entityID, Entity entityToSpawn)
|
|
{
|
|
Entity entity = this.world.getEntityByID(entityID);
|
|
|
|
if (entity != null)
|
|
{
|
|
this.world.removeEntity(entity);
|
|
this.entityList.remove(entity);
|
|
}
|
|
|
|
this.entityList.add(entityToSpawn);
|
|
entityToSpawn.setId(entityID);
|
|
|
|
this.spawnEntity(entityToSpawn);
|
|
|
|
this.entityIds.addKey(entityID, entityToSpawn);
|
|
}
|
|
|
|
public Entity removeEntityFromWorld(int entityID)
|
|
{
|
|
Entity entity = this.entityIds.removeObject(entityID);
|
|
|
|
if (entity != null)
|
|
{
|
|
this.entityList.remove(entity);
|
|
this.world.removeEntity(entity);
|
|
this.entityList.remove(entity);
|
|
}
|
|
|
|
return entity;
|
|
}
|
|
|
|
private void removeAllEntities()
|
|
{
|
|
this.entities.removeAll(this.unloaded);
|
|
|
|
for (int i = 0; i < this.unloaded.size(); ++i)
|
|
{
|
|
Entity entity = this.unloaded.get(i);
|
|
int j = entity.chunkCoordX;
|
|
int k = entity.chunkCoordZ;
|
|
|
|
if (entity.addedToChunk)
|
|
{
|
|
this.getChunk(j, k).removeEntity(entity);
|
|
}
|
|
}
|
|
|
|
for (int l = 0; l < this.unloaded.size(); ++l)
|
|
{
|
|
Entity entity2 = this.unloaded.get(l);
|
|
if(this.entityList.contains(entity2)) {
|
|
if(!entity2.isEntityAlive())
|
|
this.entityList.remove(entity2);
|
|
}
|
|
}
|
|
|
|
this.unloaded.clear();
|
|
|
|
for (int i1 = 0; i1 < this.entities.size(); ++i1)
|
|
{
|
|
Entity entity1 = this.entities.get(i1);
|
|
|
|
if (entity1.vehicle != null)
|
|
{
|
|
if (!entity1.vehicle.dead && entity1.vehicle.passenger == entity1)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
entity1.vehicle.passenger = null;
|
|
entity1.vehicle = null;
|
|
}
|
|
|
|
if (entity1.dead)
|
|
{
|
|
int j1 = entity1.chunkCoordX;
|
|
int k1 = entity1.chunkCoordZ;
|
|
|
|
if (entity1.addedToChunk)
|
|
{
|
|
this.getChunk(j1, k1).removeEntity(entity1);
|
|
}
|
|
|
|
this.entities.remove(i1--);
|
|
if(this.entityList.contains(entity1))
|
|
Client.this.entityList.remove(entity1);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void spawnEntity(Entity entityIn) {
|
|
boolean flag = this.world.spawnEntityInWorld(entityIn);
|
|
this.entityList.add(entityIn);
|
|
if(flag && entityIn instanceof EntityCart cart)
|
|
this.soundManager.playSound(new MovingSoundMinecart(cart));
|
|
}
|
|
|
|
private void ensureAreaLoaded(Entity entity) {
|
|
int x = ExtMath.floord(entity.posX / 16.0D);
|
|
int z = ExtMath.floord(entity.posZ / 16.0D);
|
|
int r = 2;
|
|
for(int cx = x - r; cx <= x + r; ++cx) {
|
|
for(int cz = z - r; cz <= z + r; ++cz) {
|
|
this.getChunk(cx, cz);
|
|
}
|
|
}
|
|
if(!this.entities.contains(entity))
|
|
this.entities.add(entity);
|
|
}
|
|
|
|
public List<Entity> getEntities() {
|
|
return this.entities;
|
|
}
|
|
|
|
public List<TileEntity> getTiles() {
|
|
return this.tiles;
|
|
}
|
|
|
|
private static byte[] genTriwave(int w, int h, int color1, int color2, int color3, int color4, int color5, int color6) {
|
|
byte[] data = new byte[w * h * 4];
|
|
byte[] color = new byte[24];
|
|
color1 = (color1 << 8) | (color1 >>> 24);
|
|
color2 = (color2 << 8) | (color2 >>> 24);
|
|
color3 = (color3 << 8) | (color3 >>> 24);
|
|
color4 = (color4 << 8) | (color4 >>> 24);
|
|
color5 = (color5 << 8) | (color5 >>> 24);
|
|
color6 = (color6 << 8) | (color6 >>> 24);
|
|
for(int z = 0; z < 4; z++) {
|
|
color[z] = (byte)((color1 >> ((3 - z) * 8)) & 0xff);
|
|
color[z+4] = (byte)((color2 >> ((3 - z) * 8)) & 0xff);
|
|
color[z+8] = (byte)((color3 >> ((3 - z) * 8)) & 0xff);
|
|
color[z+12] = (byte)((color4 >> ((3 - z) * 8)) & 0xff);
|
|
color[z+16] = (byte)((color5 >> ((3 - z) * 8)) & 0xff);
|
|
color[z+20] = (byte)((color6 >> ((3 - z) * 8)) & 0xff);
|
|
}
|
|
for(int y = 0; y < h; y++) {
|
|
int offs = ((y / 2 == h / 16) || (y / 2 == (h / 2 - h / 16) - 1)) ? 16 : (((y / 2 == h / 16 + 1) || (y / 2 == (h / 2 - h / 16) - 2)) ? 20 : 0);
|
|
for(int x = 0; x < w; x++) {
|
|
System.arraycopy(color, offs, data, (y*w+x) << 2, 4);
|
|
}
|
|
}
|
|
for(int x = 0; x < w; x++) {
|
|
float fx = (float)(w / 4 + x);
|
|
float fp = (float)((w * 3) / 4);
|
|
float fa = (float)(((h * 3) / 4) / 2);
|
|
int y = ((x < w / 8) || (x >= w - w / 8)) ? (h / 2) : (h / 2 + (int)(((4.0f * fa) / fp) * ExtMath.absf(((fx - fp / 4.0f) % fp) - fp / 2.0f) - fa));
|
|
System.arraycopy(color, 0, data, ((y-8)*w+x) << 2, 4);
|
|
System.arraycopy(color, 0, data, ((y-7)*w+x) << 2, 4);
|
|
System.arraycopy(color, 0, data, ((y-6)*w+x) << 2, 4);
|
|
System.arraycopy(color, 4, data, ((y-5)*w+x) << 2, 4);
|
|
System.arraycopy(color, 4, data, ((y-4)*w+x) << 2, 4);
|
|
System.arraycopy(color, 0, data, ((y-3)*w+x) << 2, 4);
|
|
System.arraycopy(color, 0, data, ((y-2)*w+x) << 2, 4);
|
|
System.arraycopy(color, 8, data, ((y-1)*w+x) << 2, 4);
|
|
System.arraycopy(color, 8, data, ((y+0)*w+x) << 2, 4);
|
|
System.arraycopy(color, 0, data, ((y+1)*w+x) << 2, 4);
|
|
System.arraycopy(color, 0, data, ((y+2)*w+x) << 2, 4);
|
|
System.arraycopy(color, 12, data, ((y+3)*w+x) << 2, 4);
|
|
System.arraycopy(color, 12, data, ((y+4)*w+x) << 2, 4);
|
|
System.arraycopy(color, 0, data, ((y+5)*w+x) << 2, 4);
|
|
System.arraycopy(color, 0, data, ((y+6)*w+x) << 2, 4);
|
|
System.arraycopy(color, 0, data, ((y+7)*w+x) << 2, 4);
|
|
}
|
|
return data;
|
|
}
|
|
}
|