mirror of
https://github.com/Eaglercraft-Archive/Eaglercraftx-1.8.8-src.git
synced 2025-06-28 02:48:14 -05:00
Update #51 - Protocol and FPS improvements, better workspace
This commit is contained in:
@ -19,7 +19,7 @@ package net.lax1dude.eaglercraft.v1_8.sp.gui;
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglercraftVersion;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.PlatformWebRTC;
|
||||
import net.lax1dude.eaglercraft.v1_8.profile.EaglerProfile;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.ConnectionHandshake;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.handshake.HandshakerHandler;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.lan.LANClientNetworkManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayServer;
|
||||
@ -101,8 +101,11 @@ public class GuiScreenLANConnecting extends GuiScreen {
|
||||
if(++renderCount > 1) {
|
||||
RelayServerSocket sock;
|
||||
if(relay == null) {
|
||||
sock = RelayManager.relayManager.getWorkingRelay((str) -> ls.resetProgressAndMessage("Connecting: " + str), 0x02, code);
|
||||
ls.resetProgressAndMessage("Connecting to '" + code + "'...");
|
||||
sock = RelayManager.relayManager.getWorkingRelay((str) -> ls.displayLoadingString("Connecting: " + str), 0x02, code);
|
||||
}else {
|
||||
ls.resetProgressAndMessage("Connecting to '" + code + "'...");
|
||||
ls.displayLoadingString("Connecting: " + relay.address);
|
||||
sock = RelayManager.relayManager.connectHandshake(relay, 0x02, code);
|
||||
}
|
||||
if(sock == null) {
|
||||
@ -125,7 +128,7 @@ public class GuiScreenLANConnecting extends GuiScreen {
|
||||
networkManager.setNetHandler(new NetHandlerSingleplayerLogin(networkManager, mc, parent));
|
||||
networkManager.sendPacket(new C00PacketLoginStart(this.mc.getSession().getProfile(),
|
||||
EaglerProfile.getSkinPacket(3), EaglerProfile.getCapePacket(),
|
||||
ConnectionHandshake.getSPHandshakeProtocolData(), EaglercraftVersion.clientBrandUUID));
|
||||
HandshakerHandler.getSPHandshakeProtocolData(), EaglercraftVersion.clientBrandUUID));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ import java.io.IOException;
|
||||
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglercraftVersion;
|
||||
import net.lax1dude.eaglercraft.v1_8.profile.EaglerProfile;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.ConnectionHandshake;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.handshake.HandshakerHandler;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.SingleplayerServerController;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.socket.ClientIntegratedServerNetworkManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.socket.NetHandlerSingleplayerLogin;
|
||||
@ -94,7 +94,7 @@ public class GuiScreenSingleplayerConnecting extends GuiScreen {
|
||||
this.networkManager.setNetHandler(new NetHandlerSingleplayerLogin(this.networkManager, this.mc, this.menu));
|
||||
this.networkManager.sendPacket(new C00PacketLoginStart(this.mc.getSession().getProfile(),
|
||||
EaglerProfile.getSkinPacket(3), EaglerProfile.getCapePacket(),
|
||||
ConnectionHandshake.getSPHandshakeProtocolData(), EaglercraftVersion.clientBrandUUID));
|
||||
HandshakerHandler.getSPHandshakeProtocolData(), EaglercraftVersion.clientBrandUUID));
|
||||
}
|
||||
try {
|
||||
this.networkManager.processReceivedPackets();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved.
|
||||
* Copyright (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
@ -366,6 +366,10 @@ public class LANClientNetworkManager extends EaglercraftNetworkManager {
|
||||
}
|
||||
}
|
||||
|
||||
if(injectedController != null && injectedController.handlePacket(fullData, off)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ByteBuf nettyBuffer = Unpooled.buffer(fullData, fullData.length);
|
||||
nettyBuffer.writerIndex(fullData.length);
|
||||
nettyBuffer.readerIndex(off);
|
||||
@ -399,6 +403,32 @@ public class LANClientNetworkManager extends EaglercraftNetworkManager {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectRawFrame(byte[] data) {
|
||||
if(!isChannelOpen()) {
|
||||
logger.error("Frame was injected on a closed connection");
|
||||
return;
|
||||
}
|
||||
int len = data.length;
|
||||
int fragmentSizeN1 = fragmentSize - 1;
|
||||
if(len > fragmentSizeN1) {
|
||||
int idx = 0;
|
||||
do {
|
||||
int readLen = len > fragmentSizeN1 ? fragmentSizeN1 : len;
|
||||
byte[] frag = new byte[readLen + 1];
|
||||
System.arraycopy(data, idx, frag, 1, readLen);
|
||||
idx += readLen;
|
||||
len -= readLen;
|
||||
frag[0] = len == 0 ? (byte)0 : (byte)1;
|
||||
PlatformWebRTC.clientLANSendPacket(frag);
|
||||
}while(len > 0);
|
||||
}else {
|
||||
byte[] bytes = new byte[len + 1];
|
||||
System.arraycopy(data, 0, bytes, 1, len);
|
||||
PlatformWebRTC.clientLANSendPacket(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeChannel(IChatComponent reason) {
|
||||
if(!PlatformWebRTC.clientLANClosed()) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2023-2024 lax1dude, ayunami2000. All Rights Reserved.
|
||||
* Copyright (c) 2023-2025 lax1dude, ayunami2000. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2023-2024 lax1dude, ayunami2000. All Rights Reserved.
|
||||
* Copyright (c) 2023-2025 lax1dude, ayunami2000. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
@ -23,6 +23,7 @@ import java.util.List;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.EagUtils;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.vfs2.VFile2;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
@ -33,8 +34,7 @@ import net.minecraft.world.EnumDifficulty;
|
||||
import net.minecraft.world.WorldServer;
|
||||
import net.minecraft.world.WorldSettings;
|
||||
import net.minecraft.world.WorldSettings.GameType;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.server.skins.IntegratedCapeService;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.server.skins.IntegratedSkinService;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.server.skins.IntegratedTextureService;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.server.voice.IntegratedVoiceService;
|
||||
|
||||
public class EaglerMinecraftServer extends MinecraftServer {
|
||||
@ -48,8 +48,7 @@ public class EaglerMinecraftServer extends MinecraftServer {
|
||||
protected WorldSettings newWorldSettings;
|
||||
protected boolean paused;
|
||||
protected EaglerSaveHandler saveHandler;
|
||||
protected IntegratedSkinService skinService;
|
||||
protected IntegratedCapeService capeService;
|
||||
protected IntegratedTextureService textureService;
|
||||
protected IntegratedVoiceService voiceService;
|
||||
|
||||
private long lastTPSUpdate = 0l;
|
||||
@ -67,25 +66,22 @@ public class EaglerMinecraftServer extends MinecraftServer {
|
||||
super(world);
|
||||
Bootstrap.register();
|
||||
this.saveHandler = new EaglerSaveHandler(savesDir, world);
|
||||
this.skinService = new IntegratedSkinService(WorldsDB.newVFile(saveHandler.getWorldDirectory(), "eagler/skulls"));
|
||||
this.capeService = new IntegratedCapeService();
|
||||
EaglerPlayerList playerList = new EaglerPlayerList(this, viewDistance);
|
||||
this.textureService = new IntegratedTextureService(playerList,
|
||||
WorldsDB.newVFile(saveHandler.getWorldDirectory(), "eagler/skulls"));
|
||||
this.voiceService = null;
|
||||
this.setServerOwner(owner);
|
||||
logger.info("server owner: " + owner);
|
||||
this.setDemo(demo);
|
||||
this.canCreateBonusChest(currentWorldSettings != null && currentWorldSettings.isBonusChestEnabled());
|
||||
this.setBuildLimit(256);
|
||||
this.setConfigManager(new EaglerPlayerList(this, viewDistance));
|
||||
this.setConfigManager(playerList);
|
||||
this.newWorldSettings = currentWorldSettings;
|
||||
this.paused = false;
|
||||
}
|
||||
|
||||
public IntegratedSkinService getSkinService() {
|
||||
return skinService;
|
||||
}
|
||||
|
||||
public IntegratedCapeService getCapeService() {
|
||||
return capeService;
|
||||
public IntegratedTextureService getTextureService() {
|
||||
return textureService;
|
||||
}
|
||||
|
||||
public IntegratedVoiceService getVoiceService() {
|
||||
@ -166,12 +162,14 @@ public class EaglerMinecraftServer extends MinecraftServer {
|
||||
this.currentTime += 50l;
|
||||
this.tick();
|
||||
++counterTicksPerSecond;
|
||||
} else if (!singleThreadMode) {
|
||||
EagUtils.sleep(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void updateTimeLightAndEntities() {
|
||||
this.skinService.flushCache();
|
||||
this.textureService.flushCache();
|
||||
super.updateTimeLightAndEntities();
|
||||
}
|
||||
|
||||
|
@ -44,8 +44,5 @@ public class EaglerPlayerList extends ServerConfigurationManager {
|
||||
|
||||
public void playerLoggedOut(EntityPlayerMP playerIn) {
|
||||
super.playerLoggedOut(playerIn);
|
||||
EaglerMinecraftServer svr = (EaglerMinecraftServer)getServerInstance();
|
||||
svr.skinService.unregisterPlayer(playerIn.getUniqueID());
|
||||
svr.capeService.unregisterPlayer(playerIn.getUniqueID());
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
|
||||
* Copyright (c) 2023-2025 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
@ -17,35 +17,56 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.sp.server.skins;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePluginMessageProtocol;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherSkinCustomV3EAG;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherSkinCustomV4EAG;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherSkinCustomV5EAG;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.util.SkinPacketVersionCache;
|
||||
|
||||
public class CustomSkullData {
|
||||
|
||||
public String skinURL;
|
||||
public long lastHit;
|
||||
public SkinPacketVersionCache skinData;
|
||||
protected long lastHit;
|
||||
protected byte[] textureDataV3;
|
||||
protected byte[] textureDataV4;
|
||||
|
||||
public CustomSkullData(String skinURL, byte[] skinData) {
|
||||
this.skinURL = skinURL;
|
||||
this.lastHit = EagRuntime.steadyTimeMillis();
|
||||
public CustomSkullData(byte[] skinData) {
|
||||
if(skinData.length != 16384) {
|
||||
byte[] fixed = new byte[16384];
|
||||
System.arraycopy(skinData, 0, fixed, 0, skinData.length > fixed.length ? fixed.length : skinData.length);
|
||||
skinData = fixed;
|
||||
}
|
||||
this.skinData = SkinPacketVersionCache.createCustomV3(0l, 0l, 0, skinData);
|
||||
textureDataV3 = skinData;
|
||||
lastHit = EagRuntime.steadyTimeMillis();
|
||||
}
|
||||
|
||||
public byte[] getFullSkin() {
|
||||
return ((SPacketOtherSkinCustomV3EAG)skinData.getV3()).customSkin;
|
||||
return textureDataV3;
|
||||
}
|
||||
|
||||
public GameMessagePacket getSkinPacket(EaglercraftUUID uuid, GamePluginMessageProtocol protocol) {
|
||||
return SkinPacketVersionCache.rewriteUUID(skinData.get(protocol), uuid.getMostSignificantBits(), uuid.getLeastSignificantBits());
|
||||
public GameMessagePacket getSkin(long uuidMost, long uuidLeast, GamePluginMessageProtocol protocol) {
|
||||
switch(protocol) {
|
||||
case V3:
|
||||
return new SPacketOtherSkinCustomV3EAG(uuidMost, uuidLeast, 0xFF, textureDataV3);
|
||||
case V4:
|
||||
if(textureDataV4 == null) {
|
||||
textureDataV4 = SkinPacketVersionCache.convertToV4Raw(textureDataV3);
|
||||
}
|
||||
return new SPacketOtherSkinCustomV4EAG(uuidMost, uuidLeast, 0xFF, textureDataV4);
|
||||
default:
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
public GameMessagePacket getSkinV5(int requestId, GamePluginMessageProtocol protocol) {
|
||||
if(protocol.ver >= 5) {
|
||||
if(textureDataV4 == null) {
|
||||
textureDataV4 = SkinPacketVersionCache.convertToV4Raw(textureDataV3);
|
||||
}
|
||||
return new SPacketOtherSkinCustomV5EAG(requestId, 0xFF, textureDataV4);
|
||||
}else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (c) 2025 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
package net.lax1dude.eaglercraft.v1_8.sp.server.skins;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.crypto.SHA1Digest;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.vfs2.VFile2;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.server.WorldsDB;
|
||||
|
||||
public class CustomSkullLoader {
|
||||
|
||||
private static final byte[] skullNotFoundTexture = new byte[4096];
|
||||
|
||||
static {
|
||||
for(int y = 0; y < 16; ++y) {
|
||||
for(int x = 0; x < 64; ++x) {
|
||||
int i = (y << 8) | (x << 2);
|
||||
byte j = ((x + y) & 1) == 1 ? (byte)255 : 0;
|
||||
skullNotFoundTexture[i] = (byte)255;
|
||||
skullNotFoundTexture[i + 1] = j;
|
||||
skullNotFoundTexture[i + 2] = 0;
|
||||
skullNotFoundTexture[i + 3] = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final VFile2 folder;
|
||||
|
||||
private final Map<String,CustomSkullData> customSkulls = new HashMap<>(64);
|
||||
|
||||
private long lastFlush = 0l;
|
||||
|
||||
public CustomSkullLoader(VFile2 folder) {
|
||||
this.folder = folder;
|
||||
}
|
||||
|
||||
private CustomSkullData loadSkullData0(String urlStr) {
|
||||
byte[] data = WorldsDB.newVFile(folder, urlStr).getAllBytes();
|
||||
if(data == null) {
|
||||
return new CustomSkullData(skullNotFoundTexture);
|
||||
}else {
|
||||
return new CustomSkullData(data);
|
||||
}
|
||||
}
|
||||
|
||||
public CustomSkullData loadSkullData(String url) {
|
||||
CustomSkullData sk = customSkulls.get(url);
|
||||
if(sk == null) {
|
||||
customSkulls.put(url, sk = loadSkullData0(url));
|
||||
}else {
|
||||
sk.lastHit = EagRuntime.steadyTimeMillis();
|
||||
}
|
||||
return sk;
|
||||
}
|
||||
|
||||
private static final String hex = "0123456789abcdef";
|
||||
|
||||
public String installNewSkull(byte[] skullData) {
|
||||
// set to 16384 to save a full 64x64 skin
|
||||
if(skullData.length > 4096) {
|
||||
byte[] tmp = skullData;
|
||||
skullData = new byte[4096];
|
||||
System.arraycopy(tmp, 0, skullData, 0, 4096);
|
||||
}
|
||||
SHA1Digest sha = new SHA1Digest();
|
||||
sha.update(skullData, 0, skullData.length);
|
||||
byte[] hash = new byte[20];
|
||||
sha.doFinal(hash, 0);
|
||||
char[] hashText = new char[40];
|
||||
for(int i = 0; i < 20; ++i) {
|
||||
hashText[i << 1] = hex.charAt((hash[i] & 0xF0) >> 4);
|
||||
hashText[(i << 1) + 1] = hex.charAt(hash[i] & 0x0F);
|
||||
}
|
||||
String str = "skin-" + new String(hashText) + ".bmp";
|
||||
customSkulls.put(str, new CustomSkullData(skullData));
|
||||
WorldsDB.newVFile(folder, str).setAllBytes(skullData);
|
||||
return str;
|
||||
}
|
||||
|
||||
public void flushCache() {
|
||||
long cur = EagRuntime.steadyTimeMillis();
|
||||
if(cur - lastFlush > 300000l) {
|
||||
lastFlush = cur;
|
||||
Iterator<CustomSkullData> customSkullsItr = customSkulls.values().iterator();
|
||||
while(customSkullsItr.hasNext()) {
|
||||
if(cur - customSkullsItr.next().lastHit > 900000l) {
|
||||
customSkullsItr.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
package net.lax1dude.eaglercraft.v1_8.sp.server.skins;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherCapeCustomEAG;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherCapePresetEAG;
|
||||
|
||||
public class IntegratedCapePackets {
|
||||
|
||||
public static final int PACKET_MY_CAPE_PRESET = 0x01;
|
||||
public static final int PACKET_MY_CAPE_CUSTOM = 0x02;
|
||||
|
||||
public static void registerEaglerPlayer(EaglercraftUUID clientUUID, byte[] bs, IntegratedCapeService capeService) throws IOException {
|
||||
if(bs.length == 0) {
|
||||
throw new IOException("Zero-length packet recieved");
|
||||
}
|
||||
GameMessagePacket generatedPacket;
|
||||
int packetType = (int)bs[0] & 0xFF;
|
||||
switch(packetType) {
|
||||
case PACKET_MY_CAPE_PRESET:
|
||||
if(bs.length != 5) {
|
||||
throw new IOException("Invalid length " + bs.length + " for preset cape packet");
|
||||
}
|
||||
generatedPacket = new SPacketOtherCapePresetEAG(clientUUID.msb, clientUUID.lsb, (bs[1] << 24) | (bs[2] << 16) | (bs[3] << 8) | (bs[4] & 0xFF));
|
||||
break;
|
||||
case PACKET_MY_CAPE_CUSTOM:
|
||||
if(bs.length != 1174) {
|
||||
throw new IOException("Invalid length " + bs.length + " for custom cape packet");
|
||||
}
|
||||
byte[] capePixels = new byte[bs.length - 1];
|
||||
System.arraycopy(bs, 1, capePixels, 0, capePixels.length);
|
||||
generatedPacket = new SPacketOtherCapeCustomEAG(clientUUID.msb, clientUUID.lsb, capePixels);
|
||||
break;
|
||||
default:
|
||||
throw new IOException("Unknown skin packet type: " + packetType);
|
||||
}
|
||||
capeService.registerEaglercraftPlayer(clientUUID, generatedPacket);
|
||||
}
|
||||
|
||||
public static void registerEaglerPlayerFallback(EaglercraftUUID clientUUID, IntegratedCapeService capeService) {
|
||||
capeService.registerEaglercraftPlayer(clientUUID, new SPacketOtherCapePresetEAG(clientUUID.msb, clientUUID.lsb, 0));
|
||||
}
|
||||
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
package net.lax1dude.eaglercraft.v1_8.sp.server.skins;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherCapePresetEAG;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
|
||||
public class IntegratedCapeService {
|
||||
|
||||
public static final Logger logger = LogManager.getLogger("IntegratedCapeService");
|
||||
|
||||
public static final int masterRateLimitPerPlayer = 250;
|
||||
|
||||
private final Map<EaglercraftUUID, GameMessagePacket> capesCache = new HashMap<>();
|
||||
|
||||
public void processLoginPacket(byte[] packetData, EntityPlayerMP sender) {
|
||||
try {
|
||||
IntegratedCapePackets.registerEaglerPlayer(sender.getUniqueID(), packetData, this);
|
||||
} catch (IOException e) {
|
||||
logger.error("Invalid skin data packet recieved from player {}!", sender.getName());
|
||||
logger.error(e);
|
||||
sender.playerNetServerHandler.kickPlayerFromServer("Invalid skin data packet recieved!");
|
||||
}
|
||||
}
|
||||
|
||||
public void registerEaglercraftPlayer(EaglercraftUUID playerUUID, GameMessagePacket capePacket) {
|
||||
capesCache.put(playerUUID, capePacket);
|
||||
}
|
||||
|
||||
public void processGetOtherCape(EaglercraftUUID searchUUID, EntityPlayerMP sender) {
|
||||
GameMessagePacket maybeCape = capesCache.get(searchUUID);
|
||||
if(maybeCape == null) {
|
||||
maybeCape = new SPacketOtherCapePresetEAG(searchUUID.msb, searchUUID.lsb, 0);
|
||||
}
|
||||
sender.playerNetServerHandler.sendEaglerMessage(maybeCape);
|
||||
}
|
||||
|
||||
public void unregisterPlayer(EaglercraftUUID playerUUID) {
|
||||
synchronized(capesCache) {
|
||||
capesCache.remove(playerUUID);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,120 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
package net.lax1dude.eaglercraft.v1_8.sp.server.skins;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.*;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.util.SkinPacketVersionCache;
|
||||
|
||||
public class IntegratedSkinPackets {
|
||||
|
||||
public static final int PACKET_MY_SKIN_PRESET = 0x01;
|
||||
public static final int PACKET_MY_SKIN_CUSTOM = 0x02;
|
||||
|
||||
public static void registerEaglerPlayer(EaglercraftUUID clientUUID, byte[] bs, IntegratedSkinService skinService,
|
||||
int protocolVers) throws IOException {
|
||||
if(bs.length == 0) {
|
||||
throw new IOException("Zero-length packet recieved");
|
||||
}
|
||||
GameMessagePacket generatedPacketV3 = null;
|
||||
GameMessagePacket generatedPacketV4 = null;
|
||||
int skinModel = -1;
|
||||
int packetType = (int)bs[0] & 0xFF;
|
||||
switch(packetType) {
|
||||
case PACKET_MY_SKIN_PRESET:
|
||||
if(bs.length != 5) {
|
||||
throw new IOException("Invalid length " + bs.length + " for preset skin packet");
|
||||
}
|
||||
generatedPacketV3 = generatedPacketV4 = new SPacketOtherSkinPresetEAG(clientUUID.msb, clientUUID.lsb,
|
||||
(bs[1] << 24) | (bs[2] << 16) | (bs[3] << 8) | (bs[4] & 0xFF));
|
||||
break;
|
||||
case PACKET_MY_SKIN_CUSTOM:
|
||||
if(protocolVers <= 3) {
|
||||
byte[] pixels = new byte[16384];
|
||||
if(bs.length != 2 + pixels.length) {
|
||||
throw new IOException("Invalid length " + bs.length + " for custom skin packet");
|
||||
}
|
||||
setAlphaForChestV3(pixels);
|
||||
System.arraycopy(bs, 2, pixels, 0, pixels.length);
|
||||
generatedPacketV3 = new SPacketOtherSkinCustomV3EAG(clientUUID.msb, clientUUID.lsb, (skinModel = (int)bs[1] & 0xFF), pixels);
|
||||
}else {
|
||||
byte[] pixels = new byte[12288];
|
||||
if(bs.length != 2 + pixels.length) {
|
||||
throw new IOException("Invalid length " + bs.length + " for custom skin packet");
|
||||
}
|
||||
setAlphaForChestV4(pixels);
|
||||
System.arraycopy(bs, 2, pixels, 0, pixels.length);
|
||||
generatedPacketV4 = new SPacketOtherSkinCustomV4EAG(clientUUID.msb, clientUUID.lsb, (skinModel = (int)bs[1] & 0xFF), pixels);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IOException("Unknown skin packet type: " + packetType);
|
||||
}
|
||||
skinService.processPacketPlayerSkin(clientUUID, new SkinPacketVersionCache(generatedPacketV3, generatedPacketV4), skinModel);
|
||||
}
|
||||
|
||||
public static void registerEaglerPlayerFallback(EaglercraftUUID clientUUID, IntegratedSkinService skinService) throws IOException {
|
||||
int skinModel = (clientUUID.hashCode() & 1) != 0 ? 1 : 0;
|
||||
skinService.processPacketPlayerSkin(clientUUID, SkinPacketVersionCache.createPreset(clientUUID.msb, clientUUID.lsb, skinModel), skinModel);
|
||||
}
|
||||
|
||||
public static void setAlphaForChestV3(byte[] skin64x64) {
|
||||
if(skin64x64.length != 16384) {
|
||||
throw new IllegalArgumentException("Skin is not 64x64!");
|
||||
}
|
||||
for(int y = 20; y < 32; ++y) {
|
||||
for(int x = 16; x < 40; ++x) {
|
||||
skin64x64[(y << 8) | (x << 2)] = (byte)0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void setAlphaForChestV4(byte[] skin64x64) {
|
||||
if(skin64x64.length != 12288) {
|
||||
throw new IllegalArgumentException("Skin is not 64x64!");
|
||||
}
|
||||
for(int y = 20; y < 32; ++y) {
|
||||
for(int x = 16; x < 40; ++x) {
|
||||
skin64x64[((y << 6) | x) * 3] |= 0x80;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static SPacketOtherSkinPresetEAG makePresetResponse(EaglercraftUUID uuid) {
|
||||
return new SPacketOtherSkinPresetEAG(uuid.msb, uuid.lsb, (uuid.hashCode() & 1) != 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
public static byte[] asciiString(String string) {
|
||||
byte[] str = new byte[string.length()];
|
||||
for(int i = 0; i < str.length; ++i) {
|
||||
str[i] = (byte)string.charAt(i);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
public static EaglercraftUUID createEaglerURLSkinUUID(String skinUrl) {
|
||||
return EaglercraftUUID.nameUUIDFromBytes(asciiString("EaglercraftSkinURL:" + skinUrl));
|
||||
}
|
||||
|
||||
public static int getModelId(String modelName) {
|
||||
return "slim".equalsIgnoreCase(modelName) ? 1 : 0;
|
||||
}
|
||||
|
||||
}
|
@ -1,210 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2024 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
package net.lax1dude.eaglercraft.v1_8.sp.server.skins;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.Base64;
|
||||
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
|
||||
import net.lax1dude.eaglercraft.v1_8.crypto.SHA1Digest;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.vfs2.VFile2;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherSkinPresetEAG;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.util.SkinPacketVersionCache;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.server.WorldsDB;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ChatComponentTranslation;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
import net.minecraft.nbt.NBTTagString;
|
||||
|
||||
public class IntegratedSkinService {
|
||||
|
||||
public static final Logger logger = LogManager.getLogger("IntegratedSkinService");
|
||||
|
||||
public static final byte[] skullNotFoundTexture = new byte[4096];
|
||||
|
||||
static {
|
||||
for(int y = 0; y < 16; ++y) {
|
||||
for(int x = 0; x < 64; ++x) {
|
||||
int i = (y << 8) | (x << 2);
|
||||
byte j = ((x + y) & 1) == 1 ? (byte)255 : 0;
|
||||
skullNotFoundTexture[i] = (byte)255;
|
||||
skullNotFoundTexture[i + 1] = j;
|
||||
skullNotFoundTexture[i + 2] = 0;
|
||||
skullNotFoundTexture[i + 3] = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final VFile2 skullsDirectory;
|
||||
|
||||
public final Map<EaglercraftUUID,SkinPacketVersionCache> playerSkins = new HashMap<>();
|
||||
public final Map<String,CustomSkullData> customSkulls = new HashMap<>();
|
||||
|
||||
private long lastFlush = 0l;
|
||||
|
||||
public IntegratedSkinService(VFile2 skullsDirectory) {
|
||||
this.skullsDirectory = skullsDirectory;
|
||||
}
|
||||
|
||||
public void processLoginPacket(byte[] packetData, EntityPlayerMP sender, int protocolVers) {
|
||||
try {
|
||||
IntegratedSkinPackets.registerEaglerPlayer(sender.getUniqueID(), packetData, this, protocolVers);
|
||||
} catch (IOException e) {
|
||||
logger.error("Invalid skin data packet recieved from player {}!", sender.getName());
|
||||
logger.error(e);
|
||||
sender.playerNetServerHandler.kickPlayerFromServer("Invalid skin data packet recieved!");
|
||||
}
|
||||
}
|
||||
|
||||
public void processPacketGetOtherSkin(EaglercraftUUID searchUUID, EntityPlayerMP sender) {
|
||||
SkinPacketVersionCache playerSkin = playerSkins.get(searchUUID);
|
||||
GameMessagePacket toSend = null;
|
||||
if(playerSkin != null) {
|
||||
toSend = playerSkin.get(sender.playerNetServerHandler.getEaglerMessageProtocol());
|
||||
}else {
|
||||
toSend = IntegratedSkinPackets.makePresetResponse(searchUUID);
|
||||
}
|
||||
sender.playerNetServerHandler.sendEaglerMessage(toSend);
|
||||
}
|
||||
|
||||
public void processPacketGetOtherSkin(EaglercraftUUID searchUUID, String urlStr, EntityPlayerMP sender) {
|
||||
urlStr = urlStr.toLowerCase();
|
||||
GameMessagePacket playerSkin;
|
||||
if(!urlStr.startsWith("eagler://")) {
|
||||
playerSkin = new SPacketOtherSkinPresetEAG(searchUUID.msb, searchUUID.lsb, 0);
|
||||
}else {
|
||||
urlStr = urlStr.substring(9);
|
||||
if(urlStr.contains(VFile2.pathSeperator)) {
|
||||
playerSkin = new SPacketOtherSkinPresetEAG(searchUUID.msb, searchUUID.lsb, 0);
|
||||
}else {
|
||||
CustomSkullData sk = customSkulls.get(urlStr);
|
||||
if(sk == null) {
|
||||
customSkulls.put(urlStr, sk = loadCustomSkull(urlStr));
|
||||
}else {
|
||||
sk.lastHit = EagRuntime.steadyTimeMillis();
|
||||
}
|
||||
playerSkin = sk.getSkinPacket(searchUUID, sender.playerNetServerHandler.getEaglerMessageProtocol());
|
||||
}
|
||||
}
|
||||
sender.playerNetServerHandler.sendEaglerMessage(playerSkin);
|
||||
}
|
||||
|
||||
public void processPacketPlayerSkin(EaglercraftUUID clientUUID, SkinPacketVersionCache generatedPacket, int skinModel) {
|
||||
playerSkins.put(clientUUID, generatedPacket);
|
||||
}
|
||||
|
||||
public void unregisterPlayer(EaglercraftUUID clientUUID) {
|
||||
playerSkins.remove(clientUUID);
|
||||
}
|
||||
|
||||
public void processPacketInstallNewSkin(byte[] skullData, EntityPlayerMP sender) {
|
||||
if(!sender.canCommandSenderUseCommand(2, "give")) {
|
||||
ChatComponentTranslation cc = new ChatComponentTranslation("command.skull.nopermission");
|
||||
cc.getChatStyle().setColor(EnumChatFormatting.RED);
|
||||
sender.addChatMessage(cc);
|
||||
return;
|
||||
}
|
||||
String fileName = "eagler://" + installNewSkull(skullData);
|
||||
NBTTagCompound rootTagCompound = new NBTTagCompound();
|
||||
NBTTagCompound ownerTagCompound = new NBTTagCompound();
|
||||
ownerTagCompound.setString("Name", "Eagler");
|
||||
ownerTagCompound.setString("Id", EaglercraftUUID.nameUUIDFromBytes((("EaglerSkullUUID:" + fileName).getBytes(StandardCharsets.UTF_8))).toString());
|
||||
NBTTagCompound propertiesTagCompound = new NBTTagCompound();
|
||||
NBTTagList texturesTagList = new NBTTagList();
|
||||
NBTTagCompound texturesTagCompound = new NBTTagCompound();
|
||||
String texturesProp = "{\"textures\":{\"SKIN\":{\"url\":\"" + fileName + "\",\"metadata\":{\"model\":\"default\"}}}}";
|
||||
texturesTagCompound.setString("Value", Base64.encodeBase64String(texturesProp.getBytes(StandardCharsets.UTF_8)));
|
||||
texturesTagList.appendTag(texturesTagCompound);
|
||||
propertiesTagCompound.setTag("textures", texturesTagList);
|
||||
ownerTagCompound.setTag("Properties", propertiesTagCompound);
|
||||
rootTagCompound.setTag("SkullOwner", ownerTagCompound);
|
||||
NBTTagCompound displayTagCompound = new NBTTagCompound();
|
||||
displayTagCompound.setString("Name", EnumChatFormatting.RESET + "Custom Eaglercraft Skull");
|
||||
NBTTagList loreList = new NBTTagList();
|
||||
loreList.appendTag(new NBTTagString(EnumChatFormatting.GRAY + (fileName.length() > 24 ? (fileName.substring(0, 22) + "...") : fileName)));
|
||||
displayTagCompound.setTag("Lore", loreList);
|
||||
rootTagCompound.setTag("display", displayTagCompound);
|
||||
ItemStack stack = new ItemStack(Items.skull, 1, 3);
|
||||
stack.setTagCompound(rootTagCompound);
|
||||
boolean flag = sender.inventory.addItemStackToInventory(stack);
|
||||
if (flag) {
|
||||
sender.worldObj.playSoundAtEntity(sender, "random.pop", 0.2F,
|
||||
((sender.getRNG().nextFloat() - sender.getRNG().nextFloat()) * 0.7F + 1.0F)
|
||||
* 2.0F);
|
||||
sender.inventoryContainer.detectAndSendChanges();
|
||||
}
|
||||
sender.addChatMessage(new ChatComponentTranslation("command.skull.feedback", fileName));
|
||||
}
|
||||
|
||||
private static final String hex = "0123456789abcdef";
|
||||
|
||||
public String installNewSkull(byte[] skullData) {
|
||||
// set to 16384 to save a full 64x64 skin
|
||||
if(skullData.length > 4096) {
|
||||
byte[] tmp = skullData;
|
||||
skullData = new byte[4096];
|
||||
System.arraycopy(tmp, 0, skullData, 0, 4096);
|
||||
}
|
||||
SHA1Digest sha = new SHA1Digest();
|
||||
sha.update(skullData, 0, skullData.length);
|
||||
byte[] hash = new byte[20];
|
||||
sha.doFinal(hash, 0);
|
||||
char[] hashText = new char[40];
|
||||
for(int i = 0; i < 20; ++i) {
|
||||
hashText[i << 1] = hex.charAt((hash[i] & 0xF0) >> 4);
|
||||
hashText[(i << 1) + 1] = hex.charAt(hash[i] & 0x0F);
|
||||
}
|
||||
String str = "skin-" + new String(hashText) + ".bmp";
|
||||
customSkulls.put(str, new CustomSkullData(str, skullData));
|
||||
WorldsDB.newVFile(skullsDirectory, str).setAllBytes(skullData);
|
||||
return str;
|
||||
}
|
||||
|
||||
private CustomSkullData loadCustomSkull(String urlStr) {
|
||||
byte[] data = WorldsDB.newVFile(skullsDirectory, urlStr).getAllBytes();
|
||||
if(data == null) {
|
||||
return new CustomSkullData(urlStr, skullNotFoundTexture);
|
||||
}else {
|
||||
return new CustomSkullData(urlStr, data);
|
||||
}
|
||||
}
|
||||
|
||||
public void flushCache() {
|
||||
long cur = EagRuntime.steadyTimeMillis();
|
||||
if(cur - lastFlush > 300000l) {
|
||||
lastFlush = cur;
|
||||
Iterator<CustomSkullData> customSkullsItr = customSkulls.values().iterator();
|
||||
while(customSkullsItr.hasNext()) {
|
||||
if(cur - customSkullsItr.next().lastHit > 900000l) {
|
||||
customSkullsItr.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2025 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
package net.lax1dude.eaglercraft.v1_8.sp.server.skins;
|
||||
|
||||
public class IntegratedTexturePackets {
|
||||
|
||||
public static PlayerTextureData handleTextureData(byte[] skinV1, byte[] capeV1) {
|
||||
int skinId;
|
||||
byte[] skinTextureDataV3;
|
||||
eagler: {
|
||||
if (skinV1 != null && skinV1.length > 0) {
|
||||
int packetType = (int)skinV1[0] & 0xFF;
|
||||
switch (packetType) {
|
||||
case 0x01:
|
||||
if (skinV1.length == 5) {
|
||||
skinId = ((skinV1[1] & 0x7F) << 24) | ((skinV1[2] & 0xFF) << 16)
|
||||
| ((skinV1[3] & 0xFF) << 8) | (skinV1[4] & 0xFF);
|
||||
skinTextureDataV3 = null;
|
||||
break eagler;
|
||||
}
|
||||
break;
|
||||
case 0x02:
|
||||
if (skinV1.length == 16386) {
|
||||
skinId = -(Math.min((int) skinV1[1] & 0x7F, 0x7E) | 0x80) - 1;
|
||||
skinTextureDataV3 = new byte[16384];
|
||||
System.arraycopy(skinV1, 2, skinTextureDataV3, 0, 16384);
|
||||
break eagler;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
skinId = 0;
|
||||
skinTextureDataV3 = null;
|
||||
}
|
||||
int capeId;
|
||||
byte[] capeTextureData;
|
||||
eagler: {
|
||||
if (capeV1 != null && capeV1.length > 0) {
|
||||
int packetType = (int)capeV1[0] & 0xFF;
|
||||
switch (packetType) {
|
||||
case 0x01:
|
||||
if(capeV1.length == 5) {
|
||||
capeId = ((capeV1[1] & 0x7F) << 24) | ((capeV1[2] & 0xFF) << 16)
|
||||
| ((capeV1[3] & 0xFF) << 8) | (capeV1[4] & 0xFF);
|
||||
capeTextureData = null;
|
||||
break eagler;
|
||||
}
|
||||
break;
|
||||
case 0x02:
|
||||
if (capeV1.length == 1174) {
|
||||
capeId = -1;
|
||||
capeTextureData = new byte[1173];
|
||||
System.arraycopy(capeV1, 1, capeTextureData, 0, 1173);
|
||||
break eagler;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
capeId = 0;
|
||||
capeTextureData = null;
|
||||
}
|
||||
return new PlayerTextureData(skinId, skinTextureDataV3, null, capeId, capeTextureData);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright (c) 2025 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
package net.lax1dude.eaglercraft.v1_8.sp.server.skins;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.Base64;
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
|
||||
import net.lax1dude.eaglercraft.v1_8.internal.vfs2.VFile2;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherCapePresetEAG;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherCapePresetV5EAG;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherSkinPresetEAG;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherSkinPresetV5EAG;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherTexturesV5EAG;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.server.EaglerPlayerList;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
import net.minecraft.nbt.NBTTagString;
|
||||
import net.minecraft.util.ChatComponentTranslation;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
|
||||
public class IntegratedTextureService {
|
||||
|
||||
private final EaglerPlayerList playerList;
|
||||
private final CustomSkullLoader skullHandler;
|
||||
|
||||
public IntegratedTextureService(EaglerPlayerList playerList, VFile2 file) {
|
||||
this.playerList = playerList;
|
||||
this.skullHandler = new CustomSkullLoader(file);
|
||||
}
|
||||
|
||||
public void handleRequestPlayerSkin(EntityPlayerMP requester, EaglercraftUUID uuid) {
|
||||
EntityPlayerMP target = playerList.getPlayerByUUID(uuid);
|
||||
if (target != null && target.textureData != null) {
|
||||
requester.playerNetServerHandler.sendEaglerMessage(target.textureData.getSkin(uuid.msb, uuid.lsb,
|
||||
requester.playerNetServerHandler.getEaglerMessageProtocol()));
|
||||
} else {
|
||||
requester.playerNetServerHandler.sendEaglerMessage(
|
||||
new SPacketOtherSkinPresetEAG(uuid.msb, uuid.lsb, (uuid.hashCode() & 1) != 0 ? 1 : 0));
|
||||
}
|
||||
}
|
||||
|
||||
public void handleRequestPlayerCape(EntityPlayerMP requester, EaglercraftUUID uuid) {
|
||||
EntityPlayerMP target = playerList.getPlayerByUUID(uuid);
|
||||
if (target != null && target.textureData != null) {
|
||||
requester.playerNetServerHandler.sendEaglerMessage(target.textureData.getCape(uuid.msb, uuid.lsb,
|
||||
requester.playerNetServerHandler.getEaglerMessageProtocol()));
|
||||
} else {
|
||||
requester.playerNetServerHandler.sendEaglerMessage(new SPacketOtherCapePresetEAG(uuid.msb, uuid.lsb, 0));
|
||||
}
|
||||
}
|
||||
|
||||
public void handleRequestPlayerSkinV5(EntityPlayerMP requester, int requestId, EaglercraftUUID uuid) {
|
||||
EntityPlayerMP target = playerList.getPlayerByUUID(uuid);
|
||||
if (target != null && target.textureData != null) {
|
||||
requester.playerNetServerHandler.sendEaglerMessage(target.textureData.getSkinV5(requestId,
|
||||
requester.playerNetServerHandler.getEaglerMessageProtocol()));
|
||||
} else {
|
||||
requester.playerNetServerHandler.sendEaglerMessage(
|
||||
new SPacketOtherSkinPresetV5EAG(requestId, (uuid.hashCode() & 1) != 0 ? 1 : 0));
|
||||
}
|
||||
}
|
||||
|
||||
public void handleRequestPlayerCapeV5(EntityPlayerMP requester, int requestId, EaglercraftUUID uuid) {
|
||||
EntityPlayerMP target = playerList.getPlayerByUUID(uuid);
|
||||
if (target != null && target.textureData != null) {
|
||||
requester.playerNetServerHandler.sendEaglerMessage(target.textureData.getCapeV5(requestId,
|
||||
requester.playerNetServerHandler.getEaglerMessageProtocol()));
|
||||
} else {
|
||||
requester.playerNetServerHandler.sendEaglerMessage(new SPacketOtherCapePresetV5EAG(requestId, 0));
|
||||
}
|
||||
}
|
||||
|
||||
public void handleRequestPlayerTexturesV5(EntityPlayerMP requester, int requestId, EaglercraftUUID uuid) {
|
||||
EntityPlayerMP target = playerList.getPlayerByUUID(uuid);
|
||||
if (target != null && target.textureData != null) {
|
||||
requester.playerNetServerHandler.sendEaglerMessage(target.textureData.getTexturesV5(requestId,
|
||||
requester.playerNetServerHandler.getEaglerMessageProtocol()));
|
||||
} else {
|
||||
requester.playerNetServerHandler
|
||||
.sendEaglerMessage(new SPacketOtherTexturesV5EAG(requestId, 0, null, 0, null));
|
||||
}
|
||||
}
|
||||
|
||||
public void handleRequestSkinByURL(EntityPlayerMP requester, EaglercraftUUID uuid, String url) {
|
||||
url = url.toLowerCase();
|
||||
if (url.startsWith("eagler://")) {
|
||||
url = url.substring(9);
|
||||
if (!url.contains(VFile2.pathSeperator)) {
|
||||
CustomSkullData skull = skullHandler.loadSkullData(url);
|
||||
if (skull != null) {
|
||||
requester.playerNetServerHandler.sendEaglerMessage(skull.getSkin(uuid.msb, uuid.lsb,
|
||||
requester.playerNetServerHandler.getEaglerMessageProtocol()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
requester.playerNetServerHandler.sendEaglerMessage(new SPacketOtherSkinPresetEAG(uuid.msb, uuid.lsb, 0));
|
||||
}
|
||||
|
||||
public void handleRequestSkinByURLV5(EntityPlayerMP requester, int requestId, String url) {
|
||||
url = url.toLowerCase();
|
||||
if (url.startsWith("eagler://")) {
|
||||
url = url.substring(9);
|
||||
if (!url.contains(VFile2.pathSeperator)) {
|
||||
CustomSkullData skull = skullHandler.loadSkullData(url);
|
||||
if (skull != null) {
|
||||
requester.playerNetServerHandler.sendEaglerMessage(skull.getSkinV5(requestId,
|
||||
requester.playerNetServerHandler.getEaglerMessageProtocol()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
requester.playerNetServerHandler.sendEaglerMessage(new SPacketOtherSkinPresetV5EAG(requestId, 0));
|
||||
}
|
||||
|
||||
public void handleInstallNewSkin(EntityPlayerMP requester, byte[] skullData) {
|
||||
if (!requester.canCommandSenderUseCommand(2, "give")) {
|
||||
ChatComponentTranslation cc = new ChatComponentTranslation("command.skull.nopermission");
|
||||
cc.getChatStyle().setColor(EnumChatFormatting.RED);
|
||||
requester.addChatMessage(cc);
|
||||
return;
|
||||
}
|
||||
String fileName = "eagler://" + skullHandler.installNewSkull(skullData);
|
||||
NBTTagCompound rootTagCompound = new NBTTagCompound();
|
||||
NBTTagCompound ownerTagCompound = new NBTTagCompound();
|
||||
ownerTagCompound.setString("Name", "Eagler");
|
||||
ownerTagCompound.setString("Id", EaglercraftUUID.nameUUIDFromBytes((("EaglerSkullUUID:" + fileName).getBytes(StandardCharsets.UTF_8))).toString());
|
||||
NBTTagCompound propertiesTagCompound = new NBTTagCompound();
|
||||
NBTTagList texturesTagList = new NBTTagList();
|
||||
NBTTagCompound texturesTagCompound = new NBTTagCompound();
|
||||
String texturesProp = "{\"textures\":{\"SKIN\":{\"url\":\"" + fileName + "\",\"metadata\":{\"model\":\"default\"}}}}";
|
||||
texturesTagCompound.setString("Value", Base64.encodeBase64String(texturesProp.getBytes(StandardCharsets.UTF_8)));
|
||||
texturesTagList.appendTag(texturesTagCompound);
|
||||
propertiesTagCompound.setTag("textures", texturesTagList);
|
||||
ownerTagCompound.setTag("Properties", propertiesTagCompound);
|
||||
rootTagCompound.setTag("SkullOwner", ownerTagCompound);
|
||||
NBTTagCompound displayTagCompound = new NBTTagCompound();
|
||||
displayTagCompound.setString("Name", EnumChatFormatting.RESET + "Custom Eaglercraft Skull");
|
||||
NBTTagList loreList = new NBTTagList();
|
||||
loreList.appendTag(new NBTTagString(EnumChatFormatting.GRAY + (fileName.length() > 24 ? (fileName.substring(0, 22) + "...") : fileName)));
|
||||
displayTagCompound.setTag("Lore", loreList);
|
||||
rootTagCompound.setTag("display", displayTagCompound);
|
||||
ItemStack stack = new ItemStack(Items.skull, 1, 3);
|
||||
stack.setTagCompound(rootTagCompound);
|
||||
boolean flag = requester.inventory.addItemStackToInventory(stack);
|
||||
if (flag) {
|
||||
requester.worldObj.playSoundAtEntity(requester, "random.pop", 0.2F,
|
||||
((requester.getRNG().nextFloat() - requester.getRNG().nextFloat()) * 0.7F + 1.0F)
|
||||
* 2.0F);
|
||||
requester.inventoryContainer.detectAndSendChanges();
|
||||
}
|
||||
requester.addChatMessage(new ChatComponentTranslation("command.skull.feedback", fileName));
|
||||
}
|
||||
|
||||
public void flushCache() {
|
||||
skullHandler.flushCache();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (c) 2025 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
package net.lax1dude.eaglercraft.v1_8.sp.server.skins;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePluginMessageProtocol;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessagePacket;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherCapeCustomEAG;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherCapeCustomV5EAG;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherCapePresetEAG;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherCapePresetV5EAG;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherSkinCustomV3EAG;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherSkinCustomV4EAG;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherSkinCustomV5EAG;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherSkinPresetEAG;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherSkinPresetV5EAG;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherTexturesV5EAG;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.util.SkinPacketVersionCache;
|
||||
|
||||
public class PlayerTextureData {
|
||||
|
||||
private int skinId;
|
||||
private byte[] skinTextureDataV3;
|
||||
private byte[] skinTextureDataV4;
|
||||
|
||||
private int capeId;
|
||||
private byte[] capeTextureData;
|
||||
|
||||
public PlayerTextureData(int skinId, byte[] skinTextureDataV3, byte[] skinTextureDataV4, int capeId,
|
||||
byte[] capeTextureData) {
|
||||
this.skinId = skinId;
|
||||
this.skinTextureDataV3 = skinTextureDataV3;
|
||||
this.skinTextureDataV4 = skinTextureDataV4;
|
||||
this.capeId = capeId;
|
||||
this.capeTextureData = capeTextureData;
|
||||
}
|
||||
|
||||
private byte[] getTextureV3() {
|
||||
if (skinTextureDataV3 != null) {
|
||||
return skinTextureDataV3;
|
||||
} else {
|
||||
return skinTextureDataV3 = SkinPacketVersionCache.convertToV3Raw(skinTextureDataV4);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] getTextureV4() {
|
||||
if (skinTextureDataV4 != null) {
|
||||
return skinTextureDataV4;
|
||||
} else {
|
||||
return skinTextureDataV4 = SkinPacketVersionCache.convertToV4Raw(skinTextureDataV3);
|
||||
}
|
||||
}
|
||||
|
||||
public GameMessagePacket getSkin(long uuidMost, long uuidLeast, GamePluginMessageProtocol protocol) {
|
||||
switch(protocol) {
|
||||
case V3:
|
||||
if (skinId < 0) {
|
||||
return new SPacketOtherSkinCustomV3EAG(uuidMost, uuidLeast, -skinId + 1, getTextureV3());
|
||||
} else {
|
||||
return new SPacketOtherSkinPresetEAG(uuidMost, uuidLeast, skinId);
|
||||
}
|
||||
case V4:
|
||||
if (skinId < 0) {
|
||||
return new SPacketOtherSkinCustomV4EAG(uuidMost, uuidLeast, -skinId + 1, getTextureV4());
|
||||
} else {
|
||||
return new SPacketOtherSkinPresetEAG(uuidMost, uuidLeast, skinId);
|
||||
}
|
||||
default:
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
public GameMessagePacket getSkinV5(int requestId, GamePluginMessageProtocol protocol) {
|
||||
if(protocol.ver >= 5) {
|
||||
if (skinId < 0) {
|
||||
return new SPacketOtherSkinCustomV5EAG(requestId, -skinId + 1, getTextureV4());
|
||||
} else {
|
||||
return new SPacketOtherSkinPresetV5EAG(requestId, skinId);
|
||||
}
|
||||
}else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
public GameMessagePacket getCape(long uuidMost, long uuidLeast, GamePluginMessageProtocol protocol) {
|
||||
if(protocol.ver <= 4) {
|
||||
if (capeId < 0) {
|
||||
return new SPacketOtherCapeCustomEAG(uuidMost, uuidLeast, capeTextureData);
|
||||
} else {
|
||||
return new SPacketOtherCapePresetEAG(uuidMost, uuidLeast, capeId);
|
||||
}
|
||||
}else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
public GameMessagePacket getCapeV5(int requestId, GamePluginMessageProtocol protocol) {
|
||||
if(protocol.ver >= 5) {
|
||||
if (capeId < 0) {
|
||||
return new SPacketOtherCapeCustomV5EAG(requestId, capeTextureData);
|
||||
} else {
|
||||
return new SPacketOtherCapePresetV5EAG(requestId, capeId);
|
||||
}
|
||||
}else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
public GameMessagePacket getTexturesV5(int requestId, GamePluginMessageProtocol protocol) {
|
||||
if(protocol.ver >= 5) {
|
||||
return new SPacketOtherTexturesV5EAG(requestId, skinId, skinId < 0 ? getTextureV4() : null, capeId,
|
||||
capeId < 0 ? capeTextureData : null);
|
||||
}else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved.
|
||||
* Copyright (c) 2022-2025 lax1dude, ayunami2000. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
@ -31,6 +31,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
import net.lax1dude.eaglercraft.v1_8.netty.ByteBuf;
|
||||
import net.lax1dude.eaglercraft.v1_8.netty.Unpooled;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.CompressionNotSupportedException;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.message.InjectedMessageController;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.SingleplayerServerController;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.server.EaglerIntegratedServerWorker;
|
||||
import net.minecraft.network.EnumConnectionState;
|
||||
@ -53,6 +54,7 @@ public class IntegratedServerPlayerNetworkManager {
|
||||
private int debugPacketCounter = 0;
|
||||
private final List<byte[]> recievedPacketBuffer = new LinkedList<>();
|
||||
private final boolean enableSendCompression;
|
||||
protected InjectedMessageController injectedController = null;
|
||||
|
||||
private boolean firstPacket = true;
|
||||
|
||||
@ -70,6 +72,10 @@ public class IntegratedServerPlayerNetworkManager {
|
||||
this.playerChannel = playerChannel;
|
||||
this.enableSendCompression = !SingleplayerServerController.PLAYER_CHANNEL.equals(playerChannel);
|
||||
}
|
||||
|
||||
public void setInjectedMessageController(InjectedMessageController controller) {
|
||||
injectedController = controller;
|
||||
}
|
||||
|
||||
public void connect() {
|
||||
fragmentedPacket.clear();
|
||||
@ -160,6 +166,10 @@ public class IntegratedServerPlayerNetworkManager {
|
||||
|
||||
++debugPacketCounter;
|
||||
try {
|
||||
if(injectedController != null && injectedController.handlePacket(fullData, 0)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ByteBuf nettyBuffer = Unpooled.buffer(fullData, fullData.length);
|
||||
nettyBuffer.writerIndex(fullData.length);
|
||||
PacketBuffer input = new PacketBuffer(nettyBuffer);
|
||||
@ -274,6 +284,66 @@ public class IntegratedServerPlayerNetworkManager {
|
||||
}
|
||||
}
|
||||
|
||||
public void injectRawFrame(byte[] data) {
|
||||
if(!isChannelOpen()) {
|
||||
return;
|
||||
}
|
||||
if(enableSendCompression) {
|
||||
int len = data.length;
|
||||
if(len > compressionThreshold) {
|
||||
if(compressedPacketTmp == null || compressedPacketTmp.length < len) {
|
||||
compressedPacketTmp = new byte[len];
|
||||
}
|
||||
int cmpLen;
|
||||
try {
|
||||
cmpLen = EaglerZLIB.deflateFull(data, 0, len, compressedPacketTmp, 0, compressedPacketTmp.length);
|
||||
}catch(IOException ex) {
|
||||
logger.error("Failed to compress injected frame!");
|
||||
logger.error(ex);
|
||||
return;
|
||||
}
|
||||
byte[] compressedData = new byte[5 + cmpLen];
|
||||
compressedData[0] = (byte)2;
|
||||
compressedData[1] = (byte)((len >>> 24) & 0xFF);
|
||||
compressedData[2] = (byte)((len >>> 16) & 0xFF);
|
||||
compressedData[3] = (byte)((len >>> 8) & 0xFF);
|
||||
compressedData[4] = (byte)(len & 0xFF);
|
||||
System.arraycopy(compressedPacketTmp, 0, compressedData, 5, cmpLen);
|
||||
if(compressedData.length > fragmentSize) {
|
||||
int fragmentSizeN1 = fragmentSize - 1;
|
||||
for (int j = 1; j < compressedData.length; j += fragmentSizeN1) {
|
||||
byte[] fragData = new byte[((j + fragmentSizeN1 > (compressedData.length - 1)) ? ((compressedData.length - 1) % fragmentSizeN1) : fragmentSizeN1) + 1];
|
||||
System.arraycopy(compressedData, j, fragData, 1, fragData.length - 1);
|
||||
fragData[0] = (j + fragmentSizeN1 < compressedData.length) ? (byte) 1 : (byte) 2;
|
||||
ServerPlatformSingleplayer.sendPacket(new IPCPacketData(playerChannel, fragData));
|
||||
}
|
||||
}else {
|
||||
ServerPlatformSingleplayer.sendPacket(new IPCPacketData(playerChannel, compressedData));
|
||||
}
|
||||
}else {
|
||||
int fragmentSizeN1 = fragmentSize - 1;
|
||||
if(len > fragmentSizeN1) {
|
||||
int idx = 0;
|
||||
do {
|
||||
int readLen = len > fragmentSizeN1 ? fragmentSizeN1 : len;
|
||||
byte[] frag = new byte[readLen + 1];
|
||||
System.arraycopy(data, idx, frag, 1, readLen);
|
||||
idx += readLen;
|
||||
len -= readLen;
|
||||
frag[0] = len == 0 ? (byte)0 : (byte)1;
|
||||
ServerPlatformSingleplayer.sendPacket(new IPCPacketData(playerChannel, frag));
|
||||
}while(len > 0);
|
||||
}else {
|
||||
byte[] bytes = new byte[len + 1];
|
||||
System.arraycopy(data, 0, bytes, 1, len);
|
||||
ServerPlatformSingleplayer.sendPacket(new IPCPacketData(playerChannel, bytes));
|
||||
}
|
||||
}
|
||||
}else {
|
||||
ServerPlatformSingleplayer.sendPacket(new IPCPacketData(playerChannel, data));
|
||||
}
|
||||
}
|
||||
|
||||
public void setNetHandler(INetHandler nethandler) {
|
||||
this.nethandler = nethandler;
|
||||
}
|
||||
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2025 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
package net.lax1dude.eaglercraft.v1_8.sp.server.socket.protocol;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessageHandler;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.server.EaglerMinecraftServer;
|
||||
import net.minecraft.network.NetHandlerPlayServer;
|
||||
|
||||
public abstract class ServerMessageHandler implements GameMessageHandler {
|
||||
|
||||
protected final NetHandlerPlayServer netHandler;
|
||||
protected final EaglerMinecraftServer server;
|
||||
|
||||
public ServerMessageHandler(NetHandlerPlayServer netHandler) {
|
||||
this.netHandler = netHandler;
|
||||
this.server = (EaglerMinecraftServer)netHandler.serverController;
|
||||
}
|
||||
|
||||
public static ServerMessageHandler createServerHandler(int version, NetHandlerPlayServer netHandler) {
|
||||
switch(version) {
|
||||
case 3:
|
||||
return new ServerV3MessageHandler(netHandler);
|
||||
case 4:
|
||||
return new ServerV4MessageHandler(netHandler);
|
||||
case 5:
|
||||
return new ServerV5MessageHandler(netHandler);
|
||||
default:
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
* Copyright (c) 2024-2025 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
@ -17,58 +17,57 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.sp.server.socket.protocol;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessageHandler;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.*;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.server.EaglerMinecraftServer;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.server.voice.IntegratedVoiceService;
|
||||
import net.minecraft.network.NetHandlerPlayServer;
|
||||
|
||||
public class ServerV3MessageHandler implements GameMessageHandler {
|
||||
|
||||
private final NetHandlerPlayServer netHandler;
|
||||
private final EaglerMinecraftServer server;
|
||||
public class ServerV3MessageHandler extends ServerMessageHandler {
|
||||
|
||||
public ServerV3MessageHandler(NetHandlerPlayServer netHandler) {
|
||||
this.netHandler = netHandler;
|
||||
this.server = (EaglerMinecraftServer)netHandler.serverController;
|
||||
super(netHandler);
|
||||
}
|
||||
|
||||
public void handleClient(CPacketGetOtherCapeEAG packet) {
|
||||
server.getCapeService().processGetOtherCape(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), netHandler.playerEntity);
|
||||
server.getTextureService().handleRequestPlayerCape(netHandler.playerEntity,
|
||||
new EaglercraftUUID(packet.uuidMost, packet.uuidLeast));
|
||||
}
|
||||
|
||||
public void handleClient(CPacketGetOtherSkinEAG packet) {
|
||||
server.getSkinService().processPacketGetOtherSkin(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), netHandler.playerEntity);
|
||||
server.getTextureService().handleRequestPlayerSkin(netHandler.playerEntity,
|
||||
new EaglercraftUUID(packet.uuidMost, packet.uuidLeast));
|
||||
}
|
||||
|
||||
public void handleClient(CPacketGetSkinByURLEAG packet) {
|
||||
server.getSkinService().processPacketGetOtherSkin(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), packet.url, netHandler.playerEntity);
|
||||
server.getTextureService().handleRequestSkinByURL(netHandler.playerEntity,
|
||||
new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), packet.url);
|
||||
}
|
||||
|
||||
public void handleClient(CPacketInstallSkinSPEAG packet) {
|
||||
server.getSkinService().processPacketInstallNewSkin(packet.customSkin, netHandler.playerEntity);
|
||||
server.getTextureService().handleInstallNewSkin(netHandler.playerEntity, packet.customSkin);
|
||||
}
|
||||
|
||||
public void handleClient(CPacketVoiceSignalConnectEAG packet) {
|
||||
IntegratedVoiceService voiceSvc = server.getVoiceService();
|
||||
if(voiceSvc != null) {
|
||||
if (voiceSvc != null) {
|
||||
voiceSvc.handleVoiceSignalPacketTypeConnect(netHandler.playerEntity);
|
||||
}
|
||||
}
|
||||
|
||||
public void handleClient(CPacketVoiceSignalDescEAG packet) {
|
||||
IntegratedVoiceService voiceSvc = server.getVoiceService();
|
||||
if(voiceSvc != null) {
|
||||
voiceSvc.handleVoiceSignalPacketTypeDesc(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), packet.desc, netHandler.playerEntity);
|
||||
if (voiceSvc != null) {
|
||||
voiceSvc.handleVoiceSignalPacketTypeDesc(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast),
|
||||
packet.desc, netHandler.playerEntity);
|
||||
}
|
||||
}
|
||||
|
||||
public void handleClient(CPacketVoiceSignalDisconnectV3EAG packet) {
|
||||
IntegratedVoiceService voiceSvc = server.getVoiceService();
|
||||
if(voiceSvc != null) {
|
||||
if(packet.isPeerType) {
|
||||
voiceSvc.handleVoiceSignalPacketTypeDisconnectPeer(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), netHandler.playerEntity);
|
||||
}else {
|
||||
if (voiceSvc != null) {
|
||||
if (packet.isPeerType) {
|
||||
voiceSvc.handleVoiceSignalPacketTypeDisconnectPeer(
|
||||
new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), netHandler.playerEntity);
|
||||
} else {
|
||||
voiceSvc.handleVoiceSignalPacketTypeDisconnect(netHandler.playerEntity);
|
||||
}
|
||||
}
|
||||
@ -76,15 +75,17 @@ public class ServerV3MessageHandler implements GameMessageHandler {
|
||||
|
||||
public void handleClient(CPacketVoiceSignalICEEAG packet) {
|
||||
IntegratedVoiceService voiceSvc = server.getVoiceService();
|
||||
if(voiceSvc != null) {
|
||||
voiceSvc.handleVoiceSignalPacketTypeICE(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), packet.ice, netHandler.playerEntity);
|
||||
if (voiceSvc != null) {
|
||||
voiceSvc.handleVoiceSignalPacketTypeICE(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), packet.ice,
|
||||
netHandler.playerEntity);
|
||||
}
|
||||
}
|
||||
|
||||
public void handleClient(CPacketVoiceSignalRequestEAG packet) {
|
||||
IntegratedVoiceService voiceSvc = server.getVoiceService();
|
||||
if(voiceSvc != null) {
|
||||
voiceSvc.handleVoiceSignalPacketTypeRequest(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), netHandler.playerEntity);
|
||||
if (voiceSvc != null) {
|
||||
voiceSvc.handleVoiceSignalPacketTypeRequest(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast),
|
||||
netHandler.playerEntity);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||||
* Copyright (c) 2024-2025 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
@ -17,52 +17,21 @@
|
||||
package net.lax1dude.eaglercraft.v1_8.sp.server.socket.protocol;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.GameMessageHandler;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.WrongPacketException;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.*;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.SPacketOtherPlayerClientUUIDV4EAG;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.server.EaglerMinecraftServer;
|
||||
import net.lax1dude.eaglercraft.v1_8.sp.server.voice.IntegratedVoiceService;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.network.NetHandlerPlayServer;
|
||||
|
||||
public class ServerV4MessageHandler implements GameMessageHandler {
|
||||
|
||||
private final NetHandlerPlayServer netHandler;
|
||||
private final EaglerMinecraftServer server;
|
||||
public class ServerV4MessageHandler extends ServerV3MessageHandler {
|
||||
|
||||
public ServerV4MessageHandler(NetHandlerPlayServer netHandler) {
|
||||
this.netHandler = netHandler;
|
||||
this.server = (EaglerMinecraftServer)netHandler.serverController;
|
||||
super(netHandler);
|
||||
}
|
||||
|
||||
public void handleClient(CPacketGetOtherCapeEAG packet) {
|
||||
server.getCapeService().processGetOtherCape(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), netHandler.playerEntity);
|
||||
}
|
||||
|
||||
public void handleClient(CPacketGetOtherSkinEAG packet) {
|
||||
server.getSkinService().processPacketGetOtherSkin(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), netHandler.playerEntity);
|
||||
}
|
||||
|
||||
public void handleClient(CPacketGetSkinByURLEAG packet) {
|
||||
server.getSkinService().processPacketGetOtherSkin(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), packet.url, netHandler.playerEntity);
|
||||
}
|
||||
|
||||
public void handleClient(CPacketInstallSkinSPEAG packet) {
|
||||
server.getSkinService().processPacketInstallNewSkin(packet.customSkin, netHandler.playerEntity);
|
||||
}
|
||||
|
||||
public void handleClient(CPacketVoiceSignalConnectEAG packet) {
|
||||
IntegratedVoiceService voiceSvc = server.getVoiceService();
|
||||
if(voiceSvc != null) {
|
||||
voiceSvc.handleVoiceSignalPacketTypeConnect(netHandler.playerEntity);
|
||||
}
|
||||
}
|
||||
|
||||
public void handleClient(CPacketVoiceSignalDescEAG packet) {
|
||||
IntegratedVoiceService voiceSvc = server.getVoiceService();
|
||||
if(voiceSvc != null) {
|
||||
voiceSvc.handleVoiceSignalPacketTypeDesc(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), packet.desc, netHandler.playerEntity);
|
||||
}
|
||||
public void handleClient(CPacketVoiceSignalDisconnectV3EAG packet) {
|
||||
throw new WrongPacketException();
|
||||
}
|
||||
|
||||
public void handleClient(CPacketVoiceSignalDisconnectV4EAG packet) {
|
||||
@ -74,30 +43,19 @@ public class ServerV4MessageHandler implements GameMessageHandler {
|
||||
|
||||
public void handleClient(CPacketVoiceSignalDisconnectPeerV4EAG packet) {
|
||||
IntegratedVoiceService voiceSvc = server.getVoiceService();
|
||||
if(voiceSvc != null) {
|
||||
voiceSvc.handleVoiceSignalPacketTypeDisconnectPeer(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), netHandler.playerEntity);
|
||||
}
|
||||
}
|
||||
|
||||
public void handleClient(CPacketVoiceSignalICEEAG packet) {
|
||||
IntegratedVoiceService voiceSvc = server.getVoiceService();
|
||||
if(voiceSvc != null) {
|
||||
voiceSvc.handleVoiceSignalPacketTypeICE(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), packet.ice, netHandler.playerEntity);
|
||||
}
|
||||
}
|
||||
|
||||
public void handleClient(CPacketVoiceSignalRequestEAG packet) {
|
||||
IntegratedVoiceService voiceSvc = server.getVoiceService();
|
||||
if(voiceSvc != null) {
|
||||
voiceSvc.handleVoiceSignalPacketTypeRequest(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast), netHandler.playerEntity);
|
||||
if (voiceSvc != null) {
|
||||
voiceSvc.handleVoiceSignalPacketTypeDisconnectPeer(new EaglercraftUUID(packet.uuidMost, packet.uuidLeast),
|
||||
netHandler.playerEntity);
|
||||
}
|
||||
}
|
||||
|
||||
public void handleClient(CPacketGetOtherClientUUIDV4EAG packet) {
|
||||
EntityPlayerMP player = server.getConfigurationManager().getPlayerByUUID(new EaglercraftUUID(packet.playerUUIDMost, packet.playerUUIDLeast));
|
||||
if(player != null && player.clientBrandUUID != null) {
|
||||
netHandler.sendEaglerMessage(new SPacketOtherPlayerClientUUIDV4EAG(packet.requestId, player.clientBrandUUID.msb, player.clientBrandUUID.lsb));
|
||||
}else {
|
||||
EntityPlayerMP player = server.getConfigurationManager()
|
||||
.getPlayerByUUID(new EaglercraftUUID(packet.playerUUIDMost, packet.playerUUIDLeast));
|
||||
if (player != null && player.clientBrandUUID != null) {
|
||||
netHandler.sendEaglerMessage(new SPacketOtherPlayerClientUUIDV4EAG(packet.requestId,
|
||||
player.clientBrandUUID.msb, player.clientBrandUUID.lsb));
|
||||
} else {
|
||||
netHandler.sendEaglerMessage(new SPacketOtherPlayerClientUUIDV4EAG(packet.requestId, 0l, 0l));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2024-2025 lax1dude. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
package net.lax1dude.eaglercraft.v1_8.sp.server.socket.protocol;
|
||||
|
||||
import net.lax1dude.eaglercraft.v1_8.EaglercraftUUID;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.WrongPacketException;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.client.*;
|
||||
import net.minecraft.network.NetHandlerPlayServer;
|
||||
|
||||
public class ServerV5MessageHandler extends ServerV4MessageHandler {
|
||||
|
||||
public ServerV5MessageHandler(NetHandlerPlayServer netHandler) {
|
||||
super(netHandler);
|
||||
}
|
||||
|
||||
public void handleClient(CPacketGetOtherCapeEAG packet) {
|
||||
throw new WrongPacketException();
|
||||
}
|
||||
|
||||
public void handleClient(CPacketGetOtherSkinEAG packet) {
|
||||
throw new WrongPacketException();
|
||||
}
|
||||
|
||||
public void handleClient(CPacketGetSkinByURLEAG packet) {
|
||||
throw new WrongPacketException();
|
||||
}
|
||||
|
||||
public void handleClient(CPacketGetOtherCapeV5EAG packet) {
|
||||
server.getTextureService().handleRequestPlayerCapeV5(netHandler.playerEntity, packet.requestId,
|
||||
new EaglercraftUUID(packet.uuidMost, packet.uuidLeast));
|
||||
}
|
||||
|
||||
public void handleClient(CPacketGetOtherSkinV5EAG packet) {
|
||||
server.getTextureService().handleRequestPlayerSkinV5(netHandler.playerEntity, packet.requestId,
|
||||
new EaglercraftUUID(packet.uuidMost, packet.uuidLeast));
|
||||
}
|
||||
|
||||
public void handleClient(CPacketGetSkinByURLV5EAG packet) {
|
||||
server.getTextureService().handleRequestSkinByURLV5(netHandler.playerEntity, packet.requestId, packet.url);
|
||||
}
|
||||
|
||||
public void handleClient(CPacketGetOtherTexturesV5EAG packet) {
|
||||
server.getTextureService().handleRequestPlayerTexturesV5(netHandler.playerEntity, packet.requestId,
|
||||
new EaglercraftUUID(packet.uuidMost, packet.uuidLeast));
|
||||
}
|
||||
|
||||
}
|
@ -32,6 +32,7 @@ import net.lax1dude.eaglercraft.v1_8.socket.protocol.pkt.server.*;
|
||||
import net.lax1dude.eaglercraft.v1_8.voice.ExpiringSet;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
|
||||
//TODO: Rewrite to be more like EaglerXServer
|
||||
public class IntegratedVoiceService {
|
||||
|
||||
public static final Logger logger = LogManager.getLogger("IntegratedVoiceService");
|
||||
@ -151,22 +152,33 @@ public class IntegratedVoiceService {
|
||||
}
|
||||
GameMessagePacket v3p = null;
|
||||
GameMessagePacket v4p = null;
|
||||
for(EntityPlayerMP conn : voicePlayers.values()) {
|
||||
if(conn.playerNetServerHandler.getEaglerMessageProtocol().ver <= 3) {
|
||||
conn.playerNetServerHandler.sendEaglerMessage(v3p == null ? (v3p = new SPacketVoiceSignalConnectV3EAG(senderUuid.msb, senderUuid.lsb, true, false)) : v3p);
|
||||
} else {
|
||||
conn.playerNetServerHandler.sendEaglerMessage(v4p == null ? (v4p = new SPacketVoiceSignalConnectAnnounceV4EAG(senderUuid.msb, senderUuid.lsb)) : v4p);
|
||||
}
|
||||
}
|
||||
Collection<SPacketVoiceSignalGlobalEAG.UserData> userDatas = new ArrayList<>(voicePlayers.size());
|
||||
for(EntityPlayerMP player : voicePlayers.values()) {
|
||||
EaglercraftUUID uuid = player.getUniqueID();
|
||||
userDatas.add(new SPacketVoiceSignalGlobalEAG.UserData(uuid.msb, uuid.lsb, player.getName()));
|
||||
for(EntityPlayerMP conn : voicePlayers.values()) {
|
||||
EaglercraftUUID otherUuid = conn.getUniqueID();
|
||||
if(conn != sender) {
|
||||
if(conn.playerNetServerHandler.getEaglerMessageProtocol().ver <= 3) {
|
||||
conn.playerNetServerHandler.sendEaglerMessage(v3p == null ? (v3p = new SPacketVoiceSignalConnectV3EAG(senderUuid.msb, senderUuid.lsb, true, false)) : v3p);
|
||||
} else {
|
||||
conn.playerNetServerHandler.sendEaglerMessage(v4p == null ? (v4p = new SPacketVoiceSignalConnectAnnounceV4EAG(senderUuid.msb, senderUuid.lsb)) : v4p);
|
||||
}
|
||||
}
|
||||
userDatas.add(new SPacketVoiceSignalGlobalEAG.UserData(otherUuid.msb, otherUuid.lsb, conn.getName()));
|
||||
}
|
||||
SPacketVoiceSignalGlobalEAG packetToBroadcast = new SPacketVoiceSignalGlobalEAG(userDatas);
|
||||
for (EntityPlayerMP userCon : voicePlayers.values()) {
|
||||
userCon.playerNetServerHandler.sendEaglerMessage(packetToBroadcast);
|
||||
}
|
||||
boolean selfV3 = sender.playerNetServerHandler.getEaglerMessageProtocol().ver <= 3;
|
||||
for(EntityPlayerMP conn : voicePlayers.values()) {
|
||||
EaglercraftUUID otherUuid = conn.getUniqueID();
|
||||
if(conn != sender) {
|
||||
if(selfV3) {
|
||||
sender.playerNetServerHandler.sendEaglerMessage(new SPacketVoiceSignalConnectV3EAG(otherUuid.msb, otherUuid.lsb, true, false));
|
||||
}else {
|
||||
sender.playerNetServerHandler.sendEaglerMessage(new SPacketVoiceSignalConnectAnnounceV4EAG(otherUuid.msb, otherUuid.lsb));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void handleVoiceSignalPacketTypeICE(EaglercraftUUID player, byte[] str, EntityPlayerMP sender) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2023-2024 lax1dude, ayunami2000. All Rights Reserved.
|
||||
* Copyright (c) 2023-2025 lax1dude, ayunami2000. All Rights Reserved.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
@ -78,6 +78,10 @@ public class ClientIntegratedServerNetworkManager extends EaglercraftNetworkMana
|
||||
byte[] next = recievedPacketBuffer.remove(0);
|
||||
++debugPacketCounter;
|
||||
try {
|
||||
if(injectedController != null && injectedController.handlePacket(next, 0)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ByteBuf nettyBuffer = Unpooled.buffer(next, next.length);
|
||||
nettyBuffer.writerIndex(next.length);
|
||||
PacketBuffer input = new PacketBuffer(nettyBuffer);
|
||||
@ -168,4 +172,14 @@ public class ClientIntegratedServerNetworkManager extends EaglercraftNetworkMana
|
||||
public void clearRecieveQueue() {
|
||||
recievedPacketBuffer.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectRawFrame(byte[] data) {
|
||||
if(!isChannelOpen()) {
|
||||
logger.error("Frame was injected on a closed connection");
|
||||
return;
|
||||
}
|
||||
ClientPlatformSingleplayer.sendPacket(new IPCPacketData(address, data));
|
||||
}
|
||||
|
||||
}
|
@ -20,9 +20,7 @@ import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
||||
import net.lax1dude.eaglercraft.v1_8.netty.Unpooled;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.EaglercraftNetworkManager;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePluginMessageConstants;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.GamePluginMessageProtocol;
|
||||
import net.lax1dude.eaglercraft.v1_8.socket.protocol.client.GameProtocolMessageController;
|
||||
import net.lax1dude.eaglercraft.v1_8.update.UpdateService;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiDisconnected;
|
||||
@ -73,15 +71,14 @@ public class NetHandlerSingleplayerLogin implements INetHandlerLoginClient {
|
||||
return;
|
||||
}
|
||||
logger.info("Server is using protocol: {}", p);
|
||||
NetHandlerPlayClient netHandler = new NetHandlerPlayClient(this.mc, this.previousGuiScreen, this.networkManager, var1.getProfile());
|
||||
netHandler.setEaglerMessageController(
|
||||
new GameProtocolMessageController(mp, GamePluginMessageConstants.CLIENT_TO_SERVER,
|
||||
GameProtocolMessageController.createClientHandler(p, netHandler),
|
||||
(ch, msg) -> netHandler.addToSendQueue(new C17PacketCustomPayload(ch, msg))));
|
||||
this.networkManager.setLANInfo(p);
|
||||
NetHandlerPlayClient netHandler = new NetHandlerPlayClient(this.mc, this.previousGuiScreen, this.networkManager,
|
||||
var1.getProfile(), mp);
|
||||
this.networkManager.setNetHandler(netHandler);
|
||||
byte[] b = UpdateService.getClientSignatureData();
|
||||
if(b != null) {
|
||||
this.networkManager.sendPacket(new C17PacketCustomPayload("EAG|MyUpdCert-1.8", new PacketBuffer(Unpooled.buffer(b, b.length).writerIndex(b.length))));
|
||||
this.networkManager.sendPacket(new C17PacketCustomPayload("EAG|MyUpdCert-1.8",
|
||||
new PacketBuffer(Unpooled.buffer(b, b.length).writerIndex(b.length))));
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user