Added GUI components for gun ammo, and rifle sound.
This commit is contained in:
parent
b88150fd3e
commit
219ccd94db
|
@ -8,6 +8,8 @@ import nl.andrewl.aos2_client.control.PlayerViewCursorCallback;
|
|||
import nl.andrewl.aos2_client.model.ClientPlayer;
|
||||
import nl.andrewl.aos2_client.model.OtherPlayer;
|
||||
import nl.andrewl.aos2_client.render.GameRenderer;
|
||||
import nl.andrewl.aos2_client.sound.SoundManager;
|
||||
import nl.andrewl.aos2_client.sound.SoundSource;
|
||||
import nl.andrewl.aos_core.config.Config;
|
||||
import nl.andrewl.aos_core.model.Player;
|
||||
import nl.andrewl.aos_core.model.Team;
|
||||
|
@ -34,6 +36,8 @@ public class Client implements Runnable {
|
|||
private final CommunicationHandler communicationHandler;
|
||||
private final InputHandler inputHandler;
|
||||
private GameRenderer gameRenderer;
|
||||
private SoundManager soundManager;
|
||||
private SoundSource playerSource;
|
||||
private long lastPlayerUpdate = 0;
|
||||
|
||||
private ClientWorld world;
|
||||
|
@ -81,6 +85,9 @@ public class Client implements Runnable {
|
|||
new PlayerInputKeyCallback(inputHandler),
|
||||
new PlayerInputMouseClickCallback(inputHandler)
|
||||
);
|
||||
soundManager = new SoundManager();
|
||||
soundManager.load("rifle", "sound/m1garand-shot1.wav");
|
||||
playerSource = new SoundSource();
|
||||
|
||||
long lastFrameAt = System.currentTimeMillis();
|
||||
while (!gameRenderer.windowShouldClose()) {
|
||||
|
@ -113,6 +120,7 @@ public class Client implements Runnable {
|
|||
if (gameRenderer != null) {
|
||||
gameRenderer.getCamera().setToPlayer(myPlayer);
|
||||
}
|
||||
soundManager.updateListener(myPlayer.getPosition(), myPlayer.getVelocity());
|
||||
lastPlayerUpdate = playerUpdate.timestamp();
|
||||
} else {
|
||||
OtherPlayer p = players.get(playerUpdate.clientId());
|
||||
|
@ -141,6 +149,8 @@ public class Client implements Runnable {
|
|||
players.put(op.getId(), op);
|
||||
} else if (msg instanceof PlayerLeaveMessage leaveMessage) {
|
||||
players.remove(leaveMessage.id());
|
||||
} else if (msg instanceof SoundMessage soundMessage) {
|
||||
playerSource.play(soundManager.getSoundBuffer(soundMessage.name()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ public class InputHandler {
|
|||
glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS,
|
||||
glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_1) == GLFW_PRESS,
|
||||
glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_2) == GLFW_PRESS,
|
||||
glfwGetKey(window, GLFW_KEY_R) == GLFW_PRESS,
|
||||
selectedInventoryIndex
|
||||
);
|
||||
if (!currentInputState.equals(lastInputState)) {
|
||||
|
|
|
@ -8,6 +8,8 @@ import nl.andrewl.aos2_client.render.gui.GUIRenderer;
|
|||
import nl.andrewl.aos2_client.render.gui.GUITexture;
|
||||
import nl.andrewl.aos2_client.render.model.Model;
|
||||
import nl.andrewl.aos_core.model.item.BlockItemStack;
|
||||
import nl.andrewl.aos_core.model.item.Gun;
|
||||
import nl.andrewl.aos_core.model.item.GunItemStack;
|
||||
import nl.andrewl.aos_core.model.item.ItemTypes;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Vector3f;
|
||||
|
@ -44,6 +46,11 @@ public class GameRenderer {
|
|||
private Model rifleModel;
|
||||
private Model blockModel;
|
||||
|
||||
// Standard GUI textures.
|
||||
private GUITexture crosshairTexture;
|
||||
private GUITexture clipTexture;
|
||||
private GUITexture bulletTexture;
|
||||
|
||||
private long windowHandle;
|
||||
private int screenWidth = 800;
|
||||
private int screenHeight = 600;
|
||||
|
@ -110,17 +117,16 @@ public class GameRenderer {
|
|||
|
||||
this.chunkRenderer = new ChunkRenderer();
|
||||
log.debug("Initialized chunk renderer.");
|
||||
|
||||
this.guiRenderer = new GUIRenderer();
|
||||
// TODO: More organized way to load textures for GUI.
|
||||
try {
|
||||
var crosshairTexture = new GUITexture("gui/crosshair.png");
|
||||
float size = 32;
|
||||
crosshairTexture.getScale().set(size / screenWidth, size / screenHeight);
|
||||
guiRenderer.addTexture(crosshairTexture);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
crosshairTexture = new GUITexture("gui/crosshair.png");
|
||||
clipTexture = new GUITexture("gui/clip.png");
|
||||
bulletTexture = new GUITexture("gui/bullet.png");
|
||||
guiRenderer.addTexture("crosshair", crosshairTexture);
|
||||
guiRenderer.addTexture("clip", clipTexture);
|
||||
guiRenderer.addTexture("bullet", bulletTexture);
|
||||
log.debug("Initialized GUI renderer.");
|
||||
|
||||
this.modelRenderer = new ModelRenderer();
|
||||
try {
|
||||
playerModel = new Model("model/player_simple.obj", "model/simple_player.png");
|
||||
|
@ -212,7 +218,32 @@ public class GameRenderer {
|
|||
|
||||
modelRenderer.end();
|
||||
|
||||
guiRenderer.draw();
|
||||
// GUI rendering
|
||||
guiRenderer.start();
|
||||
guiRenderer.draw(crosshairTexture, crosshairTexture.getIdealScaleX(32, screenWidth), crosshairTexture.getIdealScaleY(32, screenHeight), 0, 0);
|
||||
// If we're holding a gun, draw clip and bullet graphics.
|
||||
if (client.getMyPlayer().getInventory().getSelectedItemStack().getType() instanceof Gun) {
|
||||
GunItemStack stack = (GunItemStack) client.getMyPlayer().getInventory().getSelectedItemStack();
|
||||
for (int i = 0; i < stack.getClipCount(); i++) {
|
||||
guiRenderer.draw(
|
||||
clipTexture,
|
||||
clipTexture.getIdealScaleX(64, screenWidth),
|
||||
clipTexture.getIdealScaleY(clipTexture.getIdealHeight(64), screenHeight),
|
||||
0.90f,
|
||||
-0.90f + (i * 0.15f)
|
||||
);
|
||||
}
|
||||
for (int i = 0; i < stack.getBulletCount(); i++) {
|
||||
guiRenderer.draw(
|
||||
bulletTexture,
|
||||
bulletTexture.getIdealScaleX(16, screenWidth),
|
||||
bulletTexture.getIdealScaleY(bulletTexture.getIdealHeight(16), screenHeight),
|
||||
0.80f - (i * 0.05f),
|
||||
-0.90f
|
||||
);
|
||||
}
|
||||
}
|
||||
guiRenderer.end();
|
||||
|
||||
glfwSwapBuffers(windowHandle);
|
||||
glfwPollEvents();
|
||||
|
|
|
@ -5,8 +5,8 @@ import org.joml.Matrix4f;
|
|||
import org.lwjgl.BufferUtils;
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.lwjgl.opengl.GL46.*;
|
||||
|
||||
|
@ -19,9 +19,10 @@ public class GUIRenderer {
|
|||
private final int vertexCount;
|
||||
private final ShaderProgram shaderProgram;
|
||||
private final int transformUniformLocation;
|
||||
private final Matrix4f transformMatrix;
|
||||
private final float[] transformMatrixData;
|
||||
|
||||
|
||||
private final List<GUITexture> guiTextures = new ArrayList<>();
|
||||
private final Map<String, GUITexture> textures = new HashMap<>();
|
||||
|
||||
public GUIRenderer() {
|
||||
vaoId = glGenVertexArrays();
|
||||
|
@ -47,38 +48,52 @@ public class GUIRenderer {
|
|||
.build();
|
||||
transformUniformLocation = shaderProgram.getUniform("transform");
|
||||
shaderProgram.bindAttribute(0, "position");
|
||||
this.transformMatrix = new Matrix4f();
|
||||
this.transformMatrixData = new float[16];
|
||||
}
|
||||
|
||||
public void addTexture(GUITexture texture) {
|
||||
guiTextures.add(texture);
|
||||
public void loadTexture(String name, String resource) {
|
||||
textures.put(name, new GUITexture(resource));
|
||||
}
|
||||
|
||||
public void draw() {
|
||||
public void addTexture(String name, GUITexture texture) {
|
||||
textures.put(name, texture);
|
||||
}
|
||||
|
||||
public void start() {
|
||||
shaderProgram.use();
|
||||
glBindVertexArray(vaoId);
|
||||
glEnableVertexAttribArray(0);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
for (var texture : guiTextures) {
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
Matrix4f transform = new Matrix4f()
|
||||
.translate(texture.getPosition().x, texture.getPosition().y, 0)
|
||||
.scale(texture.getScale().x, texture.getScale().y, 1);
|
||||
float[] transformData = new float[16];
|
||||
transform.get(transformData);
|
||||
glUniformMatrix4fv(transformUniformLocation, false, transformData);
|
||||
}
|
||||
|
||||
public void draw(String name, float scaleX, float scaleY, float x, float y) {
|
||||
draw(textures.get(name), scaleX, scaleY, x, y);
|
||||
}
|
||||
|
||||
public void draw(GUITexture texture, float scaleX, float scaleY, float x, float y) {
|
||||
glActiveTexture(0);
|
||||
transformMatrix.identity()
|
||||
.translate(x, y, 0)
|
||||
.scale(scaleX, scaleY, 1)
|
||||
.get(transformMatrixData);
|
||||
glUniformMatrix4fv(transformUniformLocation, false, transformMatrixData);
|
||||
glBindTexture(GL_TEXTURE_2D, texture.getTextureId());
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexCount);
|
||||
}
|
||||
|
||||
public void end() {
|
||||
glDisable(GL_BLEND);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDisableVertexAttribArray(0);
|
||||
glBindVertexArray(0);
|
||||
shaderProgram.stopUsing();
|
||||
}
|
||||
|
||||
public void free() {
|
||||
for (var tex : guiTextures) tex.free();
|
||||
for (var tex : textures.values()) tex.free();
|
||||
glDeleteBuffers(vboId);
|
||||
glDeleteVertexArrays(vaoId);
|
||||
shaderProgram.free();
|
||||
|
|
|
@ -2,7 +2,6 @@ package nl.andrewl.aos2_client.render.gui;
|
|||
|
||||
import nl.andrewl.aos_core.ImageUtils;
|
||||
import org.joml.Vector2f;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
@ -10,14 +9,21 @@ import java.io.IOException;
|
|||
|
||||
import static org.lwjgl.opengl.GL46.*;
|
||||
|
||||
/**
|
||||
* Represents a texture loaded onto the GPU.
|
||||
*/
|
||||
public class GUITexture {
|
||||
private final int textureId;
|
||||
/**
|
||||
* The original image's width.
|
||||
*/
|
||||
private final int width;
|
||||
/**
|
||||
* The original image's height.
|
||||
*/
|
||||
private final int height;
|
||||
private final Vector2f position = new Vector2f(0, 0);
|
||||
private final Vector2f scale = new Vector2f(1, 1);
|
||||
|
||||
public GUITexture(String location) throws IOException {
|
||||
public GUITexture(String location) {
|
||||
try (var in = GUITexture.class.getClassLoader().getResourceAsStream(location)) {
|
||||
if (in == null) throw new IOException("Couldn't load texture image from " + location);
|
||||
BufferedImage img = ImageIO.read(in);
|
||||
|
@ -31,21 +37,43 @@ public class GUITexture {
|
|||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
var buf = ImageUtils.decodePng(img);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buf);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to load GUI texture.", e);
|
||||
}
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public float getAspectRatio() {
|
||||
return (float) width / height;
|
||||
}
|
||||
|
||||
public float getIdealHeight(float width) {
|
||||
return width / getAspectRatio();
|
||||
}
|
||||
|
||||
public float getIdealWidth(float height) {
|
||||
return height * getAspectRatio();
|
||||
}
|
||||
|
||||
public float getIdealScaleX(float desiredWidth, float screenWidth) {
|
||||
return desiredWidth / screenWidth;
|
||||
}
|
||||
|
||||
public float getIdealScaleY(float desiredHeight, float screenHeight) {
|
||||
return desiredHeight / screenHeight;
|
||||
}
|
||||
|
||||
public int getTextureId() {
|
||||
return textureId;
|
||||
}
|
||||
|
||||
public Vector2f getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public Vector2f getScale() {
|
||||
return scale;
|
||||
}
|
||||
|
||||
public void free() {
|
||||
glDeleteTextures(textureId);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
package nl.andrewl.aos2_client.sound;
|
||||
|
||||
import nl.andrewl.aos2_client.model.ClientPlayer;
|
||||
import org.joml.Vector3f;
|
||||
import org.lwjgl.openal.AL;
|
||||
import org.lwjgl.openal.ALC;
|
||||
import org.lwjgl.openal.ALCCapabilities;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.lwjgl.openal.ALC10.*;
|
||||
import static org.lwjgl.openal.AL10.*;
|
||||
|
||||
public class SoundManager {
|
||||
private final long alContext;
|
||||
private final Map<String, Integer> audioBuffers = new HashMap<>();
|
||||
|
||||
public SoundManager() {
|
||||
long device = alcOpenDevice((ByteBuffer) null);
|
||||
ALCCapabilities capabilities = ALC.createCapabilities(device);
|
||||
alContext = alcCreateContext(device, (IntBuffer) null);
|
||||
alcMakeContextCurrent(alContext);
|
||||
AL.createCapabilities(capabilities);
|
||||
|
||||
}
|
||||
|
||||
public void load(String name, String resource) {
|
||||
int bufferId = alGenBuffers();
|
||||
audioBuffers.put(name, bufferId);
|
||||
WaveData waveData = WaveData.create(resource);
|
||||
alBufferData(bufferId, waveData.format, waveData.data, waveData.samplerate);
|
||||
waveData.dispose();
|
||||
}
|
||||
|
||||
public void updateListener(Vector3f position, Vector3f velocity) {
|
||||
alListener3f(AL_POSITION, position.x(), position.y(), position.z());
|
||||
alListener3f(AL_VELOCITY, velocity.x(), velocity.y(), velocity.z());
|
||||
}
|
||||
|
||||
public int getSoundBuffer(String name) {
|
||||
return audioBuffers.get(name);
|
||||
}
|
||||
|
||||
public void free() {
|
||||
for (var bufferId : audioBuffers.values()) {
|
||||
alDeleteBuffers(bufferId);
|
||||
}
|
||||
alcDestroyContext(alContext);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package nl.andrewl.aos2_client.sound;
|
||||
|
||||
import static org.lwjgl.openal.AL10.*;
|
||||
|
||||
public class SoundSource {
|
||||
private final int sourceId;
|
||||
|
||||
public SoundSource() {
|
||||
sourceId = alGenSources();
|
||||
alSourcef(sourceId, AL_GAIN, 1);
|
||||
alSourcef(sourceId, AL_PITCH, 1);
|
||||
alSource3f(sourceId, AL_POSITION, 0, 0, 0);
|
||||
}
|
||||
|
||||
public void play(int bufferId) {
|
||||
alSourcei(sourceId, AL_BUFFER, bufferId);
|
||||
alSourcePlay(sourceId);
|
||||
}
|
||||
|
||||
public void free() {
|
||||
alDeleteSources(sourceId);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
package nl.andrewl.aos2_client.sound;
|
||||
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.openal.AL10;
|
||||
|
||||
import javax.sound.sampled.AudioFormat;
|
||||
import javax.sound.sampled.AudioInputStream;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.UnsupportedAudioFileException;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class WaveData {
|
||||
|
||||
final int format;
|
||||
final int samplerate;
|
||||
final int totalBytes;
|
||||
final int bytesPerFrame;
|
||||
final ByteBuffer data;
|
||||
|
||||
private final AudioInputStream audioStream;
|
||||
private final byte[] dataArray;
|
||||
|
||||
private WaveData(AudioInputStream stream) {
|
||||
this.audioStream = stream;
|
||||
AudioFormat audioFormat = stream.getFormat();
|
||||
format = getOpenAlFormat(audioFormat.getChannels(), audioFormat.getSampleSizeInBits());
|
||||
this.samplerate = (int) audioFormat.getSampleRate();
|
||||
this.bytesPerFrame = audioFormat.getFrameSize();
|
||||
this.totalBytes = (int) (stream.getFrameLength() * bytesPerFrame);
|
||||
this.data = BufferUtils.createByteBuffer(totalBytes);
|
||||
this.dataArray = new byte[totalBytes];
|
||||
loadData();
|
||||
}
|
||||
|
||||
protected void dispose() {
|
||||
try {
|
||||
audioStream.close();
|
||||
data.clear();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private ByteBuffer loadData() {
|
||||
try {
|
||||
int bytesRead = audioStream.read(dataArray, 0, totalBytes);
|
||||
data.clear();
|
||||
data.put(dataArray, 0, bytesRead);
|
||||
data.flip();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
System.err.println("Couldn't read bytes from audio stream!");
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
public static WaveData create(String file){
|
||||
InputStream stream = WaveData.class.getClassLoader().getResourceAsStream(file);
|
||||
if (stream == null) {
|
||||
System.err.println("Couldn't find file: " + file);
|
||||
return null;
|
||||
}
|
||||
InputStream bufferedInput = new BufferedInputStream(stream);
|
||||
AudioInputStream audioStream;
|
||||
try {
|
||||
audioStream = AudioSystem.getAudioInputStream(bufferedInput);
|
||||
} catch (UnsupportedAudioFileException | IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return new WaveData(audioStream);
|
||||
}
|
||||
|
||||
|
||||
private static int getOpenAlFormat(int channels, int bitsPerSample) {
|
||||
if (channels == 1) {
|
||||
return bitsPerSample == 8 ? AL10.AL_FORMAT_MONO8 : AL10.AL_FORMAT_MONO16;
|
||||
} else {
|
||||
return bitsPerSample == 8 ? AL10.AL_FORMAT_STEREO8 : AL10.AL_FORMAT_STEREO16;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
Binary file not shown.
|
@ -42,6 +42,7 @@ public final class Net {
|
|||
serializer.registerTypeSerializer(13, new InventorySerializer());
|
||||
serializer.registerTypeSerializer(14, new ItemStackSerializer());
|
||||
serializer.registerType(15, InventorySelectedStackMessage.class);
|
||||
serializer.registerType(16, SoundMessage.class);
|
||||
}
|
||||
|
||||
public static ExtendedDataInputStream getInputStream(InputStream in) {
|
||||
|
|
|
@ -14,6 +14,7 @@ public class Gun extends Item {
|
|||
private final float reloadTime;
|
||||
private final float baseDamage;
|
||||
private final float recoil;
|
||||
private boolean automatic;
|
||||
|
||||
public Gun(
|
||||
int id,
|
||||
|
@ -25,7 +26,8 @@ public class Gun extends Item {
|
|||
float shotCooldownTime,
|
||||
float reloadTime,
|
||||
float baseDamage,
|
||||
float recoil
|
||||
float recoil,
|
||||
boolean automatic
|
||||
) {
|
||||
super(id, name, 1);
|
||||
this.maxClipCount = maxClipCount;
|
||||
|
@ -36,6 +38,7 @@ public class Gun extends Item {
|
|||
this.reloadTime = reloadTime;
|
||||
this.baseDamage = baseDamage;
|
||||
this.recoil = recoil;
|
||||
this.automatic = automatic;
|
||||
}
|
||||
|
||||
public int getMaxClipCount() {
|
||||
|
@ -69,4 +72,8 @@ public class Gun extends Item {
|
|||
public float getRecoil() {
|
||||
return recoil;
|
||||
}
|
||||
|
||||
public boolean isAutomatic() {
|
||||
return automatic;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,8 @@ public class Rifle extends Gun {
|
|||
0.8f,
|
||||
2.5f,
|
||||
80f,
|
||||
50f
|
||||
50f,
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,5 +20,6 @@ public record ClientInputState(
|
|||
// Interaction
|
||||
boolean hitting, // Usually a "left-click" action.
|
||||
boolean interacting, // Usually a "right-click" action.
|
||||
boolean reloading, // Usually the "R" key.
|
||||
int selectedInventoryIndex // The selected index in the player's inventory.
|
||||
) implements Message {}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
package nl.andrewl.aos_core.net.client;
|
||||
|
||||
import nl.andrewl.record_net.Message;
|
||||
|
||||
/**
|
||||
* A message that indicates that a sound has been emitted somewhere in the
|
||||
* world, and that clients may need to play the sound.
|
||||
*/
|
||||
public record SoundMessage(
|
||||
String name,
|
||||
float px, float py, float pz
|
||||
) implements Message {}
|
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
|
@ -0,0 +1,79 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="210mm"
|
||||
height="297mm"
|
||||
viewBox="0 0 210 297"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
|
||||
sodipodi:docname="bullet.svg">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.49497475"
|
||||
inkscape:cx="1025.0529"
|
||||
inkscape:cy="684.95586"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1049"
|
||||
inkscape:window-x="1920"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<g
|
||||
id="g827"
|
||||
transform="translate(7.4821434,33.262203)"
|
||||
inkscape:export-xdpi="20.76"
|
||||
inkscape:export-ydpi="20.76">
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path821"
|
||||
d="m 60.476187,95.538688 c 0,-54.617567 37.041667,-82.587796 37.041667,-82.587796 0,0 37.041666,27.970235 37.041666,82.587796"
|
||||
style="fill:#c48916;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<rect
|
||||
ry="2.6458333"
|
||||
rx="2.6458333"
|
||||
y="95.538689"
|
||||
x="60.476189"
|
||||
height="119.86935"
|
||||
width="74.083336"
|
||||
id="rect815"
|
||||
style="fill:#383736;fill-opacity:1;stroke:#7c7c7c;stroke-width:4.23333311;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.5 KiB |
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
|
@ -0,0 +1,135 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="210mm"
|
||||
height="297mm"
|
||||
viewBox="0 0 210 297"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
|
||||
sodipodi:docname="clip.svg">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.49497475"
|
||||
inkscape:cx="379.84557"
|
||||
inkscape:cy="674.60205"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1049"
|
||||
inkscape:window-x="1920"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<rect
|
||||
style="fill:#383736;fill-opacity:1;stroke:#7c7c7c;stroke-width:8.46666622;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect867"
|
||||
width="156.86011"
|
||||
height="110.36904"
|
||||
x="20.788689"
|
||||
y="116.32738"
|
||||
rx="2.6458333"
|
||||
ry="2.6458333"
|
||||
inkscape:export-xdpi="19.67"
|
||||
inkscape:export-ydpi="19.67" />
|
||||
<g
|
||||
id="g873"
|
||||
transform="translate(7.5595238,-2.2339507)"
|
||||
inkscape:export-xdpi="19.67"
|
||||
inkscape:export-ydpi="19.67">
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path821"
|
||||
d="m 64.335157,155.54667 c 10.862887,-10.86289 23.793101,-9.05867 23.793101,-9.05867 0,0 1.804217,12.93021 -9.058669,23.7931"
|
||||
style="fill:#c48916;fill-opacity:1;stroke:none;stroke-width:4.23333311;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
transform="rotate(45)"
|
||||
ry="0.74420118"
|
||||
rx="0.74420118"
|
||||
y="64.496277"
|
||||
x="155.47993"
|
||||
height="33.716"
|
||||
width="20.837635"
|
||||
id="rect815"
|
||||
style="fill:#b63417;fill-opacity:1;stroke:#7c7c7c;stroke-width:4.23333311;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
<g
|
||||
id="g879"
|
||||
transform="translate(33.450892,-2.2339507)"
|
||||
inkscape:export-xdpi="19.67"
|
||||
inkscape:export-ydpi="19.67">
|
||||
<path
|
||||
style="fill:#c48916;fill-opacity:1;stroke:none;stroke-width:4.23333311;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 64.335157,155.54667 c 10.862887,-10.86289 23.793101,-9.05867 23.793101,-9.05867 0,0 1.804217,12.93021 -9.058669,23.7931"
|
||||
id="path875"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<rect
|
||||
style="fill:#b63417;fill-opacity:1;stroke:#7c7c7c;stroke-width:4.23333311;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect877"
|
||||
width="20.837635"
|
||||
height="33.716"
|
||||
x="155.47993"
|
||||
y="64.496277"
|
||||
rx="0.74420118"
|
||||
ry="0.74420118"
|
||||
transform="rotate(45)" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(59.342262,-2.2339507)"
|
||||
id="g885"
|
||||
inkscape:export-xdpi="19.67"
|
||||
inkscape:export-ydpi="19.67">
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path881"
|
||||
d="m 64.335157,155.54667 c 10.862887,-10.86289 23.793101,-9.05867 23.793101,-9.05867 0,0 1.804217,12.93021 -9.058669,23.7931"
|
||||
style="fill:#c48916;fill-opacity:1;stroke:none;stroke-width:4.23333311;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
transform="rotate(45)"
|
||||
ry="0.74420118"
|
||||
rx="0.74420118"
|
||||
y="64.496277"
|
||||
x="155.47993"
|
||||
height="33.716"
|
||||
width="20.837635"
|
||||
id="rect883"
|
||||
style="fill:#b63417;fill-opacity:1;stroke:#7c7c7c;stroke-width:4.23333311;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 4.9 KiB |
|
@ -3,12 +3,12 @@ package nl.andrewl.aos2_server.logic;
|
|||
import nl.andrewl.aos2_server.Server;
|
||||
import nl.andrewl.aos2_server.ServerPlayer;
|
||||
import nl.andrewl.aos2_server.config.ServerConfig;
|
||||
import nl.andrewl.aos_core.model.item.BlockItemStack;
|
||||
import nl.andrewl.aos_core.model.item.ItemTypes;
|
||||
import nl.andrewl.aos_core.model.item.*;
|
||||
import nl.andrewl.aos_core.model.world.World;
|
||||
import nl.andrewl.aos_core.net.client.ClientInputState;
|
||||
import nl.andrewl.aos_core.net.client.InventorySelectedStackMessage;
|
||||
import nl.andrewl.aos_core.net.client.ItemStackMessage;
|
||||
import nl.andrewl.aos_core.net.client.SoundMessage;
|
||||
import nl.andrewl.aos_core.net.world.ChunkUpdateMessage;
|
||||
import org.joml.Math;
|
||||
import org.joml.Vector2i;
|
||||
|
@ -30,6 +30,11 @@ public class PlayerActionManager {
|
|||
private long lastBlockRemovedAt = 0;
|
||||
private long lastBlockPlacedAt = 0;
|
||||
|
||||
private long gunLastShotAt = 0;
|
||||
private boolean gunNeedsReCock = false;
|
||||
private boolean gunReloading = false;
|
||||
private long gunReloadingStartedAt = 0;
|
||||
|
||||
private boolean updated = false;
|
||||
|
||||
public PlayerActionManager(ServerPlayer player) {
|
||||
|
@ -38,7 +43,7 @@ public class PlayerActionManager {
|
|||
player.getId(),
|
||||
false, false, false, false,
|
||||
false, false, false,
|
||||
false, false,
|
||||
false, false, false,
|
||||
player.getInventory().getSelectedIndex()
|
||||
);
|
||||
}
|
||||
|
@ -67,8 +72,15 @@ public class PlayerActionManager {
|
|||
updated = true; // Tell everyone else that this player's selected item has changed.
|
||||
}
|
||||
|
||||
if (player.getInventory().getSelectedItemStack().getType().equals(ItemTypes.BLOCK)) {
|
||||
tickBlockAction(now, server, world);
|
||||
ItemStack selectedStack = player.getInventory().getSelectedItemStack();
|
||||
if (selectedStack instanceof BlockItemStack b) {
|
||||
tickBlockAction(now, server, world, b);
|
||||
} else if (selectedStack instanceof GunItemStack g) {
|
||||
try {
|
||||
tickGunAction(now, server, world, g);
|
||||
} catch (Exception e) {
|
||||
System.out.println("bleh");
|
||||
}
|
||||
}
|
||||
|
||||
if (player.isCrouching() != lastInputState.crouching()) {
|
||||
|
@ -79,8 +91,52 @@ public class PlayerActionManager {
|
|||
tickMovement(dt, world, server.getConfig().physics);
|
||||
}
|
||||
|
||||
private void tickBlockAction(long now, Server server, World world) {
|
||||
BlockItemStack stack = (BlockItemStack) player.getInventory().getSelectedItemStack();
|
||||
private void tickGunAction(long now, Server server, World world, GunItemStack g) {
|
||||
Gun gun = (Gun) g.getType();
|
||||
if (// Check to see if the player is shooting.
|
||||
lastInputState.hitting() &&
|
||||
g.getBulletCount() > 0 &&
|
||||
!gunReloading &&
|
||||
now - gunLastShotAt > gun.getShotCooldownTime() * 1000 &&
|
||||
(gun.isAutomatic() || !gunNeedsReCock)
|
||||
) {
|
||||
// TODO: trace a ray from gun to see if players intersect with it.
|
||||
g.setBulletCount(g.getBulletCount() - 1);
|
||||
gunLastShotAt = now;
|
||||
if (!gun.isAutomatic()) {
|
||||
gunNeedsReCock = true;
|
||||
}
|
||||
server.getPlayerManager().getHandler(player.getId()).sendDatagramPacket(new ItemStackMessage(player.getInventory()));
|
||||
server.getPlayerManager().broadcastUdpMessage(new SoundMessage("rifle", player.getPosition().x(), player.getPosition().y(), player.getPosition().z()));
|
||||
}
|
||||
|
||||
if (// Check to see if the player is reloading.
|
||||
lastInputState.reloading() &&
|
||||
!gunReloading &&
|
||||
g.getClipCount() > 0
|
||||
) {
|
||||
g.setClipCount(g.getClipCount() - 1);
|
||||
gunReloadingStartedAt = now;
|
||||
gunReloading = true;
|
||||
server.getPlayerManager().getHandler(player.getId()).sendDatagramPacket(new ItemStackMessage(player.getInventory()));
|
||||
}
|
||||
|
||||
if (// Check to see if reloading is done.
|
||||
gunReloading &&
|
||||
now - gunReloadingStartedAt > gun.getReloadTime() * 1000
|
||||
) {
|
||||
g.setBulletCount(gun.getMaxBulletCount());
|
||||
gunReloading = false;
|
||||
server.getPlayerManager().getHandler(player.getId()).sendDatagramPacket(new ItemStackMessage(player.getInventory()));
|
||||
}
|
||||
|
||||
// Check to see if the player released the trigger, for non-automatic weapons.
|
||||
if (!gun.isAutomatic() && gunNeedsReCock && !lastInputState.hitting()) {
|
||||
gunNeedsReCock = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void tickBlockAction(long now, Server server, World world, BlockItemStack stack) {
|
||||
// Check for breaking blocks.
|
||||
if (
|
||||
lastInputState.hitting() &&
|
||||
|
|
Loading…
Reference in New Issue