save broken for future

This commit is contained in:
LAX1DUDE 2022-07-16 22:02:55 -07:00
parent 00821ed2ae
commit 1637fc2998
24 changed files with 1835 additions and 287 deletions

View file

@ -19,7 +19,7 @@ public class ServerIcon {
Graphics2D g = (Graphics2D) icon.getGraphics(); Graphics2D g = (Graphics2D) icon.getGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, (awtIcon.getWidth() < 64 || awtIcon.getHeight() < 64) ? g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, (awtIcon.getWidth() < 64 || awtIcon.getHeight() < 64) ?
RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR : RenderingHints.VALUE_INTERPOLATION_BICUBIC); RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR : RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g.setBackground(Color.BLACK); g.setBackground(new Color(0, true));
g.clearRect(0, 0, 64, 64); g.clearRect(0, 0, 64, 64);
int ow = awtIcon.getWidth(); int ow = awtIcon.getWidth();
int oh = awtIcon.getHeight(); int oh = awtIcon.getHeight();

View file

@ -0,0 +1,59 @@
package net.md_5.bungee.eaglercraft;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
// note that there's a few things not implemented, but I don't care.
public class ExpiringSet<T> extends HashSet<T> {
private final long expiration;
private final Map<T, Long> timestamps = new HashMap<>();
public ExpiringSet(long expiration) {
this.expiration = expiration;
}
public void checkForExpirations() {
Iterator<T> iterator = this.timestamps.keySet().iterator();
long now = System.currentTimeMillis();
while (iterator.hasNext()) {
T element = iterator.next();
if (super.contains(element)) {
if (this.timestamps.get(element) + this.expiration < now) {
iterator.remove();
super.remove(element);
}
} else {
iterator.remove();
super.remove(element);
}
}
}
public boolean add(T o) {
checkForExpirations();
boolean success = super.add(o);
if (success) timestamps.put(o, System.currentTimeMillis());
return success;
}
public boolean remove(Object o) {
checkForExpirations();
boolean success = super.remove(o);
if (success) timestamps.remove(o);
return success;
}
public void clear() {
this.timestamps.clear();
super.clear();
}
public boolean contains(Object o) {
checkForExpirations();
return super.contains(o);
}
}

View file

@ -0,0 +1,157 @@
package net.md_5.bungee.eaglercraft;
import net.md_5.bungee.UserConnection;
import net.md_5.bungee.api.event.PlayerDisconnectEvent;
import net.md_5.bungee.api.event.PluginMessageEvent;
import net.md_5.bungee.api.event.PostLoginEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.api.plugin.Plugin;
import net.md_5.bungee.api.plugin.PluginDescription;
import net.md_5.bungee.event.EventHandler;
import org.json.JSONObject;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.Collections;
public class PluginEaglerVoice extends Plugin implements Listener {
private final Map<String, UserConnection> voicePlayers = new HashMap<>();
private final Map<String, ExpiringSet<String>> voiceRequests = new HashMap<>();
private final Set<String[]> voicePairs = new HashSet<>();
public PluginEaglerVoice() {
super(new PluginDescription("EaglerVoice", PluginEaglerVoice.class.getName(), "1.0.0", "ayunami2000", Collections.emptySet(), null));
}
public void onLoad() {
}
public void onEnable() {
getProxy().getPluginManager().registerListener(this, this);
}
public void onDisable() {
}
@EventHandler
public void onPluginMessage(PluginMessageEvent event) {
if(event.getSender() instanceof UserConnection && event.getData().length > 0) {
UserConnection connection = (UserConnection) event.getSender();
String user = connection.getName();
byte[] msg = event.getData();
try {
if("EAG|VoiceJoin".equals(event.getTag())) {
if (voicePlayers.containsKey(user)) return; // user is already using voice chat
// send out packet for player joined voice
// notice: everyone on the server can see this packet!! however, it doesn't do anything but let clients know that the player has turned on voice chat
for (UserConnection conn : voicePlayers.values()) conn.sendData("EAG|VoiceJoin", user.getBytes(StandardCharsets.UTF_8));
voicePlayers.put(user, connection);
}else if("EAG|VoiceLeave".equals(event.getTag())) {
if (!voicePlayers.containsKey(user)) return; // user is not using voice chat
removeUser(user);
}else if("EAG|VoiceReq".equals(event.getTag())) {
if (!voicePlayers.containsKey(user)) return; // user is not using voice chat
String targetUser = new String(msg, StandardCharsets.UTF_8);
if (user.equals(targetUser)) return; // prevent duplicates
if (checkVoicePair(user, targetUser)) return; // already paired
if (!voicePlayers.containsKey(targetUser)) return; // target user is not using voice chat
if (!voiceRequests.containsKey(user)) voiceRequests.put(user, new ExpiringSet<>(2000));
if (voiceRequests.get(user).contains(targetUser)) return;
voiceRequests.get(user).add(targetUser);
// check if other has requested earlier
if (voiceRequests.containsKey(targetUser) && voiceRequests.get(targetUser).contains(user)) {
if (voiceRequests.containsKey(targetUser)) {
voiceRequests.get(targetUser).remove(user);
if (voiceRequests.get(targetUser).isEmpty()) voiceRequests.remove(targetUser);
}
if (voiceRequests.containsKey(user)) {
voiceRequests.get(user).remove(targetUser);
if (voiceRequests.get(user).isEmpty()) voiceRequests.remove(user);
}
// send each other add data
voicePairs.add(new String[] { user, targetUser });
JSONObject json = new JSONObject();
json.put("username", user);
json.put("offer", false);
voicePlayers.get(targetUser).sendData("EAG|VoiceAdd", json.toString().getBytes(StandardCharsets.UTF_8));
json.put("username", targetUser);
json.put("offer", true);
connection.sendData("EAG|VoiceAdd", json.toString().getBytes(StandardCharsets.UTF_8));
}
} else if("EAG|VoiceRemove".equals(event.getTag())) {
if (!voicePlayers.containsKey(user)) return; // user is not using voice chat
String targetUser = new String(msg, StandardCharsets.UTF_8);
if (voicePairs.removeIf(pair -> (pair[0].equals(user) && pair[1].equals(targetUser)) || (pair[0].equals(targetUser) && pair[1].equals(user)))) voicePlayers.get(targetUser).sendData("EAG|VoiceRemove", user.getBytes(StandardCharsets.UTF_8));
}else if("EAG|VoiceIce".equals(event.getTag())) {
if (!voicePlayers.containsKey(user)) return; // user is not using voice chat
JSONObject json = new JSONObject(new String(msg));
if (json.has("username") && json.get("username") instanceof String) {
String targetUser = json.getString("username");
if (checkVoicePair(user, targetUser)) {
if (json.has("ice_candidate")) {
// todo: limit ice_candidate data length or sanitize it fully
json.keySet().removeIf(s -> !s.equals("ice_candidate"));
json.put("username", user);
voicePlayers.get(targetUser).sendData("EAG|VoiceIce", json.toString().getBytes(StandardCharsets.UTF_8));
}
}
}
}else if("EAG|VoiceDesc".equals(event.getTag())) {
if (!voicePlayers.containsKey(user)) return; // user is not using voice chat
JSONObject json = new JSONObject(new String(msg));
if (json.has("username") && json.get("username") instanceof String) {
String targetUser = json.getString("username");
if (checkVoicePair(user, targetUser)) {
if (json.has("session_description")) {
// todo: limit session_description data length or sanitize it fully
json.keySet().removeIf(s -> !s.equals("session_description"));
json.put("username", user);
voicePlayers.get(targetUser).sendData("EAG|VoiceDesc", json.toString().getBytes(StandardCharsets.UTF_8));
}
}
}
}
}catch(Throwable t) {
// hacker
t.printStackTrace(); // todo: remove in production
removeUser(user);
}
}
}
@EventHandler
public void onPostLogin(PostLoginEvent event) {
event.getPlayer().sendData("EAG|Voice", new byte[] { });
}
@EventHandler
public void onPlayerDisconnect(PlayerDisconnectEvent event) {
String nm = event.getPlayer().getName();
removeUser(nm);
}
public void removeUser(String name) {
voicePlayers.remove(name);
for (String[] voicePair : voicePairs) {
String target = null;
if (voicePair[0].equals(name)) {
target = voicePair[1];
} else if(voicePair[1].equals(name)) {
target = voicePair[0];
}
if (target != null && voicePlayers.containsKey(target)) voicePlayers.get(target).sendData("EAG|VoiceRemove", name.getBytes(StandardCharsets.UTF_8));
}
voicePairs.removeIf(pair -> pair[0].equals(name) || pair[1].equals(name));
}
private boolean checkVoicePair(String user1, String user2) {
return voicePairs.stream().anyMatch(pair -> (pair[0].equals(user1) && pair[1].equals(user2)) || (pair[0].equals(user2) && pair[1].equals(user1)));
}
}

227
javascript/eagswebrtc.js Normal file
View file

@ -0,0 +1,227 @@
"use strict";
/*
This is the backend for voice channels in eaglercraft, it links with TeaVM EaglerAdapter at runtime
Copyright 2022 Calder Young. All rights reserved.
Based on code written by ayunami2000
*/
window.initializeVoiceClient = (() => {
const READYSTATE_NONE = 0;
const READYSTATE_ABORTED = -1;
const READYSTATE_DEVICE_INITIALIZED = 1;
const TASKSTATE_NONE = -1;
const TASKSTATE_LOADING = 0;
const TASKSTATE_COMPLETE = 1;
const TASKSTATE_FAILED = 2;
class EaglercraftVoicePeer {
constructor(client, peerId, peerConnection) {
this.client = client;
this.peerId = peerId;
this.peerConnection = peerConnection;
const self = this;
this.peerConnection.addEventListener("icecandidate", (evt) => {
if(evt.candidate) {
self.client.iceCandidateHandler(self.peerId, evt.candidate.sdpMLineIndex, evt.candidate.candidate.toJSON().stringify());
}
});
this.peerConnection.addEventListener("track", (evt) => {
self.client.peerTrackHandler(self.peerId, evt.streams[0]);
});
this.peerConnection.addStream(this.client.localMediaStream);
this.peerConnection.createOffer((desc) => {
const selfDesc = desc;
self.peerConnection.setLocalDescription(selfDesc, () => {
self.client.descriptionHandler(self.peerId, selfDesc.toJSON().stringify());
}, (err) => {
console.error("Failed to set local description for \"" + self.peerId + "\"! " + err);
self.client.signalDisconnect(self.peerId);
});
}, (err) => {
console.error("Failed to set create offer for \"" + self.peerId + "\"! " + err);
self.client.signalDisconnect(self.peerId);
});
this.peerConnection.addEventListener("connectionstatechange", (evt) => {
if(evt.connectionState === 'disconnected') {
self.client.signalDisconnect(self.peerId);
}
});
}
disconnect() {
this.peerConnection.close();
}
setRemoteDescription(descJSON) {
const self = this;
const remoteDesc = JSON.parse(descJSON);
this.peerConnection.setRemoteDescription(remoteDesc, () => {
if(remoteDesc.type == 'offer') {
self.peerConnection.createAnswer((desc) => {
const selfDesc = desc;
self.peerConnection.setLocalDescription(selfDesc, () => {
self.client.descriptionHandler(self.peerId, selfDesc.toJSON().stringify());
}, (err) => {
console.error("Failed to set local description for \"" + self.peerId + "\"! " + err);
self.signalDisconnect(peerId);
});
}, (err) => {
console.error("Failed to create answer for \"" + self.peerId + "\"! " + err);
self.signalDisconnect(peerId);
});
}
}, (err) => {
console.error("Failed to set remote description for \"" + self.peerId + "\"! " + err);
self.signalDisconnect(peerId);
});
}
addICECandidate(candidate) {
this.peerConnection.addICECandidate(new RTCIceCandidate(JSON.parse(candidate)));
}
}
class EaglercraftVoiceClient {
constructor() {
this.ICEServers = [];
this.hasInit = false;
this.peerList = new Map();
this.readyState = READYSTATE_NONE;
this.taskState = TASKSTATE_NONE;
this.iceCandidateHandler = null;
this.descriptionHandler = null;
this.peerTrackHandler = null;
this.peerDisconnectHandler = null;
this.microphoneVolumeAudioContext = new AudioContext();
}
voiceClientSupported() {
return typeof window.RTCPeerConnection !== "undefined" && typeof navigator.mediaDevices !== "undefined" &&
typeof navigator.mediaDevices.getUserMedia !== "undefined";
}
setICEServers(urls) {
this.ICEServers.length = 0;
for(var i = 0; i < urls.length; ++i) {
this.ICEServers.push({ urls: urls[i] });
}
}
setICECandidateHandler(cb) {
this.iceCandidateHandler = cb;
}
setDescriptionHandler(cb) {
this.descriptionHandler = cb;
}
setPeerTrackHandler(cb) {
this.peerTrackHandler = cb;
}
setPeerDisconnectHandler(cb) {
this.peerDisconnectHandler = cb;
}
activateVoice(tk) {
this.localRawMediaStream.getAudioTracks()[0].enabled = tk;
}
intitializeDevices() {
if(!this.hasInit) {
this.taskState = TASKSTATE_LOADING;
const self = this;
navigator.mediaDevices.getUserMedia({ audio: true, video: false }).then((stream) => {
self.localRawMediaStream = stream;
self.localRawMediaStream.getAudioTracks()[0].enabled = false;
self.localMediaStream = self.microphoneVolumeAudioContext.createMediaStreamDestination();
self.localMediaStreamGain = self.microphoneVolumeAudioContext.createGain();
var localStreamIn = self.microphoneVolumeAudioContext.createMediaStreamSource(stream);
localStreamIn.connect(self.localMediaStreamGain);
self.localMediaStreamGain.connect(self.localMediaStream);
self.localMediaStreamGain.gain = 1.0;
self.readyState = READYSTATE_DEVICE_INITIALIZED;
self.taskState = TASKSTATE_COMPLETE;
this.hasInit = true;
}).catch(() => {
self.readyState = READYSTATE_ABORTED;
self.taskState = TASKSTATE_FAILED;
});
}else {
self.readyState = READYSTATE_DEVICE_INITIALIZED;
self.taskState = TASKSTATE_COMPLETE;
}
}
setMicVolume(val) {
if(val > 0.5) val = 0.5 + (val - 0.5) * 2.0;
if(val > 1.5) val = 1.5;
if(val < 0.0) val = 0.0;
self.localMediaStreamGain.gain = val * 2.0;
}
getTaskState() {
return this.taskState;
}
getReadyState() {
return this.readyState;
}
signalConnect(peerId) {
const peerConnection = new RTCPeerConnection({ iceServers: this.ICEServers, optional: [ { DtlsSrtpKeyAgreement: true } ] });
const peerInstance = new EaglercraftVoicePeer(this, peerId, peerConnection);
this.peerList.set(peerId, peerInstance);
}
signalDescription(peerId, descJSON) {
var thePeer = this.peerList.get(peerId);
if((typeof thePeer !== "undefined") && thePeer !== null) {
thePeer.setRemoteDescription(descJSON);
}
}
signalDisconnect(peerId) {
var thePeer = this.peerList.get(peerId);
if((typeof thePeer !== "undefined") && thePeer !== null) {
this.peerList.delete(thePeer);
try {
thePeer.disconnect();
}catch(e) {}
this.peerDisconnectHandler(peerId);
}
}
signalICECandidate(peerId, candidate) {
var thePeer = this.peerList.get(peerId);
if((typeof thePeer !== "undefined") && thePeer !== null) {
thePeer.addICECandidate(candidate);
}
}
}
window.constructVoiceClient = () => new EaglercraftVoiceClient();
});
window.startVoiceClient = () => {
if(typeof window.constructVoiceClient !== "function") {
window.initializeVoiceClient();
}
return window.constructVoiceClient();
};

View file

@ -3,6 +3,7 @@
<head> <head>
<title>eagler</title> <title>eagler</title>
<script type="text/javascript" src="classes.js"></script> <script type="text/javascript" src="classes.js"></script>
<script type="text/javascript" src="eagswebrtc.js"></script>
<script type="text/javascript"> <script type="text/javascript">
if(document.location.href.startsWith("file:")) { if(document.location.href.startsWith("file:")) {
alert("You're not supposed to 'open' this file in your browser. Please upload this folder to your HTTP(s) server and access it via the internet. This is not a bug, please read the documentation"); alert("You're not supposed to 'open' this file in your browser. Please upload this folder to your HTTP(s) server and access it via the internet. This is not a bug, please read the documentation");

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

View file

@ -62,10 +62,33 @@ profile.clearSkin=Clear List
fancyGraphicsNote=go to -> Options -> Video Settings on the pause menu to enable fancy graphics and smooth lighting fancyGraphicsNote=go to -> Options -> Video Settings on the pause menu to enable fancy graphics and smooth lighting
voice.title=Voice Channel voice.title=Voice Channel
voice.addr=Channel Address voice.titleNoVoice=Voice is disabled on this server
voice.connect=Connect voice.titleVoiceUnavailable=Voice is unavailable
voice.disconnect=Disconnect voice.titleVoiceBrowserError=(fix your browser)
voice.volume=Channel Volume voice.ptt=Press '$key$' to speak
voice.pttChangeDesc=(Press Any Key)
voice.changeKey=Change
voice.off=OFF
voice.radius=NEARBY
voice.global=GLOBAL
voice.volumeTitle=Change Volume
voice.volumeListen=Speakers Volume:
voice.volumeSpeak=Microphone Volume:
voice.radiusTitle=Change Listener Radius
voice.radiusLabel=Players Within:
voice.radiusChange=change
voice.notConnected=Not Connected
voice.connecting=Connecting...
voice.unavailable=Could not connect!
voice.connectedGlobal=Connected - Global
voice.connectedRadius=Connected - $f$Within $radius$m
voice.playersListening=Players Listening:
voice.muted=Players Muted:
voice.unmute=unmute
voice.mute=mute
voice.apply=Apply
voice.volumeSpeakerLabel=Speakers:
voice.volumeMicrophoneLabel=Microphone:
voice.warning1=§cWarning:§r your network does not support the STUN voice.warning1=§cWarning:§r your network does not support the STUN
voice.warning2=connection procedure, a TURN relay will be used as voice.warning2=connection procedure, a TURN relay will be used as
voice.warning3=fallback, which will greatly impact the audio quality voice.warning3=fallback, which will greatly impact the audio quality

View file

@ -0,0 +1,5 @@
package net.lax1dude.eaglercraft;
public class AbortedException extends RuntimeException {
}

View file

@ -0,0 +1,59 @@
package net.lax1dude.eaglercraft;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
// note that there's a few things not implemented, but I don't care.
public class ExpiringSet<T> extends HashSet<T> {
private final long expiration;
private final Map<T, Long> timestamps = new HashMap<>();
public ExpiringSet(long expiration) {
this.expiration = expiration;
}
public void checkForExpirations() {
Iterator<T> iterator = this.timestamps.keySet().iterator();
long now = System.currentTimeMillis();
while (iterator.hasNext()) {
T element = iterator.next();
if (super.contains(element)) {
if (this.timestamps.get(element) + this.expiration < now) {
iterator.remove();
super.remove(element);
}
} else {
iterator.remove();
super.remove(element);
}
}
}
public boolean add(T o) {
checkForExpirations();
boolean success = super.add(o);
if (success) timestamps.put(o, System.currentTimeMillis());
return success;
}
public boolean remove(Object o) {
checkForExpirations();
boolean success = super.remove(o);
if (success) timestamps.remove(o);
return success;
}
public void clear() {
this.timestamps.clear();
super.clear();
}
public boolean contains(Object o) {
checkForExpirations();
return super.contains(o);
}
}

View file

@ -1,243 +0,0 @@
package net.lax1dude.eaglercraft;
import java.util.Arrays;
import net.minecraft.client.Minecraft;
import net.minecraft.src.GuiButton;
import net.minecraft.src.GuiIngameMenu;
import net.minecraft.src.GuiMainMenu;
import net.minecraft.src.GuiScreen;
import net.minecraft.src.GuiSlider2;
import net.minecraft.src.GuiTextField;
import net.minecraft.src.ScaledResolution;
import net.minecraft.src.StringTranslate;
public class GuiScreenVoiceChannel extends GuiScreen {
public GuiScreenVoiceChannel(GuiScreen parent) {
this.parent = parent;
}
protected String screenTitle = "Voice Channel";
private GuiScreen parent;
private GuiTextField channel;
private GuiButton done;
private GuiButton connect;
private GuiButton disconnect;
private GuiSlider2 slider;
public void initGui() {
StringTranslate var1 = StringTranslate.getInstance();
this.screenTitle = var1.translateKey("voice.title");
this.channel = new GuiTextField(this.fontRenderer, this.width / 2 - 98, this.height / 6 + 24, 195, 20);
this.channel.setText(EaglerProfile.myChannel);
EaglerAdapter.enableRepeatEvents(true);
this.buttonList.add(done = new GuiButton(200, this.width / 2 - 100, this.height / 6 + 148, var1.translateKey("gui.done")));
this.buttonList.add(connect = new GuiButton(1, this.width / 2 - 100, this.height / 6 + 52, 99, 20, var1.translateKey("voice.connect")));
this.buttonList.add(disconnect = new GuiButton(2, this.width / 2 + 1, this.height / 6 + 52, 99, 20, var1.translateKey("voice.disconnect")));
this.buttonList.add(slider = new GuiSlider2(3, this.width / 2 - 100, this.height / 6 + 103, 200, 20, 0.5f, 2.0f));
}
public void onGuiClosed() {
EaglerAdapter.enableRepeatEvents(false);
}
public void drawScreen(int mx, int my, float par3) {
this.drawDefaultBackground();
StringTranslate var1 = StringTranslate.getInstance();
this.drawCenteredString(this.fontRenderer, this.screenTitle, this.width / 2, 15, 16777215);
this.drawString(this.fontRenderer, var1.translateKey("voice.addr"), this.width / 2 - 98, this.height / 6 + 8, 10526880);
if(voiceRelayed) {
this.drawCenteredString(this.fontRenderer, var1.translateKey("voice.warning1"), this.width / 2, this.height / 6 + 125, 0xffcccc);
this.drawCenteredString(this.fontRenderer, var1.translateKey("voice.warning2"), this.width / 2, this.height / 6 + 136, 0xffcccc);
this.drawCenteredString(this.fontRenderer, var1.translateKey("voice.warning3"), this.width / 2, this.height / 6 + 147, 0xffcccc);
this.drawString(this.fontRenderer, var1.translateKey("voice.volume"), this.width / 2 - 98, this.height / 6 + 81, 10526880);
slider.yPosition = this.height / 6 + 95;
done.yPosition = this.height / 6 + 168;
}else {
this.drawString(this.fontRenderer, var1.translateKey("voice.volume"), this.width / 2 - 98, this.height / 6 + 89, 10526880);
slider.yPosition = this.height / 6 + 103;
done.yPosition = this.height / 6 + 148;
}
super.drawScreen(mx, my, par3);
this.channel.drawTextBox();
}
protected void actionPerformed(GuiButton par1GuiButton) {
if(par1GuiButton.id == 200) {
this.mc.displayGuiScreen(parent);
}else if(par1GuiButton.id == 1) {
EaglerAdapter.voiceConnect(channel.getText());
}else if(par1GuiButton.id == 2) {
EaglerAdapter.voiceEnd();
}
}
public void updateScreen() {
this.channel.updateCursorCounter();
this.connect.enabled = !voiceActive;
this.disconnect.enabled = voiceActive;
this.channel.setEnabled(!voiceActive);
this.slider.enabled = voiceActive;
}
protected void keyTyped(char par1, int par2) {
this.channel.textboxKeyTyped(par1, par2);
}
protected void mouseClicked(int par1, int par2, int par3) {
super.mouseClicked(par1, par2, par3);
this.channel.mouseClicked(par1, par2, par3);
}
public boolean doesGuiPauseGame() {
return false;
}
private static final TextureLocation tex_gui = new TextureLocation("/gui/gui.png");
private static String[] connectedUsers = new String[0];
private static String[] talkingUsers = new String[0];
private static boolean voiceActive = false;
private static boolean voiceRelayed = false;
public static void tickVoiceConnection() {
voiceActive = EaglerAdapter.voiceActive();
if(voiceActive) {
voiceRelayed = EaglerAdapter.voiceRelayed();
connectedUsers = EaglerAdapter.voiceUsers();
talkingUsers = EaglerAdapter.voiceUsersTalking();
Arrays.sort(talkingUsers);
Arrays.sort(connectedUsers);
}else {
voiceRelayed = false;
}
}
public static long fadeInTimer = 0l;
public static void drawOverlay() {
Minecraft mc = Minecraft.getMinecraft();
if(System.currentTimeMillis() - fadeInTimer < 1500l) {
ScaledResolution res = new ScaledResolution(mc.gameSettings, mc.displayWidth, mc.displayHeight);
EaglerAdapter.glDisable(EaglerAdapter.GL_TEXTURE_2D);
EaglerAdapter.glDisable(EaglerAdapter.GL_ALPHA_TEST);
EaglerAdapter.glDisable(EaglerAdapter.GL_DEPTH_TEST);
EaglerAdapter.glDepthMask(false);
EaglerAdapter.glEnable(EaglerAdapter.GL_BLEND);
EaglerAdapter.glBlendFunc(EaglerAdapter.GL_SRC_ALPHA, EaglerAdapter.GL_ONE_MINUS_SRC_ALPHA);
float i = (float)(System.currentTimeMillis() - fadeInTimer) / 600f;
i = 1.0f / (i + 1.0f);
i = i * i * 1.08f - 0.08f;
if(i < 0.0f) i = 0.0f;
drawRect(0, 0, res.getScaledWidth(), res.getScaledHeight(), ((int)(i * 255f) << 24) | 0xffffff);
EaglerAdapter.glEnable(EaglerAdapter.GL_ALPHA_TEST);
if(System.currentTimeMillis() - fadeInTimer < 130l) {
mc.showWarningText();
}
EaglerAdapter.glEnable(EaglerAdapter.GL_DEPTH_TEST);
EaglerAdapter.glDepthMask(true);
}
boolean titleScreen = (mc.currentScreen != null && (mc.currentScreen instanceof GuiMainMenu));
if(voiceActive && !(titleScreen && ((GuiMainMenu)mc.currentScreen).showAck) && !mc.gameSettings.showDebugInfo) {
ScaledResolution res = new ScaledResolution(mc.gameSettings, mc.displayWidth, mc.displayHeight);
int width = res.getScaledWidth(); int height = res.getScaledHeight();
if(titleScreen) {
EaglerAdapter.glPushMatrix();
EaglerAdapter.glTranslatef(0f, 12f, 0f);
}
EaglerAdapter.glDisable(EaglerAdapter.GL_LIGHTING);
EaglerAdapter.glEnable(EaglerAdapter.GL_BLEND);
EaglerAdapter.glBlendFunc(EaglerAdapter.GL_SRC_ALPHA, EaglerAdapter.GL_ONE_MINUS_SRC_ALPHA);
EaglerAdapter.glEnable(EaglerAdapter.GL_TEXTURE_2D);
EaglerAdapter.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
String line1 = "voice connected";
String line2 = "" + connectedUsers.length + " users listening";
int ll1 = mc.fontRenderer.getStringWidth(line1);
int ll2 = mc.fontRenderer.getStringWidth(line2);
drawRect(width - 17 - ll1 - 6, 0, width, 20, 0x33000000);
if(mc.gameSettings.keyBindPlayerList.pressed || (mc.currentScreen != null && ((mc.currentScreen instanceof GuiIngameMenu) || (mc.currentScreen instanceof GuiScreenVoiceChannel)))) {
if(connectedUsers.length > 0) {
int wid = 0;
for(int i = 0; i < connectedUsers.length; ++i) {
EaglerAdapter.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
int sw = mc.fontRenderer.getStringWidth(connectedUsers[i]);
mc.fontRenderer.drawStringWithShadow(connectedUsers[i], width - 12 - sw, 26 + i*11, 0xffeeeeee);
if(wid < sw) {
wid = sw;
}
boolean isTalking = false;
for(int j = 0; j < talkingUsers.length; ++j) {
if(talkingUsers[j].equals(connectedUsers[i])) {
isTalking = true;
break;
}
}
tex_gui.bindTexture();
EaglerAdapter.glEnable(EaglerAdapter.GL_BLEND);
EaglerAdapter.glBlendFunc(EaglerAdapter.GL_SRC_ALPHA, EaglerAdapter.GL_ONE_MINUS_SRC_ALPHA);
EaglerAdapter.glColor4f(1.0f, 1.0f, 1.0f, 0.65f);
EaglerAdapter.glPushMatrix();
EaglerAdapter.glTranslatef(width - 9, 27 + i*11, 0f);
EaglerAdapter.glScalef(0.5f, 0.5f, 0.5f);
static_drawTexturedModalRect(0, 0, isTalking ? 208 : 224, 0, 15, 15);
EaglerAdapter.glPopMatrix();
}
drawRect(width - wid - 15, 24, width, 26 + connectedUsers.length*11, 0x33000000);
}
}else {
if(talkingUsers.length > 0) {
int wid = 0;
for(int i = 0; i < talkingUsers.length; ++i) {
EaglerAdapter.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
int sw = mc.fontRenderer.getStringWidth(talkingUsers[i]);
mc.fontRenderer.drawStringWithShadow(talkingUsers[i], width - 12 - sw, 26 + i*11, 0xffeeeeee);
if(wid < sw) {
wid = sw;
}
tex_gui.bindTexture();
EaglerAdapter.glEnable(EaglerAdapter.GL_BLEND);
EaglerAdapter.glBlendFunc(EaglerAdapter.GL_SRC_ALPHA, EaglerAdapter.GL_ONE_MINUS_SRC_ALPHA);
EaglerAdapter.glColor4f(1.0f, 1.0f, 1.0f, 0.65f);
EaglerAdapter.glPushMatrix();
EaglerAdapter.glTranslatef(width - 9, 27 + i*11, 0f);
EaglerAdapter.glScalef(0.5f, 0.5f, 0.5f);
static_drawTexturedModalRect(0, 0, 208, 0, 15, 15);
EaglerAdapter.glPopMatrix();
}
drawRect(width - wid - 15, 24, width, 26 + talkingUsers.length*11, 0x33000000);
}
}
mc.fontRenderer.drawStringWithShadow(line1, width - 16 - ll1 - 4, 2, 0xffffffff);
EaglerAdapter.glPushMatrix();
EaglerAdapter.glTranslatef(width - 20, 11f, 0f);
EaglerAdapter.glScalef(0.75f, 0.75f, 0.75f);
mc.fontRenderer.drawStringWithShadow(line2, -ll2, 0, 0xffffffff);
EaglerAdapter.glPopMatrix();
boolean b = ((System.currentTimeMillis() / 800l) % 2l) == 1l;
tex_gui.bindTexture();
EaglerAdapter.glEnable(EaglerAdapter.GL_BLEND);
EaglerAdapter.glBlendFunc(EaglerAdapter.GL_SRC_ALPHA, EaglerAdapter.GL_ONE_MINUS_SRC_ALPHA);
EaglerAdapter.glColor4f(1.0f, 1.0f, 1.0f, 0.65f);
static_drawTexturedModalRect(width - 17, 2, b ? 192 : 224, 0, 15, 15);
if(titleScreen) {
EaglerAdapter.glPopMatrix();
}
}
}
}

View file

@ -0,0 +1,595 @@
package net.lax1dude.eaglercraft;
import java.util.List;
import java.util.Set;
import net.minecraft.client.Minecraft;
import net.minecraft.src.EnumChatFormatting;
import net.minecraft.src.GuiButton;
import net.minecraft.src.GuiScreen;
import net.minecraft.src.GuiSlider2;
import net.minecraft.src.MathHelper;
import net.minecraft.src.StringTranslate;
public class GuiVoiceMenu extends GuiScreen {
protected final GuiScreen parent;
protected int voiceButtonOFFposX;
protected int voiceButtonOFFposY;
protected int voiceButtonOFFposW;
protected int voiceButtonOFFposH;
protected int voiceButtonRADIUSposX;
protected int voiceButtonRADIUSposY;
protected int voiceButtonRADIUSposW;
protected int voiceButtonRADIUSposH;
protected int voiceButtonGLOBALposX;
protected int voiceButtonGLOBALposY;
protected int voiceButtonGLOBALposW;
protected int voiceButtonGLOBALposH;
protected int voiceScreenButtonOFFposX;
protected int voiceScreenButtonOFFposY;
protected int voiceScreenButtonOFFposW;
protected int voiceScreenButtonOFFposH;
protected int voiceScreenButtonRADIUSposX;
protected int voiceScreenButtonRADIUSposY;
protected int voiceScreenButtonRADIUSposW;
protected int voiceScreenButtonRADIUSposH;
protected int voiceScreenButtonGLOBALposX;
protected int voiceScreenButtonGLOBALposY;
protected int voiceScreenButtonGLOBALposW;
protected int voiceScreenButtonGLOBALposH;
protected int voiceScreenButtonChangeRadiusposX;
protected int voiceScreenButtonChangeRadiusposY;
protected int voiceScreenButtonChangeRadiusposW;
protected int voiceScreenButtonChangeRadiusposH;
protected int voiceScreenVolumeIndicatorX;
protected int voiceScreenVolumeIndicatorY;
protected int voiceScreenVolumeIndicatorW;
protected int voiceScreenVolumeIndicatorH;
protected boolean showSliderBlocks = false;
protected boolean showSliderVolume = false;
protected boolean showPTTKeyConfig = false;
protected int showNewPTTKey = 0;
protected GuiSlider2 sliderBlocks = null;
protected GuiSlider2 sliderListenVolume = null;
protected GuiSlider2 sliderSpeakVolume = null;
protected GuiButton applyRadiusButton = null;
protected GuiButton applyVolumeButton = null;
public GuiVoiceMenu(GuiScreen parent) {
this.parent = parent;
}
public void initGui() {
this.sliderBlocks = new GuiSlider2(-1, (width - 150) / 2, height / 3 + 20, 150, 20, (EaglerAdapter.getVoiceProximity() - 5) / 17.0f, 1.0f) {
public boolean mousePressed(Minecraft par1Minecraft, int par2, int par3) {
if(super.mousePressed(par1Minecraft, par2, par3)) {
this.displayString = "" + (int)((sliderValue * 17.0f) + 5.0f) + " Blocks";
return true;
}else {
return false;
}
}
public void mouseDragged(Minecraft par1Minecraft, int par2, int par3) {
super.mouseDragged(par1Minecraft, par2, par3);
this.displayString = "" + (int)((sliderValue * 17.0f) + 5.0f) + " Blocks";
}
};
sliderBlocks.displayString = "" + EaglerAdapter.getVoiceProximity() + " Blocks";
this.sliderListenVolume = new GuiSlider2(-1, (width - 150) / 2, height / 3 + 10, 150, 20, EaglerAdapter.getVoiceListenVolume(), 1.0f);
this.sliderSpeakVolume = new GuiSlider2(-1, (width - 150) / 2, height / 3 + 56, 150, 20, EaglerAdapter.getVoiceSpeakVolume(), 1.0f);
StringTranslate ts = StringTranslate.getInstance();
this.buttonList.clear();
this.buttonList.add(applyRadiusButton = new GuiButton(2, (width - 150) / 2, height / 3 + 49, 150, 20, ts.translateKey("voice.apply")));
this.buttonList.add(applyVolumeButton = new GuiButton(3, (width - 150) / 2, height / 3 + 90, 150, 20, ts.translateKey("voice.apply")));
applyRadiusButton.drawButton = applyVolumeButton.drawButton = false;
}
private static final TextureLocation voiceGuiIcons = new TextureLocation("/gui/voice.png");
public void drawScreen(int mx, int my, float partialTicks) {
StringTranslate ts = StringTranslate.getInstance();
String txt = ts.translateKey("voice.title");
drawString(fontRenderer, txt, width - 5 - fontRenderer.getStringWidth(txt), 5, 0xFFCC22);
applyRadiusButton.drawButton = showSliderBlocks;
applyVolumeButton.drawButton = showSliderVolume;
if(showSliderBlocks || showSliderVolume || showPTTKeyConfig) {
drawRect(0, 0, this.width, this.height, 0xB0101010);
if(showSliderBlocks) {
drawRect(width / 2 - 86, height / 4 - 1, this.width / 2 + 86, height / 3 + 64 + height / 16, 0xFFDDDDDD);
drawRect(width / 2 - 85, height / 4 + 0, this.width / 2 + 85, height / 3 + 63 + height / 16, 0xFF333333);
drawCenteredString(this.fontRenderer, ts.translateKey("voice.radiusTitle"), this.width / 2, height / 4 + 9, 16777215);
drawString(this.fontRenderer, ts.translateKey("voice.radiusLabel"), (this.width - 150) / 2 + 3, height / 3 + 6, 0xCCCCCC);
sliderBlocks.drawButton(mc, mx, my);
}else if(showSliderVolume) {
drawRect(width / 2 - 86, height / 4 - 11, this.width / 2 + 86, height / 3 + 104 + height / 16, 0xFFDDDDDD);
drawRect(width / 2 - 85, height / 4 - 10, this.width / 2 + 85, height / 3 + 103 + height / 16, 0xFF333333);
drawCenteredString(this.fontRenderer, ts.translateKey("voice.volumeTitle"), this.width / 2, height / 4 - 1, 16777215);
drawString(this.fontRenderer, ts.translateKey("voice.volumeListen"), (this.width - 150) / 2 + 3, height / 3 - 4, 0xCCCCCC);
sliderListenVolume.drawButton(mc, mx, my);
drawString(this.fontRenderer, ts.translateKey("voice.volumeSpeak"), (this.width - 150) / 2 + 3, height / 3 + 42, 0xCCCCCC);
sliderSpeakVolume.drawButton(mc, mx, my);
}else if(showPTTKeyConfig) {
drawRect(width / 2 - 86, height / 3 - 10, this.width / 2 + 86, height / 3 + 35, 0xFFDDDDDD);
drawRect(width / 2 - 85, height / 3 - 9, this.width / 2 + 85, height / 3 + 34, 0xFF333333);
if(showNewPTTKey > 0) {
EaglerAdapter.glPushMatrix();
EaglerAdapter.glTranslatef(this.width / 2, height / 3 + 5, 0.0f);
EaglerAdapter.glScalef(2.0f, 2.0f, 2.0f);
drawCenteredString(this.fontRenderer, EaglerAdapter.getKeyName(mc.gameSettings.voicePTTKey), 0, 0, 0xFFCC11);
EaglerAdapter.glPopMatrix();
}else {
drawCenteredString(this.fontRenderer, ts.translateKey("voice.pttChangeDesc"), this.width / 2, height / 3 + 8, 16777215);
}
}
super.drawScreen(mx, my, partialTicks);
throw new AbortedException();
}
EaglerAdapter.glPushMatrix();
EaglerAdapter.glTranslatef(width - 6, 15, 0.0f);
EaglerAdapter.glScalef(0.75f, 0.75f, 0.75f);
if(!EaglerAdapter.voiceAvailable()) {
txt = ts.translateKey("voice.titleVoiceUnavailable");
drawString(fontRenderer, txt, 1 - fontRenderer.getStringWidth(txt), 6, 0xFF7777);
txt = ts.translateKey("voice.titleVoiceBrowserError");
drawString(fontRenderer, txt, 1 - fontRenderer.getStringWidth(txt), 19, 0xAA4444);
return;
}
if(!EaglerAdapter.voiceAllowed()) {
txt = ts.translateKey("voice.titleNoVoice");
drawString(fontRenderer, txt, 1 - fontRenderer.getStringWidth(txt), 5, 0xFF7777);
return;
}
int xo = 0;
if(EaglerAdapter.voiceRelayed()) {
txt = ts.translateKey("voice.warning1");
drawString(fontRenderer, txt, 1 - fontRenderer.getStringWidth(txt), 8, 0xBB9999);
txt = ts.translateKey("voice.warning2");
drawString(fontRenderer, txt, 1 - fontRenderer.getStringWidth(txt), 18, 0xBB9999);
txt = ts.translateKey("voice.warning3");
drawString(fontRenderer, txt, 1 - fontRenderer.getStringWidth(txt), 28, 0xBB9999);
xo = 43;
EaglerAdapter.glTranslatef(0.0f, xo, 0.0f);
}
Voice.VoiceStatus status = EaglerAdapter.getVoiceStatus();
Voice.VoiceChannel channel = EaglerAdapter.getVoiceChannel();
boolean flag = false;
if(channel == Voice.VoiceChannel.NONE) {
flag = true;
}else {
if(status == Voice.VoiceStatus.CONNECTED) {
if(channel == Voice.VoiceChannel.PROXIMITY) {
txt = ts.translateKey("voice.connectedRadius").replace("$radius$", "" + EaglerAdapter.getVoiceProximity()).replace("$f$", "");
int w = fontRenderer.getStringWidth(txt);
int xx = width - 5 - (w * 3 / 4);
int yy = 15 + (xo * 3 / 4);
voiceScreenButtonChangeRadiusposX = xx;
voiceScreenButtonChangeRadiusposY = yy;
voiceScreenButtonChangeRadiusposW = width - 3 - xx;
voiceScreenButtonChangeRadiusposH = 12;
if(mx >= xx && my >= yy && mx < xx + voiceScreenButtonChangeRadiusposW && my < yy + 12) {
txt = ts.translateKey("voice.connectedRadius").replace("$radius$", "" + EaglerAdapter.getVoiceProximity())
.replace("$f$", "" + EnumChatFormatting.UNDERLINE) + EnumChatFormatting.RESET;
}
}else {
txt = ts.translateKey("voice.connectedGlobal");
}
voiceScreenVolumeIndicatorX = width - 15 - (104 * 3 / 4);
voiceScreenVolumeIndicatorY = 15 + (xo * 3 / 4) + 30;
voiceScreenVolumeIndicatorW = width - voiceScreenVolumeIndicatorX - 4;
voiceScreenVolumeIndicatorH = 23;
drawString(fontRenderer, txt, 1 - fontRenderer.getStringWidth(txt), 5, 0x66DD66);
drawRect(-90, 42, 2, 52, 0xFFAAAAAA);
drawRect(-89, 43, 1, 51, 0xFF222222);
float vol = EaglerAdapter.getVoiceListenVolume();
drawRect(-89, 43, -89 + (int)(vol * 90), 51, 0xFF993322);
for(float f = 0.07f; f < vol; f += 0.08f) {
int ww = (int)(f * 90);
drawRect(-89 + ww, 43, -89 + ww + 1, 51, 0xFF999999);
}
drawRect(-90, 57, 2, 67, 0xFFAAAAAA);
drawRect(-89, 58, 1, 66, 0xFF222222);
vol = EaglerAdapter.getVoiceSpeakVolume();
drawRect(-89, 58, -89 + (int)(vol * 90), 66, 0xFF993322);
for(float f = 0.07f; f < vol; f += 0.08f) {
int ww = (int)(f * 90);
drawRect(-89 + ww, 58, -89 + ww + 1, 66, 0xFF999999);
}
voiceGuiIcons.bindTexture();
EaglerAdapter.glColor4f(0.7f, 0.7f, 0.7f, 1.0f);
EaglerAdapter.glPushMatrix();
EaglerAdapter.glTranslatef(-104.0f, 41.5f, 0.0f);
EaglerAdapter.glScalef(0.7f, 0.7f, 0.7f);
drawTexturedModalRect(0, 0, 64, 112, 16, 16);
EaglerAdapter.glPopMatrix();
EaglerAdapter.glPushMatrix();
EaglerAdapter.glTranslatef(-104.0f, 56.5f, 0.0f);
EaglerAdapter.glScalef(0.7f, 0.7f, 0.7f);
if(EaglerAdapter.isKeyDown(mc.gameSettings.voicePTTKey)) {
EaglerAdapter.glColor4f(0.9f, 0.4f, 0.4f, 1.0f);
drawTexturedModalRect(0, 0, 64, 32, 16, 16);
}else {
drawTexturedModalRect(0, 0, 64, 0, 16, 16);
}
EaglerAdapter.glPopMatrix();
txt = ts.translateKey("voice.ptt").replace("$key$", EaglerAdapter.getKeyName(mc.gameSettings.voicePTTKey));
drawString(fontRenderer, txt, 1 - fontRenderer.getStringWidth(txt) - 10, 76, 0x66DD66);
voiceGuiIcons.bindTexture();
EaglerAdapter.glColor4f(0.4f, 0.9f, 0.4f, 1.0f);
EaglerAdapter.glPushMatrix();
EaglerAdapter.glTranslatef(-7.0f, 74.5f, 0.0f);
EaglerAdapter.glScalef(0.35f, 0.35f, 0.35f);
drawTexturedModalRect(0, 0, 32, 192, 32, 32);
EaglerAdapter.glPopMatrix();
txt = ts.translateKey("voice.playersListening");
EaglerAdapter.glPushMatrix();
EaglerAdapter.glTranslatef(0.0f, 98.0f, 0.0f);
EaglerAdapter.glScalef(1.2f, 1.2f, 1.2f);
drawString(fontRenderer, txt, -fontRenderer.getStringWidth(txt), 0, 0xFF7777);
EaglerAdapter.glPopMatrix();
List<String> playersToRender = EaglerAdapter.getVoiceRecent();
if(playersToRender.size() > 0) {
Set<String> playersSpeaking = EaglerAdapter.getVoiceSpeaking();
Set<String> playersMuted = EaglerAdapter.getVoiceMuted();
for(int i = 0, l = playersToRender.size(); i < l; ++i) {
txt = playersToRender.get(i);
boolean muted = playersMuted.contains(txt);
boolean speaking = !muted && playersSpeaking.contains(txt);
int mhy = voiceScreenVolumeIndicatorY + voiceScreenVolumeIndicatorH + 33 + i * 9;
boolean hovered = mx >= voiceScreenVolumeIndicatorX - 3 && my >= mhy && mx < voiceScreenVolumeIndicatorX + voiceScreenVolumeIndicatorW + 2 && my < mhy + 9;
float cm = hovered ? 1.5f : 1.0f;
voiceGuiIcons.bindTexture();
EaglerAdapter.glPushMatrix();
EaglerAdapter.glTranslatef(-100.0f, 115.0f + i * 12.0f, 0.0f);
EaglerAdapter.glScalef(0.78f, 0.78f, 0.78f);
if(muted) {
EaglerAdapter.glColor4f(1.0f * cm, 0.2f * cm, 0.2f * cm, 1.0f);
drawTexturedModalRect(0, 0, 64, 176, 16, 16);
}else if(speaking) {
EaglerAdapter.glColor4f(1.0f * cm, 1.0f * cm, 1.0f * cm, 1.0f);
drawTexturedModalRect(0, 0, 64, 144, 16, 16);
}else {
EaglerAdapter.glColor4f(0.65f * cm, 0.65f * cm, 0.65f * cm, 1.0f);
drawTexturedModalRect(0, 0, 64, 112, 16, 16);
}
EaglerAdapter.glPopMatrix();
if(muted) {
drawString(fontRenderer, txt, -84, 117 + i * 12, attenuate(0xCC4444, cm));
}else if(speaking) {
drawString(fontRenderer, txt, -84, 117 + i * 12, attenuate(0xCCCCCC, cm));
}else {
drawString(fontRenderer, txt, -84, 117 + i * 12, attenuate(0x999999, cm));
}
}
}else {
txt = "(none)";
drawString(fontRenderer, txt, -fontRenderer.getStringWidth(txt), 112, 0xAAAAAA);
}
}else if(status == Voice.VoiceStatus.CONNECTING) {
float fadeTimer = MathHelper.sin((float)((System.currentTimeMillis() % 700l) * 0.0014d) * 3.14159f) * 0.35f + 0.3f;
txt = ts.translateKey("voice.connecting");
EaglerAdapter.glEnable(EaglerAdapter.GL_BLEND);
EaglerAdapter.glBlendFunc(EaglerAdapter.GL_SRC_ALPHA, EaglerAdapter.GL_ONE_MINUS_SRC_ALPHA);
drawString(fontRenderer, txt, 1 - fontRenderer.getStringWidth(txt), 5, (0xFFDD77 | ((int)(Math.pow(fadeTimer, 1.0d / 2.2d) * 255.0f) << 24)));
EaglerAdapter.glDisable(EaglerAdapter.GL_BLEND);
}else if(status == Voice.VoiceStatus.UNAVAILABLE) {
txt = ts.translateKey("voice.unavailable");
drawString(fontRenderer, txt, 1 - fontRenderer.getStringWidth(txt), 5, 0xFF3333);
}else {
flag = true;
}
}
if(flag) {
txt = ts.translateKey("voice.notConnected");
drawString(fontRenderer, txt, 1 - fontRenderer.getStringWidth(txt), 5, 0xBB9999);
}
String OFFstring = ts.translateKey("voice.off");
String RADIUSstring = ts.translateKey("voice.radius");
String GLOBALstring = ts.translateKey("voice.global");
int OFFwidth = fontRenderer.getStringWidth(OFFstring);
int RADIUSwidth = fontRenderer.getStringWidth(RADIUSstring);
int GLOBALwidth = fontRenderer.getStringWidth(GLOBALstring);
voiceButtonOFFposX = 0 - OFFwidth - 8 - RADIUSwidth - 8 - GLOBALwidth;
voiceButtonOFFposY = 20;
voiceButtonOFFposW = OFFwidth + 5;
voiceButtonOFFposH = 15;
voiceScreenButtonOFFposX = voiceButtonOFFposX * 3 / 4 + width - 6;
voiceScreenButtonOFFposY = 15 + (voiceButtonOFFposY + xo) * 3 / 4;
voiceScreenButtonOFFposW = voiceButtonOFFposW * 3 / 4;
voiceScreenButtonOFFposH = voiceButtonOFFposH * 3 / 4;
voiceButtonRADIUSposX = 0 - RADIUSwidth - 8 - GLOBALwidth;
voiceButtonRADIUSposY = 20;
voiceButtonRADIUSposW = RADIUSwidth + 5;
voiceButtonRADIUSposH = 15;
voiceScreenButtonRADIUSposX = voiceButtonRADIUSposX * 3 / 4 + width - 6;
voiceScreenButtonRADIUSposY = 15 + (voiceButtonRADIUSposY + xo) * 3 / 4;
voiceScreenButtonRADIUSposW = voiceButtonRADIUSposW * 3 / 4;
voiceScreenButtonRADIUSposH = voiceButtonRADIUSposH * 3 / 4;
voiceButtonGLOBALposX = 0 - GLOBALwidth;
voiceButtonGLOBALposY = 20;
voiceButtonGLOBALposW = GLOBALwidth + 5;
voiceButtonGLOBALposH = 15;
voiceScreenButtonGLOBALposX = voiceButtonGLOBALposX * 3 / 4 + width - 6;
voiceScreenButtonGLOBALposY = 15 + (voiceButtonGLOBALposY + xo) * 3 / 4;
voiceScreenButtonGLOBALposW = voiceButtonGLOBALposW * 3 / 4;
voiceScreenButtonGLOBALposH = voiceButtonGLOBALposH * 3 / 4;
if(channel == Voice.VoiceChannel.NONE) {
drawOutline(voiceButtonOFFposX, voiceButtonOFFposY, voiceButtonOFFposW, voiceButtonOFFposH, 0xFFCCCCCC);
drawRect(voiceButtonOFFposX + 1, voiceButtonOFFposY + 1, voiceButtonOFFposX + voiceButtonOFFposW - 2,
voiceButtonOFFposY + voiceButtonOFFposH - 1, 0xFF222222);
}else if(mx >= voiceScreenButtonOFFposX && my >= voiceScreenButtonOFFposY && mx < voiceScreenButtonOFFposX +
voiceScreenButtonOFFposW && my < voiceScreenButtonOFFposY + voiceScreenButtonOFFposH) {
drawOutline(voiceButtonOFFposX, voiceButtonOFFposY, voiceButtonOFFposW, voiceButtonOFFposH, 0xFF777777);
}
if(channel == Voice.VoiceChannel.PROXIMITY) {
drawOutline(voiceButtonRADIUSposX, voiceButtonRADIUSposY, voiceButtonRADIUSposW, voiceButtonRADIUSposH, 0xFFCCCCCC);
drawRect(voiceButtonRADIUSposX + 1, voiceButtonRADIUSposY + 1, voiceButtonRADIUSposX + voiceButtonRADIUSposW - 2,
voiceButtonRADIUSposY + voiceButtonRADIUSposH - 1, 0xFF222222);
}else if(mx >= voiceScreenButtonRADIUSposX && my >= voiceScreenButtonRADIUSposY && mx < voiceScreenButtonRADIUSposX +
voiceScreenButtonRADIUSposW && my < voiceScreenButtonRADIUSposY + voiceScreenButtonRADIUSposH) {
drawOutline(voiceButtonRADIUSposX, voiceButtonRADIUSposY, voiceButtonRADIUSposW, voiceButtonRADIUSposH, 0xFF777777);
}
if(channel == Voice.VoiceChannel.GLOBAL) {
drawOutline(voiceButtonGLOBALposX, voiceButtonGLOBALposY, voiceButtonGLOBALposW, voiceButtonGLOBALposH, 0xFFCCCCCC);
drawRect(voiceButtonGLOBALposX + 1, voiceButtonGLOBALposY + 1, voiceButtonGLOBALposX + voiceButtonGLOBALposW - 2,
voiceButtonGLOBALposY + voiceButtonGLOBALposH - 1, 0xFF222222);
}else if(mx >= voiceScreenButtonGLOBALposX && my >= voiceScreenButtonGLOBALposY && mx < voiceScreenButtonGLOBALposX +
voiceScreenButtonGLOBALposW && my < voiceScreenButtonGLOBALposY + voiceScreenButtonGLOBALposH) {
drawOutline(voiceButtonGLOBALposX, voiceButtonGLOBALposY, voiceButtonGLOBALposW, voiceButtonGLOBALposH, 0xFF777777);
}
int enabledColor = (status == Voice.VoiceStatus.CONNECTED || channel == Voice.VoiceChannel.NONE) ? 0x66DD66 : 0xDDCC66;
int disabledColor = 0xDD4444;
if(status == Voice.VoiceStatus.UNAVAILABLE) {
enabledColor = disabledColor;
}
drawString(fontRenderer, OFFstring, 3 - OFFwidth - 8 - RADIUSwidth - 8 - GLOBALwidth, 24, channel == Voice.VoiceChannel.NONE ? enabledColor : disabledColor);
drawString(fontRenderer, RADIUSstring, 3 - RADIUSwidth - 8 - GLOBALwidth, 24, channel == Voice.VoiceChannel.PROXIMITY ? enabledColor : disabledColor);
drawString(fontRenderer, GLOBALstring, 3 - GLOBALwidth, 24, channel == Voice.VoiceChannel.GLOBAL ? enabledColor : disabledColor);
EaglerAdapter.glPopMatrix();
super.drawScreen(mx, my, partialTicks);
}
public static int attenuate(int cin, float f) {
return attenuate(cin, f, f, f, 1.0f);
}
public static int attenuate(int cin, float r, float g, float b, float a) {
float var10 = (float) (cin >> 24 & 255) / 255.0F;
float var6 = (float) (cin >> 16 & 255) / 255.0F;
float var7 = (float) (cin >> 8 & 255) / 255.0F;
float var8 = (float) (cin & 255) / 255.0F;
var10 *= a;
var6 *= r;
var7 *= g;
var8 *= b;
if(var10 > 1.0f) {
var10 = 1.0f;
}
if(var6 > 1.0f) {
var6 = 1.0f;
}
if(var7 > 1.0f) {
var7 = 1.0f;
}
if(var8 > 1.0f) {
var8 = 1.0f;
}
return (((int)(var10 * 255.0f) << 24) | ((int)(var6 * 255.0f) << 16) | ((int)(var7 * 255.0f) << 8) | (int)(var8 * 255.0f));
}
private void drawOutline(int x, int y, int w, int h, int color) {
drawRect(x, y, x + w, y + 1, color);
drawRect(x + w - 1, y + 1, x + w, y + h - 1, color);
drawRect(x, y + h - 1, x + w, y + h, color);
drawRect(x, y + 1, x + 1, y + h - 1, color);
}
public void mouseMovedOrUp(int par1, int par2, int par3) {
super.mouseMovedOrUp(par1, par2, par3);
if(showSliderBlocks || showSliderVolume) {
if(showSliderBlocks) {
if(par3 == 0) {
sliderBlocks.mouseReleased(par1, par2);
}
}else if(showSliderVolume) {
if(par3 == 0) {
sliderListenVolume.mouseReleased(par1, par2);
sliderSpeakVolume.mouseReleased(par1, par2);
}
}
throw new AbortedException();
}
}
public void keyTyped(char par1, int par2) {
if(showSliderBlocks || showSliderVolume || showPTTKeyConfig) {
if(showPTTKeyConfig) {
if(par2 == 1) {
showPTTKeyConfig = false;
}else {
mc.gameSettings.voicePTTKey = par2;
showNewPTTKey = 10;
}
}
throw new AbortedException();
}
}
public void mouseClicked(int mx, int my, int button) {
if(showSliderBlocks || showSliderVolume || showPTTKeyConfig) {
if(showSliderBlocks) {
sliderBlocks.mousePressed(mc, mx, my);
}else if(showSliderVolume) {
sliderListenVolume.mousePressed(mc, mx, my);
sliderSpeakVolume.mousePressed(mc, mx, my);
}
super.mouseClicked(mx, my, button);
throw new AbortedException();
}
Voice.VoiceStatus status = EaglerAdapter.getVoiceStatus();
Voice.VoiceChannel channel = EaglerAdapter.getVoiceChannel();
if(button == 0) {
if(EaglerAdapter.voiceAvailable() && EaglerAdapter.voiceAllowed()) {
if(mx >= voiceScreenButtonOFFposX && my >= voiceScreenButtonOFFposY && mx < voiceScreenButtonOFFposX +
voiceScreenButtonOFFposW && my < voiceScreenButtonOFFposY + voiceScreenButtonOFFposH) {
EaglerAdapter.enableVoice(Voice.VoiceChannel.NONE);
this.mc.sndManager.playSoundFX("random.click", 1.0F, 1.0F);
}else if(mx >= voiceScreenButtonRADIUSposX && my >= voiceScreenButtonRADIUSposY && mx < voiceScreenButtonRADIUSposX +
voiceScreenButtonRADIUSposW && my < voiceScreenButtonRADIUSposY + voiceScreenButtonRADIUSposH) {
EaglerAdapter.enableVoice(Voice.VoiceChannel.PROXIMITY);
this.mc.sndManager.playSoundFX("random.click", 1.0F, 1.0F);
}else if(mx >= voiceScreenButtonGLOBALposX && my >= voiceScreenButtonGLOBALposY && mx < voiceScreenButtonGLOBALposX +
voiceScreenButtonGLOBALposW && my < voiceScreenButtonGLOBALposY + voiceScreenButtonGLOBALposH) {
EaglerAdapter.enableVoice(Voice.VoiceChannel.GLOBAL);
this.mc.sndManager.playSoundFX("random.click", 1.0F, 1.0F);
}else if(channel == Voice.VoiceChannel.PROXIMITY && status == Voice.VoiceStatus.CONNECTED && mx >= voiceScreenButtonChangeRadiusposX &&
my >= voiceScreenButtonChangeRadiusposY && mx < voiceScreenButtonChangeRadiusposX + voiceScreenButtonChangeRadiusposW &&
my < voiceScreenButtonChangeRadiusposY + voiceScreenButtonChangeRadiusposH) {
showSliderBlocks = true;
sliderBlocks.sliderValue = (EaglerAdapter.getVoiceProximity() - 5) / 17.0f;
this.mc.sndManager.playSoundFX("random.click", 1.0F, 1.0F);
}else if(status == Voice.VoiceStatus.CONNECTED && channel != Voice.VoiceChannel.NONE && mx >= voiceScreenVolumeIndicatorX &&
my >= voiceScreenVolumeIndicatorY && mx < voiceScreenVolumeIndicatorX + voiceScreenVolumeIndicatorW &&
my < voiceScreenVolumeIndicatorY + voiceScreenVolumeIndicatorH) {
showSliderVolume = true;
sliderListenVolume.sliderValue = EaglerAdapter.getVoiceListenVolume();
sliderSpeakVolume.sliderValue = EaglerAdapter.getVoiceSpeakVolume();
this.mc.sndManager.playSoundFX("random.click", 1.0F, 1.0F);
}else if(status == Voice.VoiceStatus.CONNECTED && channel != Voice.VoiceChannel.NONE && mx >= voiceScreenVolumeIndicatorX - 1 &&
my >= voiceScreenVolumeIndicatorY + voiceScreenVolumeIndicatorH + 2 && mx < voiceScreenVolumeIndicatorX + voiceScreenVolumeIndicatorW + 2 &&
my < voiceScreenVolumeIndicatorY + voiceScreenVolumeIndicatorH + 12) {
showPTTKeyConfig = true;
this.mc.sndManager.playSoundFX("random.click", 1.0F, 1.0F);
}else if(status == Voice.VoiceStatus.CONNECTED) {
List<String> playersToRender = EaglerAdapter.getVoiceRecent();
if(playersToRender.size() > 0) {
Set<String> playersMuted = EaglerAdapter.getVoiceMuted();
for(int i = 0, l = playersToRender.size(); i < l; ++i) {
String txt = playersToRender.get(i);
boolean muted = playersMuted.contains(txt);
int mhy = voiceScreenVolumeIndicatorY + voiceScreenVolumeIndicatorH + 33 + i * 9;
if(mx >= voiceScreenVolumeIndicatorX - 3 && my >= mhy && mx < voiceScreenVolumeIndicatorX + voiceScreenVolumeIndicatorW + 2 && my < mhy + 9) {
EaglerAdapter.setVoiceMuted(txt, !muted);
this.mc.sndManager.playSoundFX("random.click", 1.0F, 1.0F);
break;
}
}
}
}
}
}
}
public void actionPerformed(GuiButton btn) {
if(btn.id == 2) {
showSliderBlocks = false;
EaglerAdapter.setVoiceProximity(mc.gameSettings.voiceListenRadius = (int)((sliderBlocks.sliderValue * 17.0f) + 5.0f));
mc.gameSettings.saveOptions();
}else if(btn.id == 3) {
showSliderVolume = false;
EaglerAdapter.setVoiceListenVolume(mc.gameSettings.voiceListenVolume = sliderListenVolume.sliderValue);
EaglerAdapter.setVoiceSpeakVolume(mc.gameSettings.voiceSpeakVolume = sliderSpeakVolume.sliderValue);
mc.gameSettings.saveOptions();
}else if(btn.id == 4) {
showPTTKeyConfig = false;
mc.gameSettings.saveOptions();
}
}
public void updateScreen() {
if(showNewPTTKey > 0) {
--showNewPTTKey;
if(showNewPTTKey == 0) {
showPTTKeyConfig = false;
mc.gameSettings.saveOptions();
}
}
}
public boolean isBlockingInput() {
return showSliderBlocks || showSliderVolume || showPTTKeyConfig;
}
}

View file

@ -0,0 +1,229 @@
package net.lax1dude.eaglercraft;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import net.minecraft.client.Minecraft;
import net.minecraft.src.Gui;
import net.minecraft.src.GuiChat;
import net.minecraft.src.GuiIngameMenu;
public class GuiVoiceOverlay extends Gui {
public final Minecraft mc;
public int width;
public int height;
private long pttTimer = 0l;
public GuiVoiceOverlay(Minecraft mc) {
this.mc = mc;
}
public void setResolution(int w, int h) {
this.width = w;
this.height = h;
}
private static final TextureLocation voiceGuiIcons = new TextureLocation("/gui/voice.png");
public void drawOverlay() {
if(mc.theWorld != null && EaglerAdapter.getVoiceStatus() == Voice.VoiceStatus.CONNECTED && EaglerAdapter.getVoiceChannel() != Voice.VoiceChannel.NONE &&
!(mc.currentScreen != null && (mc.currentScreen instanceof GuiIngameMenu))) {
if(mc.currentScreen != null && mc.currentScreen.doesGuiPauseGame()) {
return;
}
EaglerAdapter.glPushMatrix();
if(mc.currentScreen == null || (mc.currentScreen instanceof GuiChat)) {
EaglerAdapter.glTranslatef(width / 2 + 77, height - 56, 0.0f);
if(mc.thePlayer == null || mc.thePlayer.capabilities.isCreativeMode) {
EaglerAdapter.glTranslatef(0.0f, 16.0f, 0.0f);
}
}else {
EaglerAdapter.glTranslatef(width / 2 + 10, 4, 0.0f);
}
EaglerAdapter.glScalef(0.75f, 0.75f, 0.75f);
String txxt = "press '" + EaglerAdapter.getKeyName(mc.gameSettings.voicePTTKey) + "'";
drawString(mc.fontRenderer, txxt, -3 - mc.fontRenderer.getStringWidth(txxt), 9, 0xDDDDDD);
EaglerAdapter.glScalef(0.66f, 0.66f, 0.66f);
voiceGuiIcons.bindTexture();
if(EaglerAdapter.isKeyDown(mc.gameSettings.voicePTTKey)) {
long millis = System.currentTimeMillis();
if(pttTimer == 0l) {
pttTimer = millis;
}
EaglerAdapter.glColor4f(0.2f, 0.2f, 0.2f, 1.0f);
drawTexturedModalRect(0, 0, 0, 32, 32, 32);
EaglerAdapter.glTranslatef(-1.5f, -1.5f, 0.0f);
if(millis - pttTimer < 1050l) {
if((millis - pttTimer) % 300l < 150l) {
EaglerAdapter.glColor4f(0.9f, 0.2f, 0.2f, 1.0f);
}else {
EaglerAdapter.glColor4f(0.9f, 0.7f, 0.7f, 1.0f);
}
}else {
EaglerAdapter.glColor4f(0.9f, 0.3f, 0.3f, 1.0f);
}
drawTexturedModalRect(0, 0, 0, 32, 32, 32);
}else {
pttTimer = 0l;
EaglerAdapter.glColor4f(0.2f, 0.2f, 0.2f, 1.0f);
drawTexturedModalRect(0, 0, 0, 0, 32, 32);
EaglerAdapter.glTranslatef(-1.5f, -1.5f, 0.0f);
EaglerAdapter.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
drawTexturedModalRect(0, 0, 0, 0, 32, 32);
EaglerAdapter.glTranslatef(-0.5f, -0.5f, 0.0f);
drawTexturedModalRect(0, 0, 0, 0, 32, 32);
}
EaglerAdapter.glPopMatrix();
if(EaglerAdapter.getVoiceChannel() == Voice.VoiceChannel.PROXIMITY) {
Set<String> listeners = EaglerAdapter.getVoiceListening();
if(listeners.size() > 0) {
Set<String> speakers = EaglerAdapter.getVoiceSpeaking();
Set<String> muted = EaglerAdapter.getVoiceMuted();
List<String> listenerList = new ArrayList();
listenerList.addAll(listeners);
listenerList.removeAll(muted);
while(listenerList.size() > 5) {
boolean flag = false;
for(int i = 0, l = listenerList.size(); i < l; ++i) {
if(!speakers.contains(listenerList.get(i))) {
listenerList.remove(i);
flag = true;
break;
}
}
if(!flag) {
break;
}
}
int more = listenerList.size() - 5;
int ww = width;
int hh = height;
if(mc.currentScreen != null && (mc.currentScreen instanceof GuiChat)) {
hh -= 15;
}
int left = 50;
for(int i = 0, l = listenerList.size(); i < l && i < 5; ++i) {
int j = mc.fontRenderer.getStringWidth(listenerList.get(i)) + 4;
if(j > left) {
left = j;
}
}
if(more > 0) {
EaglerAdapter.glPushMatrix();
EaglerAdapter.glTranslatef(ww - left + 3, hh - 10, left);
EaglerAdapter.glScalef(0.75f, 0.75f, 0.75f);
drawString(mc.fontRenderer, "(" + more + " more)", 0, 0, 0xBBBBBB);
EaglerAdapter.glPopMatrix();
hh -= 9;
}
for(int i = 0, l = listenerList.size(); i < l && i < 5; ++i) {
String txt = listenerList.get(i);
boolean speaking = speakers.contains(txt);
float speakf = speaking ? 1.0f : 0.75f;
drawString(mc.fontRenderer, txt, ww - left, hh - 13 - i * 11, speaking ? 0xEEEEEE : 0xBBBBBB);
voiceGuiIcons.bindTexture();
EaglerAdapter.glPushMatrix();
EaglerAdapter.glTranslatef(ww - left - 14, hh - 14 - i * 11, 0.0f);
EaglerAdapter.glScalef(0.75f, 0.75f, 0.75f);
EaglerAdapter.glColor4f(speakf * 0.2f, speakf * 0.2f, speakf * 0.2f, 1.0f);
drawTexturedModalRect(0, 0, 64, speaking ? 144 : 176, 16, 16);
EaglerAdapter.glTranslatef(0.25f, 0.25f, 0.0f);
drawTexturedModalRect(0, 0, 64, speaking ? 144 : 176, 16, 16);
EaglerAdapter.glTranslatef(-1.25f, -1.25f, 0.0f);
EaglerAdapter.glColor4f(speakf, speakf, speakf, 1.0f);
drawTexturedModalRect(0, 0, 64, speaking ? 144 : 176, 16, 16);
EaglerAdapter.glPopMatrix();
}
}
}else if(EaglerAdapter.getVoiceChannel() == Voice.VoiceChannel.GLOBAL) {
Set<String> speakers = EaglerAdapter.getVoiceSpeaking();
Set<String> muted = EaglerAdapter.getVoiceMuted();
List<String> listenerList = new ArrayList();
listenerList.addAll(speakers);
listenerList.removeAll(muted);
int more = listenerList.size() - 5;
int ww = width;
int hh = height;
if(mc.currentScreen != null && (mc.currentScreen instanceof GuiChat)) {
hh -= 15;
}
int left = 50;
for(int i = 0, l = listenerList.size(); i < l && i < 5; ++i) {
int j = mc.fontRenderer.getStringWidth(listenerList.get(i)) + 4;
if(j > left) {
left = j;
}
}
if(more > 0) {
EaglerAdapter.glPushMatrix();
EaglerAdapter.glTranslatef(ww - left + 3, hh - 10, left);
EaglerAdapter.glScalef(0.75f, 0.75f, 0.75f);
drawString(mc.fontRenderer, "(" + more + " more)", 0, 0, 0xBBBBBB);
EaglerAdapter.glPopMatrix();
hh -= 9;
}
for(int i = 0, l = listenerList.size(); i < l && i < 5; ++i) {
String txt = listenerList.get(i);
drawString(mc.fontRenderer, txt, ww - left, hh - 13 - i * 11, 0xEEEEEE);
voiceGuiIcons.bindTexture();
EaglerAdapter.glPushMatrix();
EaglerAdapter.glTranslatef(ww - left - 14, hh - 14 - i * 11, 0.0f);
EaglerAdapter.glScalef(0.75f, 0.75f, 0.75f);
EaglerAdapter.glColor4f(0.2f, 0.2f, 0.2f, 1.0f);
drawTexturedModalRect(0, 0, 64, 144, 16, 16);
EaglerAdapter.glTranslatef(0.25f, 0.25f, 0.0f);
drawTexturedModalRect(0, 0, 64, 144, 16, 16);
EaglerAdapter.glTranslatef(-1.25f, -1.25f, 0.0f);
EaglerAdapter.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
drawTexturedModalRect(0, 0, 64, 144, 16, 16);
EaglerAdapter.glPopMatrix();
}
}
}
}
}

View file

@ -0,0 +1,13 @@
package net.lax1dude.eaglercraft;
public class Voice {
public static enum VoiceChannel {
NONE, GLOBAL, PROXIMITY;
}
public static enum VoiceStatus {
DISCONNECTED, CONNECTING, CONNECTED, UNAVAILABLE;
}
}

View file

@ -117,6 +117,7 @@ public class WebsocketNetworkManager implements INetworkManager {
} }
public void serverShutdown() { public void serverShutdown() {
EaglerAdapter.setVoiceStatus(Voice.VoiceStatus.DISCONNECTED);
if(EaglerAdapter.connectionOpen()) { if(EaglerAdapter.connectionOpen()) {
EaglerAdapter.endConnection(); EaglerAdapter.endConnection();
EaglerAdapter.setDebugVar("minecraftServer", "null"); EaglerAdapter.setDebugVar("minecraftServer", "null");
@ -132,6 +133,7 @@ public class WebsocketNetworkManager implements INetworkManager {
} }
public void closeConnections() { public void closeConnections() {
EaglerAdapter.setVoiceStatus(Voice.VoiceStatus.DISCONNECTED);
if(EaglerAdapter.connectionOpen()) { if(EaglerAdapter.connectionOpen()) {
EaglerAdapter.endConnection(); EaglerAdapter.endConnection();
EaglerAdapter.setDebugVar("minecraftServer", "null"); EaglerAdapter.setDebugVar("minecraftServer", "null");

View file

@ -11,7 +11,7 @@ import net.lax1dude.eaglercraft.EaglerProfile;
import net.lax1dude.eaglercraft.GuiScreenEditProfile; import net.lax1dude.eaglercraft.GuiScreenEditProfile;
import net.lax1dude.eaglercraft.GuiScreenLicense; import net.lax1dude.eaglercraft.GuiScreenLicense;
import net.lax1dude.eaglercraft.GuiScreenVoiceChannel; import net.lax1dude.eaglercraft.GuiVoiceOverlay;
import net.lax1dude.eaglercraft.LocalStorageManager; import net.lax1dude.eaglercraft.LocalStorageManager;
import net.lax1dude.eaglercraft.adapter.Tessellator; import net.lax1dude.eaglercraft.adapter.Tessellator;
import net.lax1dude.eaglercraft.glemu.EffectPipeline; import net.lax1dude.eaglercraft.glemu.EffectPipeline;
@ -165,6 +165,8 @@ public class Minecraft implements Runnable {
/** Profiler currently displayed in the debug screen pie chart */ /** Profiler currently displayed in the debug screen pie chart */
private String debugProfilerName = "root"; private String debugProfilerName = "root";
public GuiVoiceOverlay voiceOverlay;
public Minecraft() { public Minecraft() {
this.tempDisplayHeight = 480; this.tempDisplayHeight = 480;
@ -240,6 +242,7 @@ public class Minecraft implements Runnable {
this.checkGLError("Post startup"); this.checkGLError("Post startup");
this.guiAchievement = new GuiAchievement(this); this.guiAchievement = new GuiAchievement(this);
this.ingameGUI = new GuiIngame(this); this.ingameGUI = new GuiIngame(this);
this.voiceOverlay = new GuiVoiceOverlay(this);
//if (this.serverName != null) { //if (this.serverName != null) {
// this.displayGuiScreen(new GuiConnecting(new GuiMainMenu(), this, this.serverName, this.serverPort)); // this.displayGuiScreen(new GuiConnecting(new GuiMainMenu(), this, this.serverName, this.serverPort));
@ -443,7 +446,6 @@ public class Minecraft implements Runnable {
e.printStackTrace(); e.printStackTrace();
} }
GuiScreenVoiceChannel.fadeInTimer = System.currentTimeMillis();
EaglerAdapter.glDisable(EaglerAdapter.GL_BLEND); EaglerAdapter.glDisable(EaglerAdapter.GL_BLEND);
EaglerAdapter.glEnable(EaglerAdapter.GL_ALPHA_TEST); EaglerAdapter.glEnable(EaglerAdapter.GL_ALPHA_TEST);
EaglerAdapter.glAlphaFunc(EaglerAdapter.GL_GREATER, 0.1F); EaglerAdapter.glAlphaFunc(EaglerAdapter.GL_GREATER, 0.1F);
@ -1039,12 +1041,15 @@ public class Minecraft implements Runnable {
this.displayWidth = par1 <= 0 ? 1 : par1; this.displayWidth = par1 <= 0 ? 1 : par1;
this.displayHeight = par2 <= 0 ? 1 : par2; this.displayHeight = par2 <= 0 ? 1 : par2;
ScaledResolution var3 = new ScaledResolution(this.gameSettings, par1, par2);
int var4 = var3.getScaledWidth();
int var5 = var3.getScaledHeight();
if (this.currentScreen != null) { if (this.currentScreen != null) {
ScaledResolution var3 = new ScaledResolution(this.gameSettings, par1, par2);
int var4 = var3.getScaledWidth();
int var5 = var3.getScaledHeight();
this.currentScreen.setWorldAndResolution(this, var4, var5); this.currentScreen.setWorldAndResolution(this, var4, var5);
} }
this.voiceOverlay.setResolution(var4, var5);
} }
/** /**
@ -1104,7 +1109,7 @@ public class Minecraft implements Runnable {
} }
GuiMultiplayer.tickRefreshCooldown(); GuiMultiplayer.tickRefreshCooldown();
GuiScreenVoiceChannel.tickVoiceConnection(); EaglerAdapter.tickVoice();
if (this.currentScreen == null || this.currentScreen.allowUserInput) { if (this.currentScreen == null || this.currentScreen.allowUserInput) {
this.mcProfiler.endStartSection("mouse"); this.mcProfiler.endStartSection("mouse");

View file

@ -7,7 +7,6 @@ import net.minecraft.client.Minecraft;
import net.lax1dude.eaglercraft.EaglerAdapter; import net.lax1dude.eaglercraft.EaglerAdapter;
import net.lax1dude.eaglercraft.EaglerImage; import net.lax1dude.eaglercraft.EaglerImage;
import net.lax1dude.eaglercraft.EaglercraftRandom; import net.lax1dude.eaglercraft.EaglercraftRandom;
import net.lax1dude.eaglercraft.GuiScreenVoiceChannel;
import net.lax1dude.eaglercraft.TextureLocation; import net.lax1dude.eaglercraft.TextureLocation;
import net.lax1dude.eaglercraft.adapter.Tessellator; import net.lax1dude.eaglercraft.adapter.Tessellator;
import net.lax1dude.eaglercraft.glemu.EffectPipeline; import net.lax1dude.eaglercraft.glemu.EffectPipeline;
@ -876,7 +875,7 @@ public class EntityRenderer {
} }
} }
GuiScreenVoiceChannel.drawOverlay(); mc.voiceOverlay.drawOverlay();
} }
} }

View file

@ -134,9 +134,14 @@ public class GameSettings {
public boolean allowFNAWSkins = true; public boolean allowFNAWSkins = true;
public boolean showOtherCapes = true; public boolean showOtherCapes = true;
public int chunkUpdatePerFrame = 0; public int chunkUpdatePerFrame = 0;
public int voiceListenRadius = 16;
public float voiceListenVolume = 0.5f;
public float voiceSpeakVolume = 0.5f;
public int voicePTTKey = 47;
public GameSettings(Minecraft par1Minecraft) { public GameSettings(Minecraft par1Minecraft) {
this.keyBindings = new KeyBinding[] { this.keyBindAttack, this.keyBindUseItem, this.keyBindForward, this.keyBindLeft, this.keyBindBack, this.keyBindRight, this.keyBindJump, this.keyBindSneak, this.keyBindDrop, this.keyBindInventory, this.keyBindings = new KeyBinding[] { this.keyBindAttack, this.keyBindUseItem, this.keyBindForward, this.keyBindLeft, this.keyBindBack, this.keyBindRight, this.keyBindJump, this.keyBindSneak, this.keyBindDrop, this.keyBindInventory,
this.keyBindChat, this.keyBindPlayerList, this.keyBindPickBlock, this.keyBindSprint, this.keyBindZoom, this.keyBindFunction }; this.keyBindChat, this.keyBindPlayerList, this.keyBindPickBlock, this.keyBindSprint, this.keyBindZoom, this.keyBindFunction };
@ -526,6 +531,17 @@ public class GameSettings {
if(yee.hasKey("allowFNAWSkins")) allowFNAWSkins = yee.getBoolean("allowFNAWSkins"); if(yee.hasKey("allowFNAWSkins")) allowFNAWSkins = yee.getBoolean("allowFNAWSkins");
if(yee.hasKey("showOtherCapes")) showOtherCapes = yee.getBoolean("showOtherCapes"); if(yee.hasKey("showOtherCapes")) showOtherCapes = yee.getBoolean("showOtherCapes");
if(yee.hasKey("chunkUpdates")) chunkUpdatePerFrame = yee.getInteger("chunkUpdates"); if(yee.hasKey("chunkUpdates")) chunkUpdatePerFrame = yee.getInteger("chunkUpdates");
if(yee.hasKey("voiceListenVolume")) voiceListenVolume = yee.getFloat("voiceListenVolume");
if(yee.hasKey("voiceSpeakVolume")) voiceSpeakVolume = yee.getFloat("voiceSpeakVolume");
if(yee.hasKey("voicePTTKey")) voicePTTKey = yee.getInteger("voicePTTKey");
if(yee.hasKey("voiceListenRadius")) voiceListenRadius = yee.getInteger("voiceListenRadius");
if(voiceListenRadius < 5) voiceListenRadius = 5;
else if(voiceListenRadius > 22) voiceListenRadius = 22;
EaglerAdapter.setVoiceListenVolume(voiceListenVolume);
EaglerAdapter.setVoiceSpeakVolume(voiceSpeakVolume);
EaglerAdapter.setVoiceProximity(voiceListenRadius);
for (int var4 = 0; var4 < this.keyBindings.length; ++var4) { for (int var4 = 0; var4 < this.keyBindings.length; ++var4) {
if(yee.hasKey(keyBindings[var4].keyDescription)) this.keyBindings[var4].keyCode = yee.getInteger(keyBindings[var4].keyDescription); if(yee.hasKey(keyBindings[var4].keyDescription)) this.keyBindings[var4].keyCode = yee.getInteger(keyBindings[var4].keyDescription);
@ -589,6 +605,10 @@ public class GameSettings {
yee.setBoolean("allowFNAWSkins", allowFNAWSkins); yee.setBoolean("allowFNAWSkins", allowFNAWSkins);
yee.setBoolean("showOtherCapes", showOtherCapes); yee.setBoolean("showOtherCapes", showOtherCapes);
yee.setInteger("chunkUpdates", chunkUpdatePerFrame); yee.setInteger("chunkUpdates", chunkUpdatePerFrame);
yee.setFloat("voiceListenVolume", voiceListenVolume);
yee.setFloat("voiceSpeakVolume", voiceSpeakVolume);
yee.setInteger("voicePTTKey", voicePTTKey);
yee.setInteger("voiceListenRadius", voiceListenRadius);
for (int var4 = 0; var4 < this.keyBindings.length; ++var4) { for (int var4 = 0; var4 < this.keyBindings.length; ++var4) {
yee.setInteger(keyBindings[var4].keyDescription, keyBindings[var4].keyCode); yee.setInteger(keyBindings[var4].keyDescription, keyBindings[var4].keyCode);
@ -626,4 +646,4 @@ public class GameSettings {
public boolean shouldRenderClouds() { public boolean shouldRenderClouds() {
return this.renderDistance < 2 && this.clouds; return this.renderDistance < 2 && this.clouds;
} }
} }

View file

@ -464,12 +464,15 @@ public class GuiIngame extends Gui {
var8.drawStringWithShadow("x: "+MathHelper.floor_double(this.mc.thePlayer.posX)+", y: "+MathHelper.floor_double(this.mc.thePlayer.posY)+", z: "+MathHelper.floor_double(this.mc.thePlayer.posZ), 2, 12, 16777215); var8.drawStringWithShadow("x: "+MathHelper.floor_double(this.mc.thePlayer.posX)+", y: "+MathHelper.floor_double(this.mc.thePlayer.posY)+", z: "+MathHelper.floor_double(this.mc.thePlayer.posZ), 2, 12, 16777215);
} }
int offset = this.mc.isChatOpen() ? 135 : 0; if(mc.currentScreen == null || !(mc.currentScreen instanceof GuiIngameMenu)) {
int offset2 = this.mc.isChatOpen() ? 4 : 0; int offset = this.mc.isChatOpen() ? 135 : 0;
String str = "not using an xbox live account"; int offset2 = this.mc.isChatOpen() ? 4 : 0;
var8.drawStringWithShadow(str, (var6 * 4 / 3) - 2 - var8.getStringWidth(str) - offset, 2 + offset2, 0xFFDDDD); String str = "not using an xbox live account";
str = "eaglercraft: " + ConfigConstants.version; var8.drawStringWithShadow(str, (var6 * 4 / 3) - 2 - var8.getStringWidth(str) - offset, 2 + offset2, 0xFFDDDD);
var8.drawStringWithShadow(str, (var6 * 4 / 3) - 2 - var8.getStringWidth(str) - offset, 12 + offset2, 14737632); str = "eaglercraft: " + ConfigConstants.version;
var8.drawStringWithShadow(str, (var6 * 4 / 3) - 2 - var8.getStringWidth(str) - offset, 12 + offset2, 14737632);
}
EaglerAdapter.glPopMatrix(); EaglerAdapter.glPopMatrix();
} }

View file

@ -1,11 +1,20 @@
package net.minecraft.src; package net.minecraft.src;
import net.lax1dude.eaglercraft.AbortedException;
import net.lax1dude.eaglercraft.ConfigConstants;
import net.lax1dude.eaglercraft.EaglerAdapter; import net.lax1dude.eaglercraft.EaglerAdapter;
import net.lax1dude.eaglercraft.GuiScreenSkinCapeSettings; import net.lax1dude.eaglercraft.GuiScreenSkinCapeSettings;
import net.lax1dude.eaglercraft.GuiScreenVoiceChannel; import net.lax1dude.eaglercraft.GuiVoiceMenu;
import net.minecraft.client.Minecraft;
public class GuiIngameMenu extends GuiScreen { public class GuiIngameMenu extends GuiScreen {
private GuiVoiceMenu voiceMenu;
public GuiIngameMenu() {
voiceMenu = new GuiVoiceMenu(this);
}
/** /**
* Adds the buttons (and other controls) to the screen in question. * Adds the buttons (and other controls) to the screen in question.
*/ */
@ -19,7 +28,6 @@ public class GuiIngameMenu extends GuiScreen {
} }
this.buttonList.add(new GuiButton(4, this.width / 2 - 100, this.height / 4 + 24 + var1, StatCollector.translateToLocal("menu.returnToGame"))); this.buttonList.add(new GuiButton(4, this.width / 2 - 100, this.height / 4 + 24 + var1, StatCollector.translateToLocal("menu.returnToGame")));
//this.buttonList.add(new GuiButton(5, this.width / 2 - 100, this.height / 4 + 48 + var1, StatCollector.translateToLocal("menu.voicechannel")));
this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 4 + 96 + var1, 98, 20, StatCollector.translateToLocal("menu.options"))); this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 4 + 96 + var1, 98, 20, StatCollector.translateToLocal("menu.options")));
GuiButton var3; GuiButton var3;
this.buttonList.add(var3 = new GuiButton(7, this.width / 2 + 2, this.height / 4 + 96 + var1, 98, 20, StatCollector.translateToLocal("menu.shareToLan"))); this.buttonList.add(var3 = new GuiButton(7, this.width / 2 + 2, this.height / 4 + 96 + var1, 98, 20, StatCollector.translateToLocal("menu.shareToLan")));
@ -54,10 +62,6 @@ public class GuiIngameMenu extends GuiScreen {
this.mc.sndManager.resumeAllSounds(); this.mc.sndManager.resumeAllSounds();
break; break;
case 5:
this.mc.displayGuiScreen(new GuiScreenVoiceChannel(this));
break;
case 8: case 8:
this.mc.displayGuiScreen(new GuiScreenSkinCapeSettings(this)); this.mc.displayGuiScreen(new GuiScreenSkinCapeSettings(this));
break; break;
@ -69,6 +73,7 @@ public class GuiIngameMenu extends GuiScreen {
*/ */
public void updateScreen() { public void updateScreen() {
super.updateScreen(); super.updateScreen();
voiceMenu.updateScreen();
} }
/** /**
@ -88,5 +93,55 @@ public class GuiIngameMenu extends GuiScreen {
this.drawString(fontRenderer, var1.translateKey("menu.skinCapeSettingsNote1"), 0, 9, c); this.drawString(fontRenderer, var1.translateKey("menu.skinCapeSettingsNote1"), 0, 9, c);
EaglerAdapter.glPopMatrix(); EaglerAdapter.glPopMatrix();
} }
drawString(fontRenderer, "Eaglercraft: " + ConfigConstants.version, 6, 27, 0x999999);
try {
if(voiceMenu.isBlockingInput()) {
super.drawScreen(0, 0, par3);
}else {
super.drawScreen(par1, par2, par3);
}
voiceMenu.drawScreen(par1, par2, par3);
}catch(AbortedException ex) {
}
} }
/**
* Fired when a key is typed. This is the equivalent of
* KeyListener.keyTyped(KeyEvent e).
*/
protected void keyTyped(char par1, int par2) {
try {
voiceMenu.keyTyped(par1, par2);
super.keyTyped(par1, par2);
}catch(AbortedException ex) {
}
}
/**
* Called when the mouse is clicked.
*/
protected void mouseClicked(int par1, int par2, int par3) {
try {
voiceMenu.mouseClicked(par1, par2, par3);
super.mouseClicked(par1, par2, par3);
}catch(AbortedException ex) {
}
}
public void setWorldAndResolution(Minecraft par1Minecraft, int par2, int par3) {
super.setWorldAndResolution(par1Minecraft, par2, par3);
voiceMenu.setWorldAndResolution(par1Minecraft, par2, par3);
}
protected void mouseMovedOrUp(int par1, int par2, int par3) {
try {
voiceMenu.mouseMovedOrUp(par1, par2, par3);
super.mouseMovedOrUp(par1, par2, par3);
}catch(AbortedException ex) {
}
}
} }

View file

@ -90,6 +90,7 @@ public class GuiVideoSettings extends GuiScreen {
int var4 = var3.getScaledWidth(); int var4 = var3.getScaledWidth();
int var5 = var3.getScaledHeight(); int var5 = var3.getScaledHeight();
this.setWorldAndResolution(this.mc, var4, var5); this.setWorldAndResolution(this.mc, var4, var5);
this.mc.voiceOverlay.setResolution(var4, var5);
} }
} }
} }

View file

@ -2,6 +2,7 @@ package net.minecraft.src;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.lax1dude.eaglercraft.TextureLocation; import net.lax1dude.eaglercraft.TextureLocation;
import net.lax1dude.eaglercraft.Voice;
import net.lax1dude.eaglercraft.adapter.Tessellator; import net.lax1dude.eaglercraft.adapter.Tessellator;
import net.lax1dude.eaglercraft.DefaultSkinRenderer; import net.lax1dude.eaglercraft.DefaultSkinRenderer;
import net.lax1dude.eaglercraft.EaglerAdapter; import net.lax1dude.eaglercraft.EaglerAdapter;
@ -431,6 +432,8 @@ public abstract class RenderLiving extends Render {
this.renderLivingLabel(par1EntityLiving, par8Str, par2, par4, par6, 64); this.renderLivingLabel(par1EntityLiving, par8Str, par2, par4, par6, 64);
} }
} }
private static final TextureLocation voiceGuiIcons = new TextureLocation("/gui/voice.png");
/** /**
* Draws the debug or playername text above a living * Draws the debug or playername text above a living
@ -494,6 +497,86 @@ public abstract class RenderLiving extends Render {
EaglerAdapter.glEnable(EaglerAdapter.GL_LIGHTING); EaglerAdapter.glEnable(EaglerAdapter.GL_LIGHTING);
EaglerAdapter.glDisable(EaglerAdapter.GL_BLEND); EaglerAdapter.glDisable(EaglerAdapter.GL_BLEND);
EaglerAdapter.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); EaglerAdapter.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
if(par1EntityLiving instanceof EntityOtherPlayerMP) {
if(EaglerAdapter.getVoiceStatus() == Voice.VoiceStatus.CONNECTED) {
String nm = ((EntityOtherPlayerMP) par1EntityLiving).username;
boolean mute = EaglerAdapter.getVoiceMuted().contains(nm);
if(mute || EaglerAdapter.getVoiceSpeaking().contains(nm)) {
EaglerAdapter.glDisable(EaglerAdapter.GL_LIGHTING);
EaglerAdapter.glDisable(EaglerAdapter.GL_TEXTURE_2D);
EaglerAdapter.glDisable(EaglerAdapter.GL_ALPHA_TEST);
EaglerAdapter.glDepthMask(false);
EaglerAdapter.glDisable(EaglerAdapter.GL_DEPTH_TEST);
EaglerAdapter.glEnable(EaglerAdapter.GL_BLEND);
EaglerAdapter.glPushMatrix();
EaglerAdapter.glTranslatef(-8.0f, -18.0f, 0.0f);
EaglerAdapter.glScalef(16.0f, 16.0f, 16.0f);
var15.startDrawingQuads();
var15.setColorRGBA_F(0.0F, 0.0F, 0.0F, 0.25F);
var15.addVertex(-0.02, -0.02, 0.0);
var15.addVertex(-0.02, 1.02, 0.0);
var15.addVertex(1.02, 1.02, 0.0);
var15.addVertex(1.02, -0.02, 0.0);
var15.draw();
EaglerAdapter.glEnable(EaglerAdapter.GL_TEXTURE_2D);
EaglerAdapter.glEnable(EaglerAdapter.GL_ALPHA_TEST);
EaglerAdapter.glAlphaFunc(EaglerAdapter.GL_GREATER, 0.02f);
voiceGuiIcons.bindTexture();
int u = 0;
int v = mute ? 160 : 128;
float var7 = 0.00390625F;
float var8 = 0.00390625F;
if(mute) {
EaglerAdapter.glColor4f(0.9F, 0.3F, 0.3F, 0.125F);
}else {
EaglerAdapter.glColor4f(1.0F, 1.0F, 1.0F, 0.125F);
}
var15.startDrawingQuads();
var15.addVertexWithUV(0, 1.0, 0, (double) ((float) (u + 0.2f) * var7), (double) ((float) (v + 32 - 0.2f) * var8));
var15.addVertexWithUV(1.0, 1.0, 0, (double) ((float) (u + 32 - 0.2f) * var7), (double) ((float) (v + 32 - 0.2f) * var8));
var15.addVertexWithUV(1.0, 0, 0, (double) ((float) (u + 32 - 0.2f) * var7), (double) ((float) (v + 0.2f) * var8));
var15.addVertexWithUV(0, 0, 0, (double) ((float) (u + 0.2f) * var7), (double) ((float) (v + 0.2f) * var8));
var15.draw();
EaglerAdapter.glAlphaFunc(EaglerAdapter.GL_GREATER, 0.1f);
EaglerAdapter.glEnable(EaglerAdapter.GL_DEPTH_TEST);
EaglerAdapter.glDepthMask(true);
if(mute) {
EaglerAdapter.glColor4f(0.9F, 0.3F, 0.3F, 1.0F);
}else {
EaglerAdapter.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
}
var15.startDrawingQuads();
var15.addVertexWithUV(0, 1.0, 0, (double) ((float) (u + 0.2f) * var7), (double) ((float) (v + 32 - 0.2f) * var8));
var15.addVertexWithUV(1.0, 1.0, 0, (double) ((float) (u + 32 - 0.2f) * var7), (double) ((float) (v + 32 - 0.2f) * var8));
var15.addVertexWithUV(1.0, 0, 0, (double) ((float) (u + 32 - 0.2f) * var7), (double) ((float) (v + 0.2f) * var8));
var15.addVertexWithUV(0, 0, 0, (double) ((float) (u + 0.2f) * var7), (double) ((float) (v + 0.2f) * var8));
var15.draw();
EaglerAdapter.glEnable(EaglerAdapter.GL_LIGHTING);
EaglerAdapter.glDisable(EaglerAdapter.GL_BLEND);
EaglerAdapter.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
EaglerAdapter.glPopMatrix();
}
}
}
EaglerAdapter.glPopMatrix(); EaglerAdapter.glPopMatrix();
} }
} }

View file

@ -19,7 +19,6 @@ public class Client {
public static HTMLElement rootElement = null; public static HTMLElement rootElement = null;
public static Minecraft instance = null; public static Minecraft instance = null;
public static void main(String[] args) { public static void main(String[] args) {
registerErrorHandler();
//try { //try {
String[] e = getOpts(); String[] e = getOpts();
try { try {
@ -30,6 +29,7 @@ public class Client {
showCrashScreen(s.toString()); showCrashScreen(s.toString());
return; return;
} }
registerErrorHandler();
LocalStorageManager.loadStorage(); LocalStorageManager.loadStorage();
if(e.length > 2 && e[2].length() > 0) { if(e.length > 2 && e[2].length() > 0) {
ServerList.loadDefaultServers(e[2]); ServerList.loadDefaultServers(e[2]);

View file

@ -1,6 +1,9 @@
package net.lax1dude.eaglercraft.adapter; package net.lax1dude.eaglercraft.adapter;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@ -8,12 +11,15 @@ import java.nio.IntBuffer;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.function.Consumer;
import org.json.JSONObject; import org.json.JSONObject;
import org.teavm.interop.Async; import org.teavm.interop.Async;
@ -72,9 +78,11 @@ import net.lax1dude.eaglercraft.EaglerImage;
import net.lax1dude.eaglercraft.EarlyLoadScreen; import net.lax1dude.eaglercraft.EarlyLoadScreen;
import net.lax1dude.eaglercraft.LocalStorageManager; import net.lax1dude.eaglercraft.LocalStorageManager;
import net.lax1dude.eaglercraft.ServerQuery; import net.lax1dude.eaglercraft.ServerQuery;
import net.lax1dude.eaglercraft.Voice;
import net.lax1dude.eaglercraft.adapter.teavm.WebGLQuery; import net.lax1dude.eaglercraft.adapter.teavm.WebGLQuery;
import net.lax1dude.eaglercraft.adapter.teavm.WebGLVertexArray; import net.lax1dude.eaglercraft.adapter.teavm.WebGLVertexArray;
import net.minecraft.src.MathHelper; import net.minecraft.src.MathHelper;
import net.lax1dude.eaglercraft.adapter.teavm.EaglercraftVoiceClient;
import net.lax1dude.eaglercraft.adapter.teavm.WebGL2RenderingContext; import net.lax1dude.eaglercraft.adapter.teavm.WebGL2RenderingContext;
import static net.lax1dude.eaglercraft.adapter.teavm.WebGL2RenderingContext.*; import static net.lax1dude.eaglercraft.adapter.teavm.WebGL2RenderingContext.*;
@ -345,6 +353,8 @@ public class EaglerAdapterImpl2 {
EarlyLoadScreen.paintScreen(); EarlyLoadScreen.paintScreen();
voiceClient = startVoiceClient();
downloadAssetPack(assetPackageURI); downloadAssetPack(assetPackageURI);
try { try {
@ -385,6 +395,9 @@ public class EaglerAdapterImpl2 {
}, 5000); }, 5000);
} }
@JSBody(params = { }, script = "return window.startVoiceClient();")
private static native EaglercraftVoiceClient startVoiceClient();
public static final void destroyContext() { public static final void destroyContext() {
} }
@ -1546,7 +1559,7 @@ public class EaglerAdapterImpl2 {
return (p1 >= 0 && p1 < 256) ? LWJGLKeyNames[p1] : "null"; return (p1 >= 0 && p1 < 256) ? LWJGLKeyNames[p1] : "null";
} }
public static final void setFullscreen(boolean p1) { public static final void setFullscreen(boolean p1) {
win.alert("use F11 to enter fullscreen"); Window.alert("use F11 to enter fullscreen");
} }
public static final boolean shouldShutdown() { public static final boolean shouldShutdown() {
return false; return false;
@ -1997,29 +2010,198 @@ public class EaglerAdapterImpl2 {
public static final void openConsole() { public static final void openConsole() {
} }
private static boolean connected = false;
public static final void voiceConnect(String channel) {
win.alert("voice channels are not implemented yet"); //TODO: voice start =======================================================================
connected = true;
// implementation notes - DO NOT access any net.minecraft.* classes from EaglerAdapterImpl2 this time
// implementation notes - Tick all the "for (Object playerObject : Minecraft.getMinecraft().theWorld.playerEntities)" in net.minecraft.client.Minecraft.runTick() or similar
// implementation notes - try to only connect to client in GLOBAL or LOCAL not both
// implementation notes - try to only connect to nearby clients, and disconnect once they've been out of range for more then 5-10 seconds
// implementation notes - AGAIN, don't access net.minecraft.* classes from this file
// to ayunami - this is initialized at startup, right before downloadAssetPack
private static EaglercraftVoiceClient voiceClient = null;
private static boolean voiceAvailableStat = false;
private static boolean voiceSignalHandlersInitialized = false;
// to ayunami - use this as a callback to send packets on the voice signal channel
private static Consumer<byte[]> returnSignalHandler = null;
// to ayunami - call this before joining a new server
public static void clearVoiceAvailableStatus() {
voiceAvailableStat = false;
} }
public static final void voiceVolume(float volume) {
// to ayunami - use this to set returnSignalHandler when a new NetworkManager is created
public static void setVoiceSignalHandler(Consumer<byte[]> signalHandler) {
returnSignalHandler = signalHandler;
} }
public static final boolean voiceActive() {
return connected; public static final int VOICE_SIGNAL_ALLOWED_CLIENTBOUND = 0;
public static final int VOICE_SIGNAL_ICE_SERVERBOUND = 1;
public static final int VOICE_SIGNAL_DESC_SERVERBOUND = 2;
// to ayunami - use this to pass voice signal packets
public static void handleVoiceSignal(byte[] data) {
try {
DataInputStream streamIn = new DataInputStream(new ByteArrayInputStream(data));
int sig = streamIn.read();
switch(sig) {
case VOICE_SIGNAL_ALLOWED_CLIENTBOUND:
voiceAvailableStat = streamIn.readBoolean();
String[] servs = new String[streamIn.read()];
for(int i = 0; i < servs.length; ++i) {
servs[i] = streamIn.readUTF();
}
voiceClient.setICEServers(servs);
break;
default:
System.err.println("Unknown voice signal packet '" + sig + "'!");
break;
}
}catch(IOException ex) {
}
}
public static final boolean voiceAvailable() {
return voiceClient.voiceClientSupported() && voiceClient.getReadyState() != EaglercraftVoiceClient.READYSTATE_ABORTED;
}
public static final boolean voiceAllowed() {
return voiceAvailableStat;
} }
public static final boolean voiceRelayed() { public static final boolean voiceRelayed() {
return connected; return false;
} }
public static final String[] voiceUsers() { private static Voice.VoiceChannel enabledChannel = Voice.VoiceChannel.NONE;
return new String[0];
// to ayunami - use this to switch channel modes or disable voice
public static final void enableVoice(Voice.VoiceChannel enable) {
enabledChannel = enable;
if(enable == Voice.VoiceChannel.NONE) {
talkStatus = false;
}else {
if(!voiceSignalHandlersInitialized) {
voiceSignalHandlersInitialized = true;
voiceClient.setICECandidateHandler(new EaglercraftVoiceClient.ICECandidateHandler() {
@Override
public void call(String peerId, String sdpMLineIndex, String candidate) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dat = new DataOutputStream(bos);
dat.write(VOICE_SIGNAL_ICE_SERVERBOUND);
dat.writeUTF(peerId);
dat.writeUTF(sdpMLineIndex);
dat.writeUTF(candidate);
returnSignalHandler.accept(bos.toByteArray());
}catch(IOException ex) {
}
}
});
voiceClient.setDescriptionHandler(new EaglercraftVoiceClient.DescriptionHandler() {
@Override
public void call(String peerId, String candidate) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dat = new DataOutputStream(bos);
dat.write(VOICE_SIGNAL_DESC_SERVERBOUND);
dat.writeUTF(peerId);
dat.writeUTF(candidate);
returnSignalHandler.accept(bos.toByteArray());
}catch(IOException ex) {
}
}
});
voiceClient.initializeDevices();
}
}
} }
public static final String[] voiceUsersTalking() { public static final Voice.VoiceChannel getVoiceChannel() {
return new String[0]; return enabledChannel;
} }
public static final void voiceEnd() { public static final Voice.VoiceStatus getVoiceStatus() {
connected = false; return (!voiceAvailable() || !voiceAllowed()) ? Voice.VoiceStatus.UNAVAILABLE :
(voiceClient.getReadyState() != EaglercraftVoiceClient.READYSTATE_DEVICE_INITIALIZED ?
Voice.VoiceStatus.CONNECTING : Voice.VoiceStatus.CONNECTED);
} }
// to ayunami - push to talk in the JS works afaik
private static boolean talkStatus = false;
public static final void activateVoice(boolean talk) {
if(talkStatus != talk) {
voiceClient.activateVoice(talk);
}
talkStatus = talk;
}
// to ayunami - not currently used in the javascript but is used by GUI and gameSettings
private static int proximity = 16;
public static final void setVoiceProximity(int prox) {
proximity = prox;
}
public static final int getVoiceProximity() {
return proximity;
}
// to ayunami - iterate all AudioNodes from PeerTrackHandler players and adjust their gain here
private static float volumeListen = 0.5f;
public static final void setVoiceListenVolume(float f) {
volumeListen = f;
}
public static final float getVoiceListenVolume() {
return volumeListen;
}
// to ayunami - this is already implemented
private static float volumeSpeak = 0.5f;
public static final void setVoiceSpeakVolume(float f) {
if(volumeSpeak != f) {
voiceClient.setMicVolume(f);
}
volumeSpeak = f;
}
public static final float getVoiceSpeakVolume() {
return volumeSpeak;
}
// to ayunami - this is used to make the ingame GUI display who is speaking
// I also already programmed a speaker icon above player name tags of players in "getVoiceSpeaking()"
private static final Set<String> mutedSet = new HashSet();
private static final Set<String> emptySet = new HashSet();
private static final List<String> emptyLst = new ArrayList();
public static final Set<String> getVoiceListening() {
return emptySet;
}
public static final Set<String> getVoiceSpeaking() {
return emptySet;
}
public static final void setVoiceMuted(String username, boolean mute) {
if(mute) {
mutedSet.add(username);
}else {
mutedSet.remove(username);
}
}
public static final Set<String> getVoiceMuted() {
return mutedSet;
}
public static final List<String> getVoiceRecent() {
return emptyLst;
}
// to ayunami - use this to clean up that ExpiringSet class you made
public static final void tickVoice() {
}
//TODO: voice end ========================================================
public static final void doJavascriptCoroutines() { public static final void doJavascriptCoroutines() {
} }

View file

@ -0,0 +1,73 @@
package net.lax1dude.eaglercraft.adapter.teavm;
import org.teavm.jso.JSFunctor;
import org.teavm.jso.JSObject;
import org.teavm.jso.webaudio.MediaStreamAudioSourceNode;
public interface EaglercraftVoiceClient extends JSObject {
int READYSTATE_NONE = 0;
int READYSTATE_ABORTED = -1;
int READYSTATE_DEVICE_INITIALIZED = 1;
int TASKSTATE_NONE = -1;
int TASKSTATE_LOADING = 0;
int TASKSTATE_COMPLETE = 1;
int TASKSTATE_FAILED = 2;
boolean voiceClientSupported();
void initializeDevices();
// to ayunami - allow the server to tell the client what to put here
void setICEServers(String[] urls);
// to ayunami - this is the equivalent of your "EAG|VoiceIce" callback
void setICECandidateHandler(ICECandidateHandler callback);
// to ayunami - this is the equivalent of your "EAG|VoiceDesc" callback
void setDescriptionHandler(DescriptionHandler callback);
// to ayunami - this returns a "MediaStreamAudioSourceNode" for new peers
void setPeerTrackHandler(PeerTrackHandler callback);
// to ayunami - this is called when a peer disconnects (so you can remove their MediaStreamAudioSourceNode and stuff)
void setPeerDisconnectHandler(PeerDisconnectHandler callback);
void activateVoice(boolean active);
void setMicVolume(float volume);
int getTaskState();
int getReadyState();
int signalConnect(String peerId);
int signalDescription(String peerId, String description);
int signalDisconnect(String peerId);
int signalICECandidate(String peerId, String candidate);
@JSFunctor
public static interface ICECandidateHandler extends JSObject {
void call(String peerId, String sdpMLineIndex, String candidate);
}
@JSFunctor
public static interface DescriptionHandler extends JSObject {
void call(String peerId, String candidate);
}
@JSFunctor
public static interface PeerTrackHandler extends JSObject {
void call(String peerId, MediaStreamAudioSourceNode candidate);
}
@JSFunctor
public static interface PeerDisconnectHandler extends JSObject {
void call(String peerId);
}
}