Update #22 - Singleplayer and shared worlds, shader fixes

This commit is contained in:
lax1dude
2023-12-12 01:22:54 -08:00
parent e3d6256493
commit 3f00d402fa
2350 changed files with 45241 additions and 7798 deletions

View File

@ -0,0 +1,98 @@
package net.lax1dude.eaglercraft.v1_8.sp;
import net.lax1dude.eaglercraft.v1_8.sp.ipc.*;
/**
* Copyright (c) 2022-2024 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
* 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.
*
*/
public class IntegratedServerState {
public static final int WORLD_WORKER_NOT_RUNNING = -2;
public static final int WORLD_WORKER_BOOTING = -1;
public static final int WORLD_NONE = 0;
public static final int WORLD_LOADING = 2;
public static final int WORLD_LOADED = 3;
public static final int WORLD_UNLOADING = 4;
public static final int WORLD_DELETING = 5;
public static final int WORLD_RENAMING = 6;
public static final int WORLD_DUPLICATING = 7;
public static final int WORLD_PAUSED = 9;
public static final int WORLD_LISTING = 10;
public static final int WORLD_SAVING = 11;
public static final int WORLD_IMPORTING = 12;
public static final int WORLD_EXPORTING = 13;
public static final int WORLD_GET_NBT = 14;
public static final int WORLD_LIST_FILE = 15;
public static final int WORLD_FILE_READ = 16;
public static final int WORLD_FILE_WRITE = 17;
public static final int WORLD_FILE_MOVE = 18;
public static final int WORLD_FILE_COPY = 19;
public static final int WORLD_CLEAR_PLAYERS = 20;
public static String getStateName(int i) {
switch(i) {
case WORLD_WORKER_NOT_RUNNING: return "WORLD_WORKER_NOT_RUNNING";
case WORLD_WORKER_BOOTING: return "WORLD_WORKER_BOOTING";
case WORLD_NONE: return "WORLD_NONE";
case WORLD_LOADING: return "WORLD_LOADING";
case WORLD_LOADED: return "WORLD_LOADED";
case WORLD_UNLOADING: return "WORLD_UNLOADING";
case WORLD_DELETING: return "WORLD_DELETING";
case WORLD_RENAMING: return "WORLD_RENAMING";
case WORLD_DUPLICATING: return "WORLD_DUPLICATING";
case WORLD_PAUSED: return "WORLD_PAUSED";
case WORLD_LISTING: return "WORLD_LISTING";
case WORLD_SAVING: return "WORLD_SAVING";
case WORLD_IMPORTING: return "WORLD_IMPORTING";
case WORLD_EXPORTING: return "WORLD_EXPORTING";
case WORLD_GET_NBT: return "WORLD_GET_NBT";
case WORLD_LIST_FILE: return "WORLD_LIST_FILE";
case WORLD_FILE_READ: return "WORLD_FILE_READ";
case WORLD_FILE_WRITE: return "WORLD_FILE_WRITE";
case WORLD_FILE_MOVE: return "WORLD_FILE_MOVE";
case WORLD_FILE_COPY: return "WORLD_FILE_COPY";
case WORLD_CLEAR_PLAYERS: return "WORLD_CLEAR_PLAYERS";
default: return "INVALID";
}
}
public static boolean isACKValidInState(int ack, int state) {
switch(ack) {
case 0xFF: return state == WORLD_WORKER_BOOTING;
case IPCPacketFFProcessKeepAlive.EXITED: return true;
case IPCPacketFFProcessKeepAlive.FAILURE: return true;
case IPCPacket01StopServer.ID: return true;
case IPCPacket00StartServer.ID: return state == WORLD_LOADING;
case IPCPacket03DeleteWorld.ID: return state == WORLD_DELETING;
case IPCPacket06RenameWorldNBT.ID: return (state == WORLD_DUPLICATING || state == WORLD_RENAMING);
case IPCPacket07ImportWorld.ID: return state == WORLD_IMPORTING;
case IPCPacket0BPause.ID:
case IPCPacket19Autosave.ID: return (state == WORLD_SAVING || state == WORLD_PAUSED || state == WORLD_LOADED || state == WORLD_UNLOADING);
case IPCPacket12FileWrite.ID: return state == WORLD_FILE_WRITE;
case IPCPacket13FileCopyMove.ID: return (state == WORLD_FILE_MOVE || state == WORLD_FILE_COPY);
case IPCPacket18ClearPlayers.ID: return state == WORLD_CLEAR_PLAYERS;
default: return false;
}
}
public static void assertState(int ack, int state) {
if(!isACKValidInState(ack, state)) {
String msg = "Recieved ACK " + ack + " while the client state was " + state + " '" + getStateName(state) + "'";
throw new IllegalStateException(msg);
}
}
}

View File

@ -0,0 +1,32 @@
package net.lax1dude.eaglercraft.v1_8.sp;
import net.minecraft.world.storage.SaveHandlerMP;
import net.minecraft.world.storage.WorldInfo;
/**
* Copyright (c) 2023-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.
*
*/
public class SingleplayerSaveHandler extends SaveHandlerMP {
private final WorldInfo worldInfo;
public SingleplayerSaveHandler(WorldInfo worldInfo) {
this.worldInfo = worldInfo;
}
public WorldInfo loadWorldInfo() {
return worldInfo;
}
}

View File

@ -0,0 +1,586 @@
package net.lax1dude.eaglercraft.v1_8.sp;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import net.lax1dude.eaglercraft.v1_8.internal.PlatformWebRTC;
import org.apache.commons.lang3.StringUtils;
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
import net.lax1dude.eaglercraft.v1_8.internal.EnumEaglerConnectionState;
import net.lax1dude.eaglercraft.v1_8.internal.IPCPacketData;
import net.lax1dude.eaglercraft.v1_8.internal.PlatformApplication;
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
import net.lax1dude.eaglercraft.v1_8.profile.EaglerProfile;
import net.lax1dude.eaglercraft.v1_8.sp.internal.ClientPlatformSingleplayer;
import net.lax1dude.eaglercraft.v1_8.sp.ipc.*;
import net.lax1dude.eaglercraft.v1_8.sp.lan.LANServerController;
import net.lax1dude.eaglercraft.v1_8.sp.socket.ClientIntegratedServerNetworkManager;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.IProgressUpdate;
import net.minecraft.util.StringTranslate;
import net.minecraft.world.WorldSettings;
import net.minecraft.world.storage.ISaveFormat;
import net.minecraft.world.storage.ISaveHandler;
import net.minecraft.world.storage.SaveFormatComparator;
import net.minecraft.world.storage.WorldInfo;
/**
* Copyright (c) 2022-2024 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
* 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.
*
*/
public class SingleplayerServerController implements ISaveFormat {
public static final String IPC_CHANNEL = "~!IPC";
public static final String PLAYER_CHANNEL = "~!LOCAL_PLAYER";
private static int statusState = IntegratedServerState.WORLD_WORKER_NOT_RUNNING;
private static boolean loggingState = true;
private static String worldStatusString = "";
private static float worldStatusProgress = 0.0f;
private static final LinkedList<IPCPacket15Crashed> exceptions = new LinkedList();
public static final SingleplayerServerController instance = new SingleplayerServerController();
public static final Logger logger = LogManager.getLogger("SingleplayerServerController");
public static final List<SaveFormatComparator> saveListCache = new ArrayList();
public static final Map<String, WorldInfo> saveListMap = new HashMap();
public static final List<NBTTagCompound> saveListNBT = new ArrayList();
private static boolean isPaused = false;
private static List<String> integratedServerTPS = new ArrayList();
private static long integratedServerLastTPSUpdate = 0;
public static final ClientIntegratedServerNetworkManager localPlayerNetworkManager = new ClientIntegratedServerNetworkManager(PLAYER_CHANNEL);
private static final List<String> openLANChannels = new ArrayList();
private SingleplayerServerController() {
}
public static void startIntegratedServerWorker() {
if(statusState == IntegratedServerState.WORLD_WORKER_NOT_RUNNING) {
exceptions.clear();
statusState = IntegratedServerState.WORLD_WORKER_BOOTING;
loggingState = true;
ClientPlatformSingleplayer.startIntegratedServer();
}
}
public static boolean isIntegratedServerWorkerStarted() {
return statusState != IntegratedServerState.WORLD_WORKER_NOT_RUNNING && statusState != IntegratedServerState.WORLD_WORKER_BOOTING;
}
public static boolean isIntegratedServerWorkerAlive() {
return statusState != IntegratedServerState.WORLD_WORKER_NOT_RUNNING;
}
public static boolean isRunningSingleThreadMode() {
return ClientPlatformSingleplayer.isRunningSingleThreadMode();
}
public static boolean isReady() {
return statusState == IntegratedServerState.WORLD_NONE;
}
public static boolean isWorldNotLoaded() {
return statusState == IntegratedServerState.WORLD_NONE || statusState == IntegratedServerState.WORLD_WORKER_NOT_RUNNING ||
statusState == IntegratedServerState.WORLD_WORKER_BOOTING;
}
public static boolean isWorldRunning() {
return statusState == IntegratedServerState.WORLD_LOADED || statusState == IntegratedServerState.WORLD_PAUSED ||
statusState == IntegratedServerState.WORLD_LOADING || statusState == IntegratedServerState.WORLD_SAVING;
}
public static boolean isWorldReady() {
return statusState == IntegratedServerState.WORLD_LOADED || statusState == IntegratedServerState.WORLD_PAUSED ||
statusState == IntegratedServerState.WORLD_SAVING;
}
public static int getStatusState() {
return statusState;
}
public static boolean isChannelOpen(String ch) {
return openLANChannels.contains(ch);
}
public static boolean isChannelNameAllowed(String ch) {
return !IPC_CHANNEL.equals(ch) && !PLAYER_CHANNEL.equals(ch);
}
public static void openPlayerChannel(String ch) {
if(openLANChannels.contains(ch)) {
logger.error("Tried to open channel that already exists: \"{}\"", ch);
} else if (!isChannelNameAllowed(ch)) {
logger.error("Tried to open disallowed channel name: \"{}\"", ch);
}else {
openLANChannels.add(ch);
sendIPCPacket(new IPCPacket0CPlayerChannel(ch, true));
PlatformWebRTC.serverLANCreatePeer(ch);
}
}
public static void closePlayerChannel(String ch) {
if(!openLANChannels.remove(ch)) {
logger.error("Tried to close channel that doesn't exist: \"{}\"", ch);
}else {
sendIPCPacket(new IPCPacket0CPlayerChannel(ch, false));
PlatformWebRTC.serverLANDisconnectPeer(ch);
}
}
public static void openLocalPlayerChannel() {
localPlayerNetworkManager.isPlayerChannelOpen = true;
sendIPCPacket(new IPCPacket0CPlayerChannel(PLAYER_CHANNEL, true));
}
public static void closeLocalPlayerChannel() {
localPlayerNetworkManager.isPlayerChannelOpen = false;
sendIPCPacket(new IPCPacket0CPlayerChannel(PLAYER_CHANNEL, false));
}
private static void ensureReady() {
if(!isReady()) {
String msg = "Server is in state " + statusState + " '" + IntegratedServerState.getStateName(statusState) + "' which is not the 'WORLD_NONE' state for the requested IPC operation";
throw new IllegalStateException(msg);
}
}
private static void ensureWorldReady() {
if(!isWorldReady()) {
String msg = "Server is in state " + statusState + " '" + IntegratedServerState.getStateName(statusState) + "' which is not the 'WORLD_LOADED' state for the requested IPC operation";
throw new IllegalStateException(msg);
}
}
public static void launchEaglercraftServer(String folderName, int difficulty, int viewDistance, WorldSettings settings) {
ensureReady();
clearTPS();
if(settings != null) {
sendIPCPacket(new IPCPacket02InitWorld(folderName, settings.getGameType().getID(),
settings.getTerrainType().getWorldTypeID(), settings.getWorldName(), settings.getSeed(),
settings.areCommandsAllowed(), settings.isMapFeaturesEnabled(), settings.isBonusChestEnabled(),
settings.getHardcoreEnabled()));
}
statusState = IntegratedServerState.WORLD_LOADING;
worldStatusProgress = 0.0f;
sendIPCPacket(new IPCPacket00StartServer(folderName, EaglerProfile.getName(), difficulty, viewDistance, EagRuntime.getConfiguration().isDemo()));
}
public static void clearTPS() {
integratedServerTPS.clear();
integratedServerLastTPSUpdate = 0l;
}
public static List<String> getTPS() {
return integratedServerTPS;
}
public static long getTPSAge() {
return System.currentTimeMillis() - integratedServerLastTPSUpdate;
}
public static boolean hangupEaglercraftServer() {
LANServerController.closeLAN();
if(isWorldRunning()) {
logger.error("Shutting down integrated server due to unexpected client hangup, this is a memleak");
statusState = IntegratedServerState.WORLD_UNLOADING;
sendIPCPacket(new IPCPacket01StopServer());
return true;
}else {
return false;
}
}
public static boolean shutdownEaglercraftServer() {
LANServerController.closeLAN();
if(isWorldRunning()) {
logger.info("Shutting down integrated server");
statusState = IntegratedServerState.WORLD_UNLOADING;
sendIPCPacket(new IPCPacket01StopServer());
return true;
}else {
return false;
}
}
public static void autoSave() {
if(!isPaused) {
statusState = IntegratedServerState.WORLD_SAVING;
sendIPCPacket(new IPCPacket19Autosave());
}
}
public static void setPaused(boolean pause) {
if(statusState != IntegratedServerState.WORLD_LOADED && statusState != IntegratedServerState.WORLD_PAUSED && statusState != IntegratedServerState.WORLD_SAVING) {
return;
}
if(isPaused != pause) {
sendIPCPacket(new IPCPacket0BPause(pause));
isPaused = pause;
}
}
public static void runTick() {
List<IPCPacketData> pktList = ClientPlatformSingleplayer.recieveAllPacket();
if(pktList != null) {
IPCPacketData packetData;
for(int i = 0, l = pktList.size(); i < l; ++i) {
packetData = pktList.get(i);
if(packetData.channel.equals(SingleplayerServerController.IPC_CHANNEL)) {
IPCPacketBase ipc;
try {
ipc = IPCPacketManager.IPCDeserialize(packetData.contents);
}catch(IOException ex) {
throw new RuntimeException("Failed to deserialize IPC packet", ex);
}
handleIPCPacket(ipc);
}else if(packetData.channel.equals(SingleplayerServerController.PLAYER_CHANNEL)) {
if(localPlayerNetworkManager.getConnectStatus() != EnumEaglerConnectionState.CLOSED) {
localPlayerNetworkManager.addRecievedPacket(packetData.contents);
}else {
logger.warn("Recieved {} byte packet on closed local player connection", packetData.contents.length);
}
}else {
PlatformWebRTC.serverLANWritePacket(packetData.channel, packetData.contents);
}
}
}
boolean logWindowState = PlatformApplication.isShowingDebugConsole();
if(loggingState != logWindowState) {
loggingState = logWindowState;
sendIPCPacket(new IPCPacket21EnableLogging(logWindowState));
}
LANServerController.updateLANServer();
}
private static void handleIPCPacket(IPCPacketBase ipc) {
switch(ipc.id()) {
case IPCPacketFFProcessKeepAlive.ID: {
IPCPacketFFProcessKeepAlive pkt = (IPCPacketFFProcessKeepAlive)ipc;
IntegratedServerState.assertState(pkt.ack, statusState);
switch(pkt.ack) {
case 0xFF:
logger.info("Integrated server signaled a successful boot");
sendIPCPacket(new IPCPacket14StringList(IPCPacket14StringList.LOCALE, StringTranslate.dump()));
statusState = IntegratedServerState.WORLD_NONE;
break;
case IPCPacket00StartServer.ID:
statusState = IntegratedServerState.WORLD_LOADED;
isPaused = false;
break;
case IPCPacket0BPause.ID:
case IPCPacket19Autosave.ID:
if(statusState != IntegratedServerState.WORLD_UNLOADING) {
statusState = isPaused ? IntegratedServerState.WORLD_PAUSED : IntegratedServerState.WORLD_LOADED;
}
break;
case IPCPacketFFProcessKeepAlive.FAILURE:
logger.error("Server signaled 'FAILURE' response in state '{}'", IntegratedServerState.getStateName(statusState));
statusState = IntegratedServerState.WORLD_NONE;
callFailed = true;
break;
case IPCPacket01StopServer.ID:
LANServerController.closeLAN();
localPlayerNetworkManager.isPlayerChannelOpen = false;
statusState = IntegratedServerState.WORLD_NONE;
break;
case IPCPacket06RenameWorldNBT.ID:
statusState = IntegratedServerState.WORLD_NONE;
break;
case IPCPacket03DeleteWorld.ID:
case IPCPacket07ImportWorld.ID:
case IPCPacket12FileWrite.ID:
case IPCPacket13FileCopyMove.ID:
case IPCPacket18ClearPlayers.ID:
statusState = IntegratedServerState.WORLD_NONE;
break;
case IPCPacketFFProcessKeepAlive.EXITED:
logger.error("Server signaled 'EXITED' response in state '{}'", IntegratedServerState.getStateName(statusState));
if(ClientPlatformSingleplayer.canKillWorker()) {
ClientPlatformSingleplayer.killWorker();
}
LANServerController.closeLAN();
localPlayerNetworkManager.isPlayerChannelOpen = false;
statusState = IntegratedServerState.WORLD_WORKER_NOT_RUNNING;
callFailed = true;
break;
default:
logger.error("IPC acknowledge packet type 0x{} was not handled", Integer.toHexString(pkt.ack));
break;
}
break;
}
case IPCPacket09RequestResponse.ID: {
IPCPacket09RequestResponse pkt = (IPCPacket09RequestResponse)ipc;
if(statusState == IntegratedServerState.WORLD_EXPORTING) {
statusState = IntegratedServerState.WORLD_NONE;
exportResponse = pkt.response;
}else {
logger.error("IPCPacket09RequestResponse was recieved but statusState was '{}' instead of 'WORLD_EXPORTING'", IntegratedServerState.getStateName(statusState));
}
break;
}
case IPCPacket0DProgressUpdate.ID: {
IPCPacket0DProgressUpdate pkt = (IPCPacket0DProgressUpdate)ipc;
worldStatusString = pkt.updateMessage;
worldStatusProgress = pkt.updateProgress;
break;
}
case IPCPacket15Crashed.ID: {
exceptions.add((IPCPacket15Crashed)ipc);
if(exceptions.size() > 64) {
exceptions.remove(0);
}
break;
}
case IPCPacket16NBTList.ID: {
IPCPacket16NBTList pkt = (IPCPacket16NBTList)ipc;
if(pkt.opCode == IPCPacket16NBTList.WORLD_LIST && statusState == IntegratedServerState.WORLD_LISTING) {
statusState = IntegratedServerState.WORLD_NONE;
saveListNBT.clear();
saveListNBT.addAll(pkt.nbtTagList);
loadSaveComparators();
}else {
logger.error("IPC packet type 0x{} class '{}' contained invalid opCode {} in state {} '{}'", Integer.toHexString(ipc.id()), ipc.getClass().getSimpleName(), pkt.opCode, statusState, IntegratedServerState.getStateName(statusState));
}
break;
}
case IPCPacket0CPlayerChannel.ID: {
IPCPacket0CPlayerChannel pkt = (IPCPacket0CPlayerChannel)ipc;
if(!pkt.open) {
if(pkt.channel.equals(PLAYER_CHANNEL)) {
LANServerController.closeLAN();
localPlayerNetworkManager.isPlayerChannelOpen = false;
logger.error("Local player channel was closed");
}else {
PlatformWebRTC.serverLANDisconnectPeer(pkt.channel);
}
}
break;
}
case IPCPacket14StringList.ID: {
IPCPacket14StringList pkt = (IPCPacket14StringList)ipc;
if(pkt.opCode == IPCPacket14StringList.SERVER_TPS) {
integratedServerTPS.clear();
integratedServerTPS.addAll(pkt.stringList);
integratedServerLastTPSUpdate = System.currentTimeMillis();
}else {
logger.warn("Strange string list type {} recieved!", pkt.opCode);
}
break;
}
case IPCPacket20LoggerMessage.ID: {
IPCPacket20LoggerMessage pkt = (IPCPacket20LoggerMessage)ipc;
PlatformApplication.addLogMessage(pkt.logMessage, pkt.isError);
break;
}
default:
throw new RuntimeException("Unexpected IPC packet type recieved on client: " + ipc.id());
}
}
public static void sendIPCPacket(IPCPacketBase ipc) {
byte[] pkt;
try {
pkt = IPCPacketManager.IPCSerialize(ipc);
}catch (IOException ex) {
throw new RuntimeException("Failed to serialize IPC packet", ex);
}
ClientPlatformSingleplayer.sendPacket(new IPCPacketData(IPC_CHANNEL, pkt));
}
private static boolean callFailed = false;
public static boolean didLastCallFail() {
boolean c = callFailed;
callFailed = false;
return c;
}
public static void importWorld(String name, byte[] data, int format, byte gameRules) {
ensureReady();
statusState = IntegratedServerState.WORLD_IMPORTING;
sendIPCPacket(new IPCPacket07ImportWorld(name, data, (byte)format, gameRules));
}
public static void exportWorld(String name, int format) {
ensureReady();
statusState = IntegratedServerState.WORLD_EXPORTING;
if(format == IPCPacket05RequestData.REQUEST_LEVEL_EAG) {
name = name + (new String(new char[] { (char)253, (char)233, (char)233 })) + EaglerProfile.getName();
}
sendIPCPacket(new IPCPacket05RequestData(name, (byte)format));
}
private static byte[] exportResponse = null;
public static byte[] getExportResponse() {
byte[] dat = exportResponse;
exportResponse = null;
return dat;
}
public static String worldStatusString() {
return worldStatusString;
}
public static float worldStatusProgress() {
return worldStatusProgress;
}
public static IPCPacket15Crashed worldStatusError() {
return exceptions.size() > 0 ? exceptions.remove(0) : null;
}
public static IPCPacket15Crashed[] worldStatusErrors() {
int l = exceptions.size();
if(l == 0) {
return null;
}
IPCPacket15Crashed[] pkts = exceptions.toArray(new IPCPacket15Crashed[l]);
exceptions.clear();
return pkts;
}
public static void clearPlayerData(String worldName) {
ensureReady();
statusState = IntegratedServerState.WORLD_CLEAR_PLAYERS;
sendIPCPacket(new IPCPacket18ClearPlayers(worldName));
}
private static void loadSaveComparators() {
saveListMap.clear();
saveListCache.clear();
for(NBTTagCompound nbt : saveListNBT) {
String folderName = nbt.getString("folderNameEagler");
if(!StringUtils.isEmpty(folderName)) {
WorldInfo worldinfo = new WorldInfo(nbt.getCompoundTag("Data"));
saveListMap.put(folderName, worldinfo);
String s1 = worldinfo.getWorldName();
if (StringUtils.isEmpty(s1)) {
s1 = folderName;
}
long i = 0L;
saveListCache.add(new SaveFormatComparator(folderName, s1, worldinfo.getLastTimePlayed(), i,
worldinfo.getGameType(), false, worldinfo.isHardcoreModeEnabled(),
worldinfo.areCommandsAllowed(), nbt));
}
}
}
@Override
public String getName() {
return "eaglercraft";
}
@Override
public ISaveHandler getSaveLoader(String var1, boolean var2) {
return new SingleplayerSaveHandler(saveListMap.get(var1));
}
@Override
public List<SaveFormatComparator> getSaveList() {
return saveListCache;
}
@Override
public void flushCache() {
sendIPCPacket(new IPCPacket0EListWorlds());
statusState = IntegratedServerState.WORLD_LISTING;
}
@Override
public WorldInfo getWorldInfo(String var1) {
return saveListMap.get(var1);
}
@Override
public boolean func_154335_d(String var1) {
return false;
}
@Override
public boolean deleteWorldDirectory(String var1) {
sendIPCPacket(new IPCPacket03DeleteWorld(var1));
statusState = IntegratedServerState.WORLD_DELETING;
return false;
}
@Override
public void renameWorld(String var1, String var2) {
sendIPCPacket(new IPCPacket06RenameWorldNBT(var1, var2, false));
statusState = IntegratedServerState.WORLD_RENAMING;
}
public static void duplicateWorld(String var1, String var2) {
sendIPCPacket(new IPCPacket06RenameWorldNBT(var1, var2, true));
statusState = IntegratedServerState.WORLD_DUPLICATING;
}
@Override
public boolean func_154334_a(String var1) {
return false;
}
@Override
public boolean isOldMapFormat(String var1) {
return false;
}
@Override
public boolean convertMapFormat(String var1, IProgressUpdate var2) {
return false;
}
@Override
public boolean canLoadWorld(String var1) {
return saveListMap.containsKey(var1);
}
public static boolean canKillWorker() {
return ClientPlatformSingleplayer.canKillWorker();
}
public static void killWorker() {
statusState = IntegratedServerState.WORLD_WORKER_NOT_RUNNING;
ClientPlatformSingleplayer.killWorker();
LANServerController.closeLAN();
}
public static void updateLocale(List<String> dump) {
if(statusState != IntegratedServerState.WORLD_WORKER_NOT_RUNNING) {
sendIPCPacket(new IPCPacket14StringList(IPCPacket14StringList.LOCALE, dump));
}
}
public static void setDifficulty(int difficultyId) {
if(isWorldRunning()) {
sendIPCPacket(new IPCPacket0ASetWorldDifficulty((byte)difficultyId));
}
}
public static void configureLAN(net.minecraft.world.WorldSettings.GameType enumGameType, boolean allowCommands) {
sendIPCPacket(new IPCPacket17ConfigureLAN(enumGameType.getID(), allowCommands, LANServerController.currentICEServers));
}
}

View File

@ -0,0 +1,69 @@
package net.lax1dude.eaglercraft.v1_8.sp;
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
import net.lax1dude.eaglercraft.v1_8.internal.FileChooserResult;
import net.lax1dude.eaglercraft.v1_8.opengl.ImageData;
import net.lax1dude.eaglercraft.v1_8.profile.SkinPackets;
import net.minecraft.client.Minecraft;
import net.minecraft.network.play.client.C17PacketCustomPayload;
import net.minecraft.util.ChatComponentTranslation;
/**
* 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.
*
*/
public class SkullCommand {
private final Minecraft mc;
private boolean waitingForSelection = false;
public SkullCommand(Minecraft mc) {
this.mc = mc;
}
public void openFileChooser() {
EagRuntime.displayFileChooser("image/png", "png");
waitingForSelection = true;
}
public void tick() {
if(waitingForSelection && EagRuntime.fileChooserHasResult()) {
waitingForSelection = false;
FileChooserResult fr = EagRuntime.getFileChooserResult();
if(fr == null || mc.thePlayer == null || mc.thePlayer.sendQueue == null) {
return;
}
ImageData loaded = ImageData.loadImageFile(fr.fileData);
if(loaded == null) {
mc.ingameGUI.getChatGUI().printChatMessage(new ChatComponentTranslation("command.skull.error.invalid.png"));
return;
}
if(loaded.width != 64 || loaded.height > 64) {
mc.ingameGUI.getChatGUI().printChatMessage(new ChatComponentTranslation("command.skull.error.invalid.skin", loaded.width, loaded.height));
return;
}
byte[] rawSkin = new byte[loaded.pixels.length << 2];
for(int i = 0, j, k; i < 4096; ++i) {
j = i << 2;
k = loaded.pixels[i];
rawSkin[j] = (byte)(k >> 24);
rawSkin[j + 1] = (byte)(k >> 16);
rawSkin[j + 2] = (byte)(k >> 8);
rawSkin[j + 3] = (byte)(k & 0xFF);
}
mc.thePlayer.sendQueue.addToSendQueue(new C17PacketCustomPayload("EAG|Skins-1.8", SkinPackets.writeCreateCustomSkull(rawSkin)));
}
}
}

View File

@ -0,0 +1,24 @@
package net.lax1dude.eaglercraft.v1_8.sp;
/**
* Copyright (c) 2023-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.
*
*/
public class WorkerStartupFailedException extends RuntimeException {
public WorkerStartupFailedException(String msg) {
super(msg);
}
}

View File

@ -0,0 +1,30 @@
package net.lax1dude.eaglercraft.v1_8.sp.gui;
import net.lax1dude.eaglercraft.v1_8.sp.internal.ClientPlatformSingleplayer;
/**
* Copyright (c) 2023-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.
*
*/
public class CrashScreen {
public static void showCrashReportOverlay(String report, int x, int y, int w, int h) {
ClientPlatformSingleplayer.showCrashReportOverlay(report, x, y, w, h);
}
public static void hideCrashReportOverlay() {
ClientPlatformSingleplayer.hideCrashReportOverlay();
}
}

View File

@ -0,0 +1,58 @@
package net.lax1dude.eaglercraft.v1_8.sp.gui;
import net.lax1dude.eaglercraft.v1_8.sp.SingleplayerServerController;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.GuiSelectWorld;
import net.minecraft.client.resources.I18n;
/**
* Copyright (c) 2023-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.
*
*/
public class GuiIntegratedServerStartup extends GuiScreen {
private final GuiScreen backScreen;
private static final String[] dotDotDot = new String[] { "", ".", "..", "..." };
private int counter = 0;
public GuiIntegratedServerStartup(GuiScreen backScreen) {
this.backScreen = backScreen;
}
protected void keyTyped(char parChar1, int parInt1) {
}
public void initGui() {
this.buttonList.clear();
}
public void updateScreen() {
++counter;
if(counter > 1 && SingleplayerServerController.isIntegratedServerWorkerStarted()) {
mc.displayGuiScreen(new GuiSelectWorld(backScreen));
}else if(counter == 2) {
SingleplayerServerController.startIntegratedServerWorker();
}
}
public void drawScreen(int i, int j, float f) {
this.drawBackground(0);
String txt = I18n.format("singleplayer.integratedStartup");
int w = this.fontRendererObj.getStringWidth(txt);
this.drawString(this.fontRendererObj, txt + dotDotDot[(int)((System.currentTimeMillis() / 300L) % 4L)], (this.width - w) / 2, this.height / 2 - 50, 16777215);
super.drawScreen(i, j, f);
}
}

View File

@ -0,0 +1,70 @@
package net.lax1dude.eaglercraft.v1_8.sp.gui;
import net.lax1dude.eaglercraft.v1_8.Mouse;
import net.lax1dude.eaglercraft.v1_8.internal.EnumCursorType;
import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
import net.lax1dude.eaglercraft.v1_8.sp.lan.LANServerController;
import net.minecraft.client.Minecraft;
import net.minecraft.client.audio.PositionedSoundRecord;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.resources.I18n;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.ResourceLocation;
/**
* Copyright (c) 2022-2024 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
* 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.
*
*/
public class GuiNetworkSettingsButton extends Gui {
private final GuiScreen screen;
private final String text;
private final Minecraft mc;
public GuiNetworkSettingsButton(GuiScreen screen) {
this.screen = screen;
this.text = I18n.format("directConnect.lanWorldRelay");
this.mc = Minecraft.getMinecraft();
}
public void drawScreen(int xx, int yy) {
GlStateManager.pushMatrix();
GlStateManager.scale(0.75f, 0.75f, 0.75f);
GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f);
int w = mc.fontRendererObj.getStringWidth(text);
boolean hover = xx > 1 && yy > 1 && xx < (w * 3 / 4) + 7 && yy < 12;
if(hover) {
Mouse.showCursor(EnumCursorType.HAND);
}
drawString(mc.fontRendererObj, EnumChatFormatting.UNDERLINE + text, 5, 5, hover ? 0xFFEEEE22 : 0xFFCCCCCC);
GlStateManager.popMatrix();
}
public void mouseClicked(int xx, int yy, int btn) {
int w = mc.fontRendererObj.getStringWidth(text);
if(xx > 2 && yy > 2 && xx < (w * 3 / 4) + 5 && yy < 12) {
if(LANServerController.supported()) {
mc.displayGuiScreen(GuiScreenLANInfo.showLANInfoScreen(new GuiScreenRelay(screen)));
}else {
mc.displayGuiScreen(new GuiScreenLANNotSupported(screen));
}
this.mc.getSoundHandler().playSound(PositionedSoundRecord.create(new ResourceLocation("gui.button.press"), 1.0F));
}
}
}

View File

@ -0,0 +1,143 @@
package net.lax1dude.eaglercraft.v1_8.sp.gui;
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
import net.lax1dude.eaglercraft.v1_8.Keyboard;
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayManager;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.GuiTextField;
import net.minecraft.client.resources.I18n;
/**
* Copyright (c) 2022-2024 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
* 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.
*
*/
public class GuiScreenAddRelay extends GuiScreen {
/** This GUI's parent GUI. */
private GuiScreenRelay parentGui;
private GuiTextField serverAddress;
private GuiTextField serverName;
public GuiScreenAddRelay(GuiScreenRelay par1GuiScreen) {
this.parentGui = par1GuiScreen;
}
/**
* Called from the main game loop to update the screen.
*/
public void updateScreen() {
this.serverName.updateCursorCounter();
this.serverAddress.updateCursorCounter();
}
/**
* Adds the buttons (and other controls) to the screen in question.
*/
public void initGui() {
Keyboard.enableRepeatEvents(true);
this.buttonList.clear();
this.parentGui.addNewName = RelayManager.relayManager.makeNewRelayName();
this.parentGui.addNewAddr = "";
this.parentGui.addNewPrimary = RelayManager.relayManager.count() == 0;
int sslOff = EagRuntime.requireSSL() ? 36 : 0;
this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 4 + 96 + 12 + sslOff, I18n.format("addRelay.add")));
this.buttonList.add(new GuiButton(1, this.width / 2 - 100, this.height / 4 + 120 + 12 + sslOff, I18n.format("gui.cancel")));
this.buttonList.add(new GuiButton(2, this.width / 2 - 100, 142, I18n.format("addRelay.primary") + ": " + (this.parentGui.addNewPrimary ? I18n.format("gui.yes") : I18n.format("gui.no"))));
this.serverName = new GuiTextField(3, this.fontRendererObj, this.width / 2 - 100, 106, 200, 20);
this.serverAddress = new GuiTextField(4, this.fontRendererObj, this.width / 2 - 100, 66, 200, 20);
this.serverAddress.setMaxStringLength(128);
this.serverAddress.setFocused(true);
((GuiButton) this.buttonList.get(0)).enabled = this.serverAddress.getText().length() > 0 && this.serverAddress.getText().split(":").length > 0 && this.serverName.getText().length() > 0;
this.serverName.setText(this.parentGui.addNewName);
}
/**
* Called when the screen is unloaded. Used to disable keyboard repeat events
*/
public void onGuiClosed() {
Keyboard.enableRepeatEvents(false);
}
/**
* Fired when a control is clicked. This is the equivalent of
* ActionListener.actionPerformed(ActionEvent e).
*/
protected void actionPerformed(GuiButton par1GuiButton) {
if (par1GuiButton.enabled) {
if (par1GuiButton.id == 1) {
this.parentGui.confirmClicked(false, 0);
} else if (par1GuiButton.id == 0) {
this.parentGui.addNewName = this.serverName.getText();
this.parentGui.addNewAddr = this.serverAddress.getText();
this.parentGui.confirmClicked(true, 0);
} else if (par1GuiButton.id == 2) {
this.parentGui.addNewPrimary = !this.parentGui.addNewPrimary;
((GuiButton) this.buttonList.get(2)).displayString = I18n.format("addRelay.primary") + ": " + (this.parentGui.addNewPrimary ? I18n.format("gui.yes") : I18n.format("gui.no"));
}
}
}
/**
* Fired when a key is typed. This is the equivalent of
* KeyListener.keyTyped(KeyEvent e).
*/
protected void keyTyped(char par1, int par2) {
this.serverName.textboxKeyTyped(par1, par2);
this.serverAddress.textboxKeyTyped(par1, par2);
if (par1 == 9) {
if (this.serverName.isFocused()) {
this.serverName.setFocused(false);
this.serverAddress.setFocused(true);
} else {
this.serverName.setFocused(true);
this.serverAddress.setFocused(false);
}
}
if (par1 == 13) {
this.actionPerformed((GuiButton) this.buttonList.get(0));
}
((GuiButton) this.buttonList.get(0)).enabled = this.serverAddress.getText().length() > 0 && this.serverAddress.getText().split(":").length > 0 && this.serverName.getText().length() > 0;
}
/**
* Called when the mouse is clicked.
*/
protected void mouseClicked(int par1, int par2, int par3) {
super.mouseClicked(par1, par2, par3);
this.serverAddress.mouseClicked(par1, par2, par3);
this.serverName.mouseClicked(par1, par2, par3);
}
/**
* Draws the screen and all the components in it.
*/
public void drawScreen(int par1, int par2, float par3) {
this.drawBackground(0);
this.drawCenteredString(this.fontRendererObj, I18n.format("addRelay.title"), this.width / 2, 17, 16777215);
this.drawString(this.fontRendererObj, I18n.format("addRelay.address"), this.width / 2 - 100, 53, 10526880);
this.drawString(this.fontRendererObj, I18n.format("addRelay.name"), this.width / 2 - 100, 94, 10526880);
if(EagRuntime.requireSSL()) {
this.drawCenteredString(this.fontRendererObj, I18n.format("addServer.SSLWarn1"), this.width / 2, 169, 0xccccff);
this.drawCenteredString(this.fontRendererObj, I18n.format("addServer.SSLWarn2"), this.width / 2, 181, 0xccccff);
}
this.serverName.drawTextBox();
this.serverAddress.drawTextBox();
super.drawScreen(par1, par2, par3);
}
}

View File

@ -0,0 +1,127 @@
package net.lax1dude.eaglercraft.v1_8.sp.gui;
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
import net.lax1dude.eaglercraft.v1_8.profile.EaglerProfile;
import net.lax1dude.eaglercraft.v1_8.sp.SingleplayerServerController;
import net.lax1dude.eaglercraft.v1_8.sp.ipc.IPCPacket05RequestData;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiCreateWorld;
import net.minecraft.client.gui.GuiRenameWorld;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.GuiYesNo;
import net.minecraft.client.resources.I18n;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.storage.WorldInfo;
/**
* Copyright (c) 2022-2024 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
* 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.
*
*/
public class GuiScreenBackupWorldSelection extends GuiScreen {
private GuiScreen selectWorld;
private GuiButton worldRecreate = null;
private GuiButton worldDuplicate = null;
private GuiButton worldExport = null;
private GuiButton worldConvert = null;
private GuiButton worldBackup = null;
private long worldSeed;
private NBTTagCompound levelDat;
private String worldName;
public GuiScreenBackupWorldSelection(GuiScreen selectWorld, String worldName, NBTTagCompound levelDat) {
this.selectWorld = selectWorld;
this.worldName = worldName;
this.levelDat = levelDat;
this.worldSeed = levelDat.getCompoundTag("Data").getLong("RandomSeed");
}
public void initGui() {
this.buttonList.add(worldRecreate = new GuiButton(1, this.width / 2 - 100, this.height / 5 + 5, I18n.format("singleplayer.backup.recreate")));
this.buttonList.add(worldDuplicate = new GuiButton(2, this.width / 2 - 100, this.height / 5 + 30, I18n.format("singleplayer.backup.duplicate")));
this.buttonList.add(worldExport = new GuiButton(3, this.width / 2 - 100, this.height / 5 + 80, I18n.format("singleplayer.backup.export")));
this.buttonList.add(worldConvert = new GuiButton(4, this.width / 2 - 100, this.height / 5 + 105, I18n.format("singleplayer.backup.vanilla")));
this.buttonList.add(worldBackup = new GuiButton(5, this.width / 2 - 100, this.height / 5 + 136, I18n.format("singleplayer.backup.clearPlayerData")));
this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 4 + 155, I18n.format("gui.cancel")));
}
public void drawScreen(int par1, int par2, float par3) {
this.drawDefaultBackground();
this.drawCenteredString(this.fontRendererObj, I18n.format("singleplayer.backup.title", worldName), this.width / 2, this.height / 5 - 35, 16777215);
this.drawCenteredString(this.fontRendererObj, I18n.format("singleplayer.backup.seed") + " " + worldSeed, this.width / 2, this.height / 5 + 62, 0xAAAAFF);
int toolTipColor = 0xDDDDAA;
if(worldRecreate.isMouseOver()) {
this.drawCenteredString(this.fontRendererObj, I18n.format("singleplayer.backup.recreate.tooltip"), this.width / 2, this.height / 5 - 12, toolTipColor);
}else if(worldDuplicate.isMouseOver()) {
this.drawCenteredString(this.fontRendererObj, I18n.format("singleplayer.backup.duplicate.tooltip"), this.width / 2, this.height / 5 - 12, toolTipColor);
}else if(worldExport.isMouseOver()) {
this.drawCenteredString(this.fontRendererObj, I18n.format("singleplayer.backup.export.tooltip"), this.width / 2, this.height / 5 - 12, toolTipColor);
}else if(worldConvert.isMouseOver()) {
this.drawCenteredString(this.fontRendererObj, I18n.format("singleplayer.backup.vanilla.tooltip"), this.width / 2, this.height / 5 - 12, toolTipColor);
}else if(worldBackup.isMouseOver()) {
this.drawCenteredString(this.fontRendererObj, I18n.format("singleplayer.backup.clearPlayerData.tooltip"), this.width / 2, this.height / 5 - 12, toolTipColor);
}
super.drawScreen(par1, par2, par3);
}
protected void actionPerformed(GuiButton par1GuiButton) {
if(par1GuiButton.id == 0) {
this.mc.displayGuiScreen(selectWorld);
}else if(par1GuiButton.id == 1) {
GuiCreateWorld cw = new GuiCreateWorld(selectWorld);
cw.func_146318_a(new WorldInfo(this.levelDat.getCompoundTag("Data")));
this.mc.displayGuiScreen(cw);
}else if(par1GuiButton.id == 2) {
this.mc.displayGuiScreen(new GuiRenameWorld(this.selectWorld, this.worldName, true));
}else if(par1GuiButton.id == 3) {
SingleplayerServerController.exportWorld(worldName, IPCPacket05RequestData.REQUEST_LEVEL_EAG);
this.mc.displayGuiScreen(new GuiScreenIntegratedServerBusy(selectWorld, "singleplayer.busy.exporting.1", "singleplayer.failed.exporting.1", () -> {
byte[] b = SingleplayerServerController.getExportResponse();
if(b != null) {
EagRuntime.downloadFileWithName(worldName + ".epk", b);
return true;
}
return false;
}));
}else if(par1GuiButton.id == 4) {
SingleplayerServerController.exportWorld(worldName, IPCPacket05RequestData.REQUEST_LEVEL_MCA);
this.mc.displayGuiScreen(new GuiScreenIntegratedServerBusy(selectWorld, "singleplayer.busy.exporting.2", "singleplayer.failed.exporting.2", () -> {
byte[] b = SingleplayerServerController.getExportResponse();
if(b != null) {
EagRuntime.downloadFileWithName(worldName + ".zip", b);
return true;
}
return false;
}));
}else if(par1GuiButton.id == 5) {
this.mc.displayGuiScreen(new GuiYesNo(this, I18n.format("singleplayer.backup.clearPlayerData.warning1"),
I18n.format("singleplayer.backup.clearPlayerData.warning2", worldName, EaglerProfile.getName()), 0));
}
}
public void confirmClicked(boolean par1, int par2) {
if(par1) {
SingleplayerServerController.clearPlayerData(worldName);
this.mc.displayGuiScreen(new GuiScreenIntegratedServerBusy(this, "singleplayer.busy.clearplayers", "singleplayer.failed.clearplayers", () -> SingleplayerServerController.isReady()));
}else {
mc.displayGuiScreen(this);
}
}
}

View File

@ -0,0 +1,84 @@
package net.lax1dude.eaglercraft.v1_8.sp.gui;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.resources.I18n;
/**
* Copyright (c) 2022-2024 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
* 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.
*
*/
public class GuiScreenChangeRelayTimeout extends GuiScreen {
private GuiScreen parent;
private GuiSlider2 slider;
private String title;
public GuiScreenChangeRelayTimeout(GuiScreen parent) {
this.parent = parent;
}
public void initGui() {
title = I18n.format("networkSettings.relayTimeoutTitle");
buttonList.clear();
buttonList.add(new GuiButton(0, width / 2 - 100, height / 3 + 55, I18n.format("gui.done")));
buttonList.add(new GuiButton(1, width / 2 - 100, height / 3 + 85, I18n.format("gui.cancel")));
slider = new GuiSlider2(0, width / 2 - 100, height / 3 + 10, 200, 20, (mc.gameSettings.relayTimeout - 1) / 14.0f, 1.0f) {
public boolean mousePressed(Minecraft par1Minecraft, int par2, int par3) {
if(super.mousePressed(par1Minecraft, par2, par3)) {
this.displayString = "" + (int)((sliderValue * 14.0f) + 1.0f) + "s";
return true;
}else {
return false;
}
}
public void mouseDragged(Minecraft par1Minecraft, int par2, int par3) {
super.mouseDragged(par1Minecraft, par2, par3);
this.displayString = "" + (int)((sliderValue * 14.0f) + 1.0f) + "s";
}
};
slider.displayString = "" + mc.gameSettings.relayTimeout + "s";
}
public void actionPerformed(GuiButton btn) {
if(btn.id == 0) {
mc.gameSettings.relayTimeout = (int)((slider.sliderValue * 14.0f) + 1.0f);
mc.gameSettings.saveOptions();
mc.displayGuiScreen(parent);
}else if(btn.id == 1) {
mc.displayGuiScreen(parent);
}
}
public void drawScreen(int par1, int par2, float par3) {
drawBackground(0);
drawCenteredString(fontRendererObj, title, width / 2, height / 3 - 20, 0xFFFFFF);
slider.drawButton(mc, par1, par2);
super.drawScreen(par1, par2, par3);
}
public void mouseClicked(int mx, int my, int button) {
slider.mousePressed(mc, mx, my);
super.mouseClicked(mx, my, button);
}
public void mouseReleased(int par1, int par2, int par3) {
if(par3 == 0) {
slider.mouseReleased(par1, par2);
}
super.mouseReleased(par1, par2, par3);
}
}

View File

@ -0,0 +1,74 @@
package net.lax1dude.eaglercraft.v1_8.sp.gui;
import net.lax1dude.eaglercraft.v1_8.sp.lan.LANServerController;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiMultiplayer;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.GuiScreenServerList;
import net.minecraft.client.resources.I18n;
/**
* Copyright (c) 2022-2024 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
* 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.
*
*/
public class GuiScreenConnectOption extends GuiScreen {
private final GuiMultiplayer guiScreen;
private String title;
private String prompt;
private final GuiNetworkSettingsButton relaysButton;
public GuiScreenConnectOption(GuiMultiplayer guiScreen) {
this.guiScreen = guiScreen;
this.relaysButton = new GuiNetworkSettingsButton(this);
}
public void initGui() {
title = I18n.format("selectServer.direct");
prompt = I18n.format("directConnect.prompt");
buttonList.clear();
buttonList.add(new GuiButton(1, this.width / 2 - 100, this.height / 4 - 60 + 90, I18n.format("directConnect.serverJoin")));
buttonList.add(new GuiButton(2, this.width / 2 - 100, this.height / 4 - 60 + 115, I18n.format("directConnect.lanWorld")));
buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 4 - 60 + 155, I18n.format("gui.cancel")));
}
protected void actionPerformed(GuiButton par1GuiButton) {
if(par1GuiButton.id == 0) {
mc.displayGuiScreen(guiScreen);
}else if(par1GuiButton.id == 1) {
mc.displayGuiScreen(new GuiScreenServerList(guiScreen, guiScreen.getSelectedServer()));
}else if(par1GuiButton.id == 2) {
if(LANServerController.supported()) {
mc.displayGuiScreen(GuiScreenLANInfo.showLANInfoScreen(new GuiScreenLANConnect(guiScreen)));
}else {
mc.displayGuiScreen(new GuiScreenLANNotSupported(this));
}
}
}
public void drawScreen(int par1, int par2, float par3) {
this.drawDefaultBackground();
this.drawCenteredString(this.fontRendererObj, title, this.width / 2, this.height / 4 - 60 + 20, 16777215);
this.drawCenteredString(this.fontRendererObj, prompt, this.width / 2, this.height / 4 - 60 + 55, 0x999999);
super.drawScreen(par1, par2, par3);
relaysButton.drawScreen(par1, par2);
}
protected void mouseClicked(int par1, int par2, int par3) {
relaysButton.mouseClicked(par1, par2, par3);
super.mouseClicked(par1, par2, par3);
}
}

View File

@ -0,0 +1,86 @@
package net.lax1dude.eaglercraft.v1_8.sp.gui;
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
import net.lax1dude.eaglercraft.v1_8.internal.FileChooserResult;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiCreateWorld;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.resources.I18n;
/**
* 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.
*
*/
public class GuiScreenCreateWorldSelection extends GuiScreen {
private GuiScreen mainmenu;
private GuiButton worldCreate = null;
private GuiButton worldImport = null;
private GuiButton worldVanilla = null;
private boolean isImportingEPK = false;
private boolean isImportingMCA = false;
public GuiScreenCreateWorldSelection(GuiScreen mainmenu) {
this.mainmenu = mainmenu;
}
public void initGui() {
this.buttonList.add(worldCreate = new GuiButton(1, this.width / 2 - 100, this.height / 4 + 40, I18n.format("singleplayer.create.create")));
this.buttonList.add(worldImport = new GuiButton(2, this.width / 2 - 100, this.height / 4 + 65, I18n.format("singleplayer.create.import")));
this.buttonList.add(worldVanilla = new GuiButton(3, this.width / 2 - 100, this.height / 4 + 90, I18n.format("singleplayer.create.vanilla")));
this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 4 + 130, I18n.format("gui.cancel")));
}
public void updateScreen() {
if(EagRuntime.fileChooserHasResult() && (isImportingEPK || isImportingMCA)) {
FileChooserResult fr = EagRuntime.getFileChooserResult();
if(fr != null) {
this.mc.displayGuiScreen(new GuiScreenNameWorldImport(mainmenu, fr, isImportingEPK ? 0 : (isImportingMCA ? 1 : -1)));
}
isImportingEPK = isImportingMCA = false;
}
}
public void drawScreen(int par1, int par2, float par3) {
this.drawDefaultBackground();
this.drawCenteredString(this.fontRendererObj, I18n.format("singleplayer.create.title"), this.width / 2, this.height / 4, 16777215);
int toolTipColor = 0xDDDDAA;
if(worldCreate.isMouseOver()) {
this.drawCenteredString(this.fontRendererObj, I18n.format("singleplayer.create.create.tooltip"), this.width / 2, this.height / 4 + 20, toolTipColor);
}else if(worldImport.isMouseOver()) {
this.drawCenteredString(this.fontRendererObj, I18n.format("singleplayer.create.import.tooltip"), this.width / 2, this.height / 4 + 20, toolTipColor);
}else if(worldVanilla.isMouseOver()) {
this.drawCenteredString(this.fontRendererObj, I18n.format("singleplayer.create.vanilla.tooltip"), this.width / 2, this.height / 4 + 20, toolTipColor);
}
super.drawScreen(par1, par2, par3);
}
protected void actionPerformed(GuiButton par1GuiButton) {
if(par1GuiButton.id == 0) {
this.mc.displayGuiScreen(mainmenu);
}else if(par1GuiButton.id == 1) {
this.mc.displayGuiScreen(new GuiCreateWorld(mainmenu));
}else if(par1GuiButton.id == 2) {
isImportingEPK = true;
EagRuntime.displayFileChooser(null, "epk");
}else if(par1GuiButton.id == 3) {
isImportingMCA = true;
EagRuntime.displayFileChooser(null, "zip");
}
}
}

View File

@ -0,0 +1,38 @@
package net.lax1dude.eaglercraft.v1_8.sp.gui;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.resources.I18n;
/**
* Copyright (c) 2023-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.
*
*/
public class GuiScreenDemoIntegratedServerFailed extends GuiScreen {
private String str1;
private String str2;
public GuiScreenDemoIntegratedServerFailed() {
this.str1 = I18n.format("singleplayer.failed.demo.title");
this.str2 = I18n.format("singleplayer.failed.demo.desc");
}
public void drawScreen(int par1, int par2, float par3) {
this.drawDefaultBackground();
this.drawCenteredString(fontRendererObj, str1, this.width / 2, 70, 11184810);
this.drawCenteredString(fontRendererObj, str2, this.width / 2, 90, 16777215);
super.drawScreen(par1, par2, par3);
}
}

View File

@ -0,0 +1,69 @@
package net.lax1dude.eaglercraft.v1_8.sp.gui;
import net.lax1dude.eaglercraft.v1_8.sp.SingleplayerServerController;
import net.lax1dude.eaglercraft.v1_8.sp.WorkerStartupFailedException;
import net.lax1dude.eaglercraft.v1_8.sp.ipc.IPCPacket15Crashed;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.resources.I18n;
/**
* Copyright (c) 2023-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.
*
*/
public class GuiScreenDemoIntegratedServerStartup extends GuiScreen {
private final GuiScreen contScreen;
private static final String[] dotDotDot = new String[] { "", ".", "..", "..." };
private int counter = 0;
public GuiScreenDemoIntegratedServerStartup(GuiScreen contScreen) {
this.contScreen = contScreen;
}
protected void keyTyped(char parChar1, int parInt1) {
}
public void initGui() {
this.buttonList.clear();
}
public void updateScreen() {
++counter;
if(counter == 2) {
try {
SingleplayerServerController.startIntegratedServerWorker();
}catch(WorkerStartupFailedException ex) {
mc.displayGuiScreen(new GuiScreenIntegratedServerFailed(ex.getMessage(), new GuiScreenDemoIntegratedServerFailed()));
return;
}
}else if(counter > 2) {
IPCPacket15Crashed[] crashReport = SingleplayerServerController.worldStatusErrors();
if(crashReport != null) {
mc.displayGuiScreen(GuiScreenIntegratedServerBusy.createException(new GuiScreenDemoIntegratedServerFailed(), "singleplayer.failed.notStarted", crashReport));
}else if(SingleplayerServerController.isIntegratedServerWorkerStarted()) {
mc.displayGuiScreen(contScreen);
}
}
}
public void drawScreen(int i, int j, float f) {
this.drawBackground(0);
String txt = I18n.format("singleplayer.integratedStartup");
int w = this.fontRendererObj.getStringWidth(txt);
this.drawString(this.fontRendererObj, txt + dotDotDot[(int)((System.currentTimeMillis() / 300L) % 4L)], (this.width - w) / 2, this.height / 2 - 50, 16777215);
super.drawScreen(i, j, f);
}
}

View File

@ -0,0 +1,72 @@
package net.lax1dude.eaglercraft.v1_8.sp.gui;
import net.lax1dude.eaglercraft.v1_8.sp.lan.LANServerController;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiCreateWorld;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.resources.I18n;
import net.minecraft.world.demo.DemoWorldServer;
/**
* 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.
*
*/
public class GuiScreenDemoPlayWorldSelection extends GuiScreen {
private GuiScreen mainmenu;
private GuiButton playWorld = null;
private GuiButton joinWorld = null;
public GuiScreenDemoPlayWorldSelection(GuiScreen mainmenu) {
this.mainmenu = mainmenu;
}
public void initGui() {
this.buttonList.add(playWorld = new GuiButton(1, this.width / 2 - 100, this.height / 4 + 40, I18n.format("singleplayer.demo.create.create")));
this.buttonList.add(joinWorld = new GuiButton(2, this.width / 2 - 100, this.height / 4 + 65, I18n.format("singleplayer.demo.create.join")));
this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 4 + 130, I18n.format("gui.cancel")));
}
public void drawScreen(int par1, int par2, float par3) {
this.drawDefaultBackground();
this.drawCenteredString(this.fontRendererObj, I18n.format("singleplayer.demo.create.title"), this.width / 2, this.height / 4, 16777215);
int toolTipColor = 0xDDDDAA;
if(playWorld.isMouseOver()) {
this.drawCenteredString(this.fontRendererObj, I18n.format("singleplayer.demo.create.create.tooltip"), this.width / 2, this.height / 4 + 20, toolTipColor);
}else if(joinWorld.isMouseOver()) {
this.drawCenteredString(this.fontRendererObj, I18n.format("singleplayer.demo.create.join.tooltip"), this.width / 2, this.height / 4 + 20, toolTipColor);
}
super.drawScreen(par1, par2, par3);
}
protected void actionPerformed(GuiButton par1GuiButton) {
if(par1GuiButton.id == 0) {
this.mc.displayGuiScreen(mainmenu);
}else if(par1GuiButton.id == 1) {
this.mc.gameSettings.hasCreatedDemoWorld = true;
this.mc.gameSettings.saveOptions();
this.mc.launchIntegratedServer("Demo World", "Demo World", DemoWorldServer.demoWorldSettings);
}else if(par1GuiButton.id == 2) {
if(LANServerController.supported()) {
this.mc.displayGuiScreen(GuiScreenLANInfo.showLANInfoScreen(new GuiScreenLANConnect(mainmenu)));
}else {
this.mc.displayGuiScreen(new GuiScreenLANNotSupported(mainmenu));
}
}
}
}

View File

@ -0,0 +1,167 @@
package net.lax1dude.eaglercraft.v1_8.sp.gui;
import java.util.function.BiConsumer;
import java.util.function.BooleanSupplier;
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
import net.lax1dude.eaglercraft.v1_8.sp.SingleplayerServerController;
import net.lax1dude.eaglercraft.v1_8.sp.ipc.IPCPacket15Crashed;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiMainMenu;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.resources.I18n;
/**
* 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.
*
*/
public class GuiScreenIntegratedServerBusy extends GuiScreen {
public final GuiScreen menu;
private GuiButton killTask;
public final String failMessage;
private BooleanSupplier checkTaskComplete;
private Runnable taskKill;
private String lastStatus;
private String currentStatus;
private BiConsumer<GuiScreen, IPCPacket15Crashed[]> onException;
private int areYouSure;
private long startStartTime;
private static final Runnable defaultTerminateAction = () -> {
if(SingleplayerServerController.canKillWorker()) {
SingleplayerServerController.killWorker();
Minecraft.getMinecraft().displayGuiScreen(new GuiScreenIntegratedServerFailed("singleplayer.failed.killed", new GuiMainMenu()));
}else {
EagRuntime.showPopup("Cannot kill worker tasks on desktop runtime!");
}
};
public static GuiScreen createException(GuiScreen ok, String msg, IPCPacket15Crashed[] exceptions) {
ok = new GuiScreenIntegratedServerFailed(msg, ok);
if(exceptions != null) {
for(int i = exceptions.length - 1; i >= 0; --i) {
ok = new GuiScreenIntegratedServerCrashed(ok, exceptions[i].crashReport);
}
}
return ok;
}
private static final BiConsumer<GuiScreen, IPCPacket15Crashed[]> defaultExceptionAction = (t, u) -> {
GuiScreenIntegratedServerBusy tt = (GuiScreenIntegratedServerBusy) t;
Minecraft.getMinecraft().displayGuiScreen(createException(tt.menu, tt.failMessage, u));
};
public GuiScreenIntegratedServerBusy(GuiScreen menu, String progressMessage, String failMessage, BooleanSupplier checkTaskComplete) {
this(menu, progressMessage, failMessage, checkTaskComplete, defaultExceptionAction, defaultTerminateAction);
}
public GuiScreenIntegratedServerBusy(GuiScreen menu, String progressMessage, String failMessage, BooleanSupplier checkTaskComplete, BiConsumer<GuiScreen, IPCPacket15Crashed[]> exceptionAction) {
this(menu, progressMessage, failMessage, checkTaskComplete, exceptionAction, defaultTerminateAction);
}
public GuiScreenIntegratedServerBusy(GuiScreen menu, String progressMessage, String failMessage, BooleanSupplier checkTaskComplete, Runnable onTerminate) {
this(menu, progressMessage, failMessage, checkTaskComplete, defaultExceptionAction, onTerminate);
}
public GuiScreenIntegratedServerBusy(GuiScreen menu, String progressMessage, String failMessage, BooleanSupplier checkTaskComplete, BiConsumer<GuiScreen, IPCPacket15Crashed[]> onException, Runnable onTerminate) {
this.menu = menu;
this.failMessage = failMessage;
this.checkTaskComplete = checkTaskComplete;
this.onException = onException;
this.taskKill = onTerminate;
this.lastStatus = SingleplayerServerController.worldStatusString();
this.currentStatus = progressMessage;
}
public void initGui() {
if(startStartTime == 0) this.startStartTime = System.currentTimeMillis();
areYouSure = 0;
this.buttonList.add(killTask = new GuiButton(0, this.width / 2 - 100, this.height / 3 + 50, I18n.format("singleplayer.busy.killTask")));
killTask.enabled = false;
}
public boolean doesGuiPauseGame() {
return false;
}
public void drawScreen(int par1, int par2, float par3) {
this.drawDefaultBackground();
int top = this.height / 3;
long millis = System.currentTimeMillis();
String str = I18n.format(currentStatus);
long dots = (millis / 500l) % 4l;
this.drawString(fontRendererObj, str + (dots > 0 ? "." : "") + (dots > 1 ? "." : "") + (dots > 2 ? "." : ""), (this.width - this.fontRendererObj.getStringWidth(str)) / 2, top + 10, 0xFFFFFF);
if(areYouSure > 0) {
this.drawCenteredString(fontRendererObj, I18n.format("singleplayer.busy.cancelWarning"), this.width / 2, top + 25, 0xFF8888);
}else {
float prog = SingleplayerServerController.worldStatusProgress();
if(this.currentStatus.equals(this.lastStatus) && prog > 0.01f) {
this.drawCenteredString(fontRendererObj, (prog > 1.0f ? ("(" + (prog > 1000000.0f ? "" + (int)(prog / 1000000.0f) + "MB" :
(prog > 1000.0f ? "" + (int)(prog / 1000.0f) + "kB" : "" + (int)prog + "B")) + ")") : "" + (int)(prog * 100.0f) + "%"), this.width / 2, top + 25, 0xFFFFFF);
}else {
long elapsed = (millis - startStartTime) / 1000l;
if(elapsed > 3) {
this.drawCenteredString(fontRendererObj, "(" + elapsed + "s)", this.width / 2, top + 25, 0xFFFFFF);
}
}
}
super.drawScreen(par1, par2, par3);
}
public void updateScreen() {
long millis = System.currentTimeMillis();
if(millis - startStartTime > 6000l && SingleplayerServerController.canKillWorker()) {
killTask.enabled = true;
}
if(SingleplayerServerController.didLastCallFail() || !SingleplayerServerController.isIntegratedServerWorkerAlive()) {
onException.accept(this, SingleplayerServerController.worldStatusErrors());
return;
}
if(checkTaskComplete.getAsBoolean()) {
this.mc.displayGuiScreen(menu);
}
String str = SingleplayerServerController.worldStatusString();
if(!lastStatus.equals(str)) {
lastStatus = str;
currentStatus = str;
}
killTask.displayString = I18n.format(areYouSure > 0 ? "singleplayer.busy.confirmCancel" : "singleplayer.busy.killTask");
if(areYouSure > 0) {
--areYouSure;
}
}
protected void actionPerformed(GuiButton par1GuiButton) {
if(par1GuiButton.id == 0) {
if(areYouSure <= 0) {
areYouSure = 80;
}else if(areYouSure <= 65) {
taskKill.run();
}
}
}
public boolean shouldHangupIntegratedServer() {
return false;
}
}

View File

@ -0,0 +1,60 @@
package net.lax1dude.eaglercraft.v1_8.sp.gui;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.client.resources.I18n;
/**
* Copyright (c) 2023-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.
*
*/
public class GuiScreenIntegratedServerCrashed extends GuiScreen {
private GuiScreen mainmenu;
private String crashReport;
public GuiScreenIntegratedServerCrashed(GuiScreen mainmenu, String crashReport) {
this.mainmenu = mainmenu;
this.crashReport = crashReport;
}
public void initGui() {
this.buttonList.clear();
this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height - 50, I18n.format("singleplayer.crashed.continue")));
ScaledResolution res = new ScaledResolution(mc);
int i = res.getScaleFactor();
CrashScreen.showCrashReportOverlay(crashReport, 90 * i, 60 * i, (width - 180) * i, (height - 130) * i);
}
public void onGuiClosed() {
CrashScreen.hideCrashReportOverlay();
}
public void drawScreen(int par1, int par2, float par3) {
this.drawDefaultBackground();
this.drawCenteredString(fontRendererObj, I18n.format("singleplayer.crashed.title"), this.width / 2, 25, 0xFFAAAA);
this.drawCenteredString(fontRendererObj, I18n.format("singleplayer.crashed.checkConsole"), this.width / 2, 40, 0xBBBBBB);
super.drawScreen(par1, par2, par3);
}
protected void actionPerformed(GuiButton par1GuiButton) {
if(par1GuiButton.id == 0) {
this.mc.displayGuiScreen(mainmenu);
}
}
}

View File

@ -0,0 +1,57 @@
package net.lax1dude.eaglercraft.v1_8.sp.gui;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.resources.I18n;
/**
* Copyright (c) 2023-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.
*
*/
public class GuiScreenIntegratedServerFailed extends GuiScreen {
private String str1;
private String str2;
private GuiScreen cont;
public GuiScreenIntegratedServerFailed(String str1, String str2, GuiScreen cont) {
this.str1 = I18n.format(str1);
this.str2 = I18n.format(str2);
this.cont = cont;
}
public GuiScreenIntegratedServerFailed(String str2, GuiScreen cont) {
this.str1 = I18n.format("singleplayer.failed.title");
this.str2 = I18n.format(str2);
this.cont = cont;
}
public void initGui() {
this.buttonList.clear();
this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 6 + 96, I18n.format("singleplayer.crashed.continue")));
}
public void drawScreen(int par1, int par2, float par3) {
this.drawDefaultBackground();
this.drawCenteredString(fontRendererObj, str1, this.width / 2, 70, 11184810);
this.drawCenteredString(fontRendererObj, str2, this.width / 2, 90, 16777215);
super.drawScreen(par1, par2, par3);
}
protected void actionPerformed(GuiButton par1GuiButton) {
if(par1GuiButton.id == 0) {
this.mc.displayGuiScreen(cont);
}
}
}

View File

@ -0,0 +1,75 @@
package net.lax1dude.eaglercraft.v1_8.sp.gui;
import net.lax1dude.eaglercraft.v1_8.sp.SingleplayerServerController;
import net.lax1dude.eaglercraft.v1_8.sp.WorkerStartupFailedException;
import net.lax1dude.eaglercraft.v1_8.sp.ipc.IPCPacket15Crashed;
import net.minecraft.client.gui.GuiMainMenu;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.GuiSelectWorld;
import net.minecraft.client.resources.I18n;
/**
* Copyright (c) 2023-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.
*
*/
public class GuiScreenIntegratedServerStartup extends GuiScreen {
private final GuiScreen backScreen;
private static final String[] dotDotDot = new String[] { "", ".", "..", "..." };
private int counter = 0;
public GuiScreenIntegratedServerStartup(GuiScreen backScreen) {
this.backScreen = backScreen;
}
protected void keyTyped(char parChar1, int parInt1) {
}
public void initGui() {
this.buttonList.clear();
}
public void updateScreen() {
++counter;
if(counter == 2) {
try {
SingleplayerServerController.startIntegratedServerWorker();
}catch(WorkerStartupFailedException ex) {
mc.displayGuiScreen(new GuiScreenIntegratedServerFailed(ex.getMessage(), new GuiMainMenu()));
return;
}
}else if(counter > 2) {
IPCPacket15Crashed[] crashReport = SingleplayerServerController.worldStatusErrors();
if(crashReport != null) {
mc.displayGuiScreen(GuiScreenIntegratedServerBusy.createException(new GuiMainMenu(), "singleplayer.failed.notStarted", crashReport));
}else if(SingleplayerServerController.isIntegratedServerWorkerStarted()) {
GuiScreen cont = new GuiSelectWorld(backScreen);
if(SingleplayerServerController.isRunningSingleThreadMode()) {
cont = new GuiScreenIntegratedServerFailed("singleplayer.failed.singleThreadWarning.1", "singleplayer.failed.singleThreadWarning.2", cont);
}
mc.displayGuiScreen(cont);
}
}
}
public void drawScreen(int i, int j, float f) {
this.drawBackground(0);
String txt = I18n.format("singleplayer.integratedStartup");
int w = this.fontRendererObj.getStringWidth(txt);
this.drawString(this.fontRendererObj, txt + dotDotDot[(int)((System.currentTimeMillis() / 300L) % 4L)], (this.width - w) / 2, this.height / 2 - 50, 16777215);
super.drawScreen(i, j, f);
}
}

View File

@ -0,0 +1,91 @@
package net.lax1dude.eaglercraft.v1_8.sp.gui;
import net.lax1dude.eaglercraft.v1_8.Keyboard;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.GuiTextField;
import net.minecraft.client.resources.I18n;
/**
* Copyright (c) 2022-2024 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
* 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.
*
*/
public class GuiScreenLANConnect extends GuiScreen {
private final GuiScreen parent;
private GuiTextField codeTextField;
private final GuiNetworkSettingsButton relaysButton;
private static String lastCode = "";
public GuiScreenLANConnect(GuiScreen parent) {
this.parent = parent;
this.relaysButton = new GuiNetworkSettingsButton(this);
}
public void initGui() {
Keyboard.enableRepeatEvents(true);
this.buttonList.clear();
this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 4 + 96 + 12, I18n.format("directConnect.lanWorldJoin")));
this.buttonList.add(new GuiButton(1, this.width / 2 - 100, this.height / 4 + 120 + 12, I18n.format("gui.cancel")));
this.codeTextField = new GuiTextField(2, this.fontRendererObj, this.width / 2 - 100, this.height / 4 + 27, 200, 20);
this.codeTextField.setMaxStringLength(48);
this.codeTextField.setFocused(true);
this.codeTextField.setText(lastCode);
this.buttonList.get(0).enabled = this.codeTextField.getText().trim().length() > 0;
}
public void onGuiClosed() {
Keyboard.enableRepeatEvents(false);
lastCode = this.codeTextField.getText().trim();
}
protected void keyTyped(char par1, int par2) {
if (this.codeTextField.textboxKeyTyped(par1, par2)) {
((GuiButton) this.buttonList.get(0)).enabled = this.codeTextField.getText().trim().length() > 0;
} else if (par2 == 28) {
this.actionPerformed(this.buttonList.get(0));
}
}
public void updateScreen() {
this.codeTextField.updateCursorCounter();
}
protected void mouseClicked(int par1, int par2, int par3) {
super.mouseClicked(par1, par2, par3);
this.codeTextField.mouseClicked(par1, par2, par3);
this.relaysButton.mouseClicked(par1, par2, par3);
}
public void drawScreen(int xx, int yy, float pt) {
this.drawDefaultBackground();
this.drawCenteredString(this.fontRendererObj, I18n.format("selectServer.direct"), this.width / 2, this.height / 4 - 60 + 20, 16777215);
this.drawString(this.fontRendererObj, I18n.format("directConnect.lanWorldCode"), this.width / 2 - 100, this.height / 4 + 12, 10526880);
this.drawCenteredString(this.fontRendererObj, I18n.format("directConnect.networkSettingsNote"), this.width / 2, this.height / 4 + 63, 10526880);
this.drawCenteredString(this.fontRendererObj, I18n.format("directConnect.ipGrabNote"), this.width / 2, this.height / 4 + 77, 10526880);
this.codeTextField.drawTextBox();
super.drawScreen(xx, yy, pt);
this.relaysButton.drawScreen(xx, yy);
}
protected void actionPerformed(GuiButton par1GuiButton) {
if(par1GuiButton.id == 1) {
mc.displayGuiScreen(parent);
}else if(par1GuiButton.id == 0) {
mc.displayGuiScreen(new GuiScreenLANConnecting(parent, this.codeTextField.getText().trim()));
}
}
}

View File

@ -0,0 +1,125 @@
package net.lax1dude.eaglercraft.v1_8.sp.gui;
import net.lax1dude.eaglercraft.v1_8.internal.PlatformWebRTC;
import net.lax1dude.eaglercraft.v1_8.profile.EaglerProfile;
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;
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayServerSocket;
import net.lax1dude.eaglercraft.v1_8.sp.socket.NetHandlerSingleplayerLogin;
import net.minecraft.client.LoadingScreenRenderer;
import net.minecraft.client.gui.GuiDisconnected;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.resources.I18n;
import net.minecraft.network.EnumConnectionState;
import net.minecraft.network.login.client.C00PacketLoginStart;
import net.minecraft.util.ChatComponentText;
import java.io.IOException;
/**
* Copyright (c) 2022-2024 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
* 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.
*
*/
public class GuiScreenLANConnecting extends GuiScreen {
private final GuiScreen parent;
private final String code;
private final RelayServer relay;
private boolean completed = false;
private LANClientNetworkManager networkManager = null;
private int renderCount = 0;
public GuiScreenLANConnecting(GuiScreen parent, String code) {
this.parent = parent;
this.code = code;
this.relay = null;
}
public GuiScreenLANConnecting(GuiScreen parent, String code, RelayServer relay) {
this.parent = parent;
this.code = code;
this.relay = relay;
}
public boolean doesGuiPauseGame() {
return false;
}
public void updateScreen() {
if(networkManager != null) {
if (networkManager.isChannelOpen()) {
try {
networkManager.processReceivedPackets();
} catch (IOException ex) {
}
} else {
if (networkManager.checkDisconnected()) {
this.mc.getSession().reset();
if (mc.currentScreen == this) {
mc.loadWorld(null);
mc.displayGuiScreen(new GuiDisconnected(parent, "connect.failed", new ChatComponentText("LAN Connection Refused")));
}
}
}
}
}
public void drawScreen(int par1, int par2, float par3) {
this.drawDefaultBackground();
if(completed) {
String message = I18n.format("connect.authorizing");
this.drawString(fontRendererObj, message, (this.width - this.fontRendererObj.getStringWidth(message)) / 2, this.height / 3 + 10, 0xFFFFFF);
}else {
LoadingScreenRenderer ls = mc.loadingScreen;
String message = I18n.format("lanServer.pleaseWait");
this.drawString(fontRendererObj, message, (this.width - this.fontRendererObj.getStringWidth(message)) / 2, this.height / 3 + 10, 0xFFFFFF);
PlatformWebRTC.startRTCLANClient();
if(++renderCount > 1) {
RelayServerSocket sock;
if(relay == null) {
sock = RelayManager.relayManager.getWorkingRelay((str) -> ls.resetProgressAndMessage("Connecting: " + str), 0x02, code);
}else {
sock = RelayManager.relayManager.connectHandshake(relay, 0x02, code);
}
if(sock == null) {
this.mc.displayGuiScreen(new GuiScreenNoRelays(parent, I18n.format("noRelay.worldNotFound1").replace("$code$", code),
I18n.format("noRelay.worldNotFound2").replace("$code$", code), I18n.format("noRelay.worldNotFound3")));
return;
}
networkManager = LANClientNetworkManager.connectToWorld(sock, code, sock.getURI());
if(networkManager == null) {
this.mc.displayGuiScreen(new GuiDisconnected(parent, "connect.failed", new ChatComponentText(I18n.format("noRelay.worldFail").replace("$code$", code))));
return;
}
completed = true;
this.mc.getSession().setLAN();
this.mc.clearTitles();
networkManager.setConnectionState(EnumConnectionState.LOGIN);
networkManager.setNetHandler(new NetHandlerSingleplayerLogin(networkManager, mc, parent));
networkManager.sendPacket(new C00PacketLoginStart(this.mc.getSession().getProfile(), EaglerProfile.getSkinPacket()));
}
}
}
}

View File

@ -0,0 +1,58 @@
package net.lax1dude.eaglercraft.v1_8.sp.gui;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.resources.I18n;
/**
* Copyright (c) 2024 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
* 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.
*
*/
public class GuiScreenLANInfo extends GuiScreen {
private GuiScreen parent;
public GuiScreenLANInfo(GuiScreen parent) {
this.parent = parent;
}
public void initGui() {
buttonList.clear();
buttonList.add(new GuiButton(0, this.width / 2 - 100, height / 6 + 168, I18n.format("gui.continue")));
}
public void drawScreen(int par1, int par2, float par3) {
this.drawDefaultBackground();
this.drawCenteredString(this.fontRendererObj, I18n.format("lanInfo.title"), this.width / 2, this.height / 4 - 60 + 20, 16777215);
this.fontRendererObj.drawSplitString(I18n.format("lanInfo.desc.0") + "\n\n\n" + I18n.format("lanInfo.desc.1", I18n.format("menu.multiplayer"), I18n.format("menu.openToLan")), this.width / 2 - 100, this.height / 4 - 60 + 60, 200, -6250336);
super.drawScreen(par1, par2, par3);
}
protected void actionPerformed(GuiButton par1GuiButton) {
if(par1GuiButton.id == 0) {
mc.displayGuiScreen(parent);
}
}
private static boolean hasShown = false;
public static GuiScreen showLANInfoScreen(GuiScreen cont) {
if(!hasShown) {
hasShown = true;
return new GuiScreenLANInfo(cont);
}else {
return cont;
}
}
}

View File

@ -0,0 +1,48 @@
package net.lax1dude.eaglercraft.v1_8.sp.gui;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.resources.I18n;
/**
* 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.
*
*/
public class GuiScreenLANNotSupported extends GuiScreen {
private GuiScreen cont;
public GuiScreenLANNotSupported(GuiScreen cont) {
this.cont = cont;
}
public void initGui() {
this.buttonList.clear();
this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 6 + 96, I18n.format("singleplayer.crashed.continue")));
}
public void drawScreen(int par1, int par2, float par3) {
this.drawDefaultBackground();
this.drawCenteredString(fontRendererObj, I18n.format("singleplayer.notSupported.title"), this.width / 2, 70, 11184810);
this.drawCenteredString(fontRendererObj, I18n.format("singleplayer.notSupported.desc"), this.width / 2, 90, 16777215);
super.drawScreen(par1, par2, par3);
}
protected void actionPerformed(GuiButton par1GuiButton) {
if(par1GuiButton.id == 0) {
this.mc.displayGuiScreen(cont);
}
}
}

View File

@ -0,0 +1,155 @@
package net.lax1dude.eaglercraft.v1_8.sp.gui;
import org.apache.commons.lang3.StringUtils;
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
import net.lax1dude.eaglercraft.v1_8.Keyboard;
import net.lax1dude.eaglercraft.v1_8.internal.FileChooserResult;
import net.lax1dude.eaglercraft.v1_8.sp.SingleplayerServerController;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiCreateWorld;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.GuiTextField;
import net.minecraft.client.resources.I18n;
/**
* 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.
*
*/
public class GuiScreenNameWorldImport extends GuiScreen {
private GuiScreen parentGuiScreen;
private GuiTextField theGuiTextField;
private GuiButton loadSpawnChunksBtn;
private GuiButton enhancedGameRulesBtn;
private int importFormat;
private FileChooserResult world;
private String name;
private boolean timeToImport = false;
private boolean definetlyTimeToImport = false;
private boolean isImporting = false;
private boolean loadSpawnChunks = false;
private boolean enhancedGameRules = true;
public GuiScreenNameWorldImport(GuiScreen menu, FileChooserResult world, int format) {
this.parentGuiScreen = menu;
this.importFormat = format;
this.world = world;
this.name = world.fileName;
if(name.length() > 4 && (name.endsWith(".epk") || name.endsWith(".zip"))) {
name = name.substring(0, name.length() - 4);
}
}
/**
* Called from the main game loop to update the screen.
*/
public void updateScreen() {
if(!timeToImport) {
this.theGuiTextField.updateCursorCounter();
}
if(definetlyTimeToImport && !isImporting) {
isImporting = true;
SingleplayerServerController.importWorld(GuiCreateWorld.func_146317_a(mc.getSaveLoader(), this.theGuiTextField.getText().trim()), world.fileData, importFormat, (byte) ((loadSpawnChunks ? 2 : 0) | (enhancedGameRules ? 1 : 0)));
mc.displayGuiScreen(new GuiScreenIntegratedServerBusy(parentGuiScreen, "singleplayer.busy.importing." + (importFormat + 1), "singleplayer.failed.importing." + (importFormat + 1), () -> SingleplayerServerController.isReady()));
}
}
/**
* Adds the buttons (and other controls) to the screen in question.
*/
public void initGui() {
if(!timeToImport) {
Keyboard.enableRepeatEvents(true);
this.buttonList.clear();
this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 4 + 96 + 12, I18n.format("singleplayer.import.continue")));
this.buttonList.add(new GuiButton(1, this.width / 2 - 100, this.height / 4 + 120 + 12, I18n.format("gui.cancel")));
this.theGuiTextField = new GuiTextField(2, this.fontRendererObj, this.width / 2 - 100, this.height / 4 + 3, 200, 20);
this.theGuiTextField.setFocused(true);
this.theGuiTextField.setText(name);
this.buttonList.add(loadSpawnChunksBtn = new GuiButton(2, this.width / 2 - 100, this.height / 4 + 24 + 12, I18n.format("singleplayer.import.loadSpawnChunks", loadSpawnChunks ? I18n.format("gui.yes") : I18n.format("gui.no"))));
this.buttonList.add(enhancedGameRulesBtn = new GuiButton(3, this.width / 2 - 100, this.height / 4 + 48 + 12, I18n.format("singleplayer.import.enhancedGameRules", enhancedGameRules ? I18n.format("gui.yes") : I18n.format("gui.no"))));
}
}
/**
* Called when the screen is unloaded. Used to disable keyboard repeat events
*/
public void onGuiClosed() {
Keyboard.enableRepeatEvents(false);
}
/**
* Fired when a control is clicked. This is the equivalent of
* ActionListener.actionPerformed(ActionEvent e).
*/
protected void actionPerformed(GuiButton par1GuiButton) {
if (par1GuiButton.enabled) {
if (par1GuiButton.id == 1) {
EagRuntime.clearFileChooserResult();
this.mc.displayGuiScreen(this.parentGuiScreen);
} else if (par1GuiButton.id == 0) {
this.buttonList.clear();
timeToImport = true;
} else if (par1GuiButton.id == 2) {
loadSpawnChunks = !loadSpawnChunks;
loadSpawnChunksBtn.displayString = I18n.format("singleplayer.import.loadSpawnChunks", loadSpawnChunks ? I18n.format("gui.yes") : I18n.format("gui.no"));
} else if (par1GuiButton.id == 3) {
enhancedGameRules = !enhancedGameRules;
enhancedGameRulesBtn.displayString = I18n.format("singleplayer.import.enhancedGameRules", enhancedGameRules ? I18n.format("gui.yes") : I18n.format("gui.no"));
}
}
}
/**
* Fired when a key is typed. This is the equivalent of
* KeyListener.keyTyped(KeyEvent e).
*/
protected void keyTyped(char par1, int par2) {
this.theGuiTextField.textboxKeyTyped(par1, par2);
((GuiButton) this.buttonList.get(0)).enabled = this.theGuiTextField.getText().trim().length() > 0;
if (par1 == 13) {
this.actionPerformed((GuiButton) this.buttonList.get(0));
}
}
/**
* Called when the mouse is clicked.
*/
protected void mouseClicked(int par1, int par2, int par3) {
super.mouseClicked(par1, par2, par3);
if(!timeToImport) {
this.theGuiTextField.mouseClicked(par1, par2, par3);
}
}
/**
* Draws the screen and all the components in it.
*/
public void drawScreen(int par1, int par2, float par3) {
this.drawDefaultBackground();
if(!timeToImport) {
this.drawCenteredString(this.fontRendererObj, I18n.format("singleplayer.import.title"), this.width / 2, this.height / 4 - 60 + 20, 16777215);
this.drawString(this.fontRendererObj, I18n.format("singleplayer.import.enterName"), this.width / 2 - 100, this.height / 4 - 60 + 50, 10526880);
this.drawCenteredString(this.fontRendererObj, I18n.format("createWorld.seedNote"), this.width / 2, this.height / 4 + 90, -6250336);
this.theGuiTextField.drawTextBox();
}else {
definetlyTimeToImport = true;
long dots = (System.currentTimeMillis() / 500l) % 4l;
String str = I18n.format("singleplayer.import.reading", world.fileName);
this.drawString(fontRendererObj, str + (dots > 0 ? "." : "") + (dots > 1 ? "." : "") + (dots > 2 ? "." : ""), (this.width - this.fontRendererObj.getStringWidth(str)) / 2, this.height / 3 + 10, 0xFFFFFF);
}
super.drawScreen(par1, par2, par3);
}
}

View File

@ -0,0 +1,69 @@
package net.lax1dude.eaglercraft.v1_8.sp.gui;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.resources.I18n;
/**
* Copyright (c) 2022-2024 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
* 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.
*
*/
public class GuiScreenNoRelays extends GuiScreen {
private GuiScreen parent;
private String title1;
private String title2;
private String title3;
public GuiScreenNoRelays(GuiScreen parent, String title) {
this.parent = parent;
this.title1 = title;
this.title2 = null;
this.title3 = null;
}
public GuiScreenNoRelays(GuiScreen parent, String title1, String title2, String title3) {
this.parent = parent;
this.title1 = title1;
this.title2 = title2;
this.title3 = title3;
}
public void initGui() {
buttonList.clear();
buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 4 - 60 + 145, I18n.format("gui.cancel")));
buttonList.add(new GuiButton(1, this.width / 2 - 100, this.height / 4 - 60 + 115, I18n.format("directConnect.lanWorldRelay")));
}
public void drawScreen(int par1, int par2, float par3) {
this.drawDefaultBackground();
this.drawCenteredString(this.fontRendererObj, I18n.format(title1), this.width / 2, this.height / 4 - 60 + 70, 16777215);
if(title2 != null) {
this.drawCenteredString(this.fontRendererObj, I18n.format(title2), this.width / 2, this.height / 4 - 60 + 80, 0xCCCCCC);
}
if(title3 != null) {
this.drawCenteredString(this.fontRendererObj, I18n.format(title3), this.width / 2, this.height / 4 - 60 + 90, 0xCCCCCC);
}
super.drawScreen(par1, par2, par3);
}
protected void actionPerformed(GuiButton par1GuiButton) {
if(par1GuiButton.id == 0) {
mc.displayGuiScreen(parent);
}else if(par1GuiButton.id == 1) {
mc.displayGuiScreen(GuiScreenLANInfo.showLANInfoScreen(new GuiScreenRelay(parent)));
}
}
}

View File

@ -0,0 +1,218 @@
package net.lax1dude.eaglercraft.v1_8.sp.gui;
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
import net.lax1dude.eaglercraft.v1_8.Mouse;
import net.lax1dude.eaglercraft.v1_8.internal.EnumCursorType;
import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayManager;
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayServer;
import net.minecraft.client.Minecraft;
import net.minecraft.client.audio.PositionedSoundRecord;
import net.minecraft.client.gui.*;
import net.minecraft.client.resources.I18n;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.ResourceLocation;
import java.io.IOException;
/**
* Copyright (c) 2022-2024 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
* 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.
*
*/
public class GuiScreenRelay extends GuiScreen implements GuiYesNoCallback {
private final GuiScreen screen;
private GuiSlotRelay slots;
private boolean hasPinged;
private boolean addingNew = false;
private boolean deleting = false;
int selected;
private GuiButton deleteRelay;
private GuiButton setPrimary;
private String tooltipString = null;
private long lastRefresh = 0l;
public GuiScreenRelay(GuiScreen screen) {
this.screen = screen;
}
public void initGui() {
selected = -1;
buttonList.clear();
buttonList.add(new GuiButton(0, this.width / 2 + 54, this.height - 28, 100, 20, I18n.format("gui.done")));
buttonList.add(new GuiButton(1, this.width / 2 - 154, this.height - 52, 100, 20, I18n.format("networkSettings.add")));
buttonList.add(deleteRelay = new GuiButton(2, this.width / 2 - 50, this.height - 52, 100, 20, I18n.format("networkSettings.delete")));
buttonList.add(setPrimary = new GuiButton(3, this.width / 2 + 54, this.height - 52, 100, 20, I18n.format("networkSettings.default")));
buttonList.add(new GuiButton(4, this.width / 2 - 50, this.height - 28, 100, 20, I18n.format("networkSettings.refresh")));
buttonList.add(new GuiButton(5, this.width / 2 - 154, this.height - 28, 100, 20, I18n.format("networkSettings.loadDefaults")));
buttonList.add(new GuiButton(6, this.width - 100, 0, 100, 20, I18n.format("networkSettings.downloadRelay")));
updateButtons();
this.slots = new GuiSlotRelay(this);
if(!hasPinged) {
hasPinged = true;
slots.relayManager.ping();
}
}
void updateButtons() {
if(selected < 0) {
deleteRelay.enabled = false;
setPrimary.enabled = false;
}else {
deleteRelay.enabled = true;
setPrimary.enabled = true;
}
}
public void actionPerformed(GuiButton btn) {
if(btn.id == 0) {
RelayManager.relayManager.save();
mc.displayGuiScreen(screen);
} else if(btn.id == 1) {
addingNew = true;
mc.displayGuiScreen(new GuiScreenAddRelay(this));
} else if(btn.id == 2) {
if(selected >= 0) {
RelayServer srv = RelayManager.relayManager.get(selected);
mc.displayGuiScreen(new GuiYesNo(this, I18n.format("networkSettings.delete"), I18n.format("addRelay.removeText1") +
EnumChatFormatting.GRAY + " '" + srv.comment + "' (" + srv.address + ")", selected));
deleting = true;
}
} else if(btn.id == 3) {
if(selected >= 0) {
slots.relayManager.setPrimary(selected);
selected = 0;
}
} else if(btn.id == 4) {
long millis = System.currentTimeMillis();
if(millis - lastRefresh > 700l) {
lastRefresh = millis;
slots.relayManager.ping();
}
lastRefresh += 60l;
} else if(btn.id == 5) {
slots.relayManager.loadDefaults();
long millis = System.currentTimeMillis();
if(millis - lastRefresh > 700l) {
lastRefresh = millis;
slots.relayManager.ping();
}
lastRefresh += 60l;
} else if(btn.id == 6) {
EagRuntime.downloadFileWithName("EaglerSPRelay.zip", EagRuntime.getResourceBytes("relay_download.zip"));
}
}
public void updateScreen() {
slots.relayManager.update();
}
private int mx = 0;
private int my = 0;
int getFrameMouseX() {
return mx;
}
int getFrameMouseY() {
return my;
}
public void drawScreen(int par1, int par2, float par3) {
mx = par1;
my = par2;
slots.drawScreen(par1, par2, par3);
if(tooltipString != null) {
int ww = mc.fontRendererObj.getStringWidth(tooltipString);
Gui.drawRect(par1 + 1, par2 - 14, par1 + ww + 7, par2 - 2, 0xC0000000);
screen.drawString(mc.fontRendererObj, tooltipString, par1 + 4, par2 - 12, 0xFF999999);
tooltipString = null;
}
this.drawCenteredString(fontRendererObj, I18n.format("networkSettings.title"), this.width / 2, 16, 16777215);
String str = I18n.format("networkSettings.relayTimeout") + " " + mc.gameSettings.relayTimeout;
int w = fontRendererObj.getStringWidth(str);
this.drawString(fontRendererObj, str, 3, 3, 0xDDDDDD);
GlStateManager.pushMatrix();
GlStateManager.translate(w + 7, 4, 0.0f);
GlStateManager.scale(0.75f, 0.75f, 0.75f);
str = EnumChatFormatting.UNDERLINE + I18n.format("networkSettings.relayTimeoutChange");
int w2 = fontRendererObj.getStringWidth(str);
boolean b = par1 > w + 5 && par1 < w + 7 + w2 * 3 / 4 && par2 > 3 && par2 < 11;
if(b) Mouse.showCursor(EnumCursorType.HAND);
this.drawString(fontRendererObj, EnumChatFormatting.UNDERLINE + I18n.format("networkSettings.relayTimeoutChange"), 0, 0, b ? 0xCCCCCC : 0x999999);
GlStateManager.popMatrix();
super.drawScreen(par1, par2, par3);
}
protected void mouseClicked(int par1, int par2, int par3) {
super.mouseClicked(par1, par2, par3);
if(par3 == 0) {
String str = I18n.format("networkSettings.relayTimeout") + " " + mc.gameSettings.relayTimeout;
int w = fontRendererObj.getStringWidth(str);
str = I18n.format("networkSettings.relayTimeoutChange");
int w2 = fontRendererObj.getStringWidth(str);
if(par1 > w + 5 && par1 < w + 7 + w2 * 3 / 4 && par2 > 3 && par2 < 11) {
this.mc.displayGuiScreen(new GuiScreenChangeRelayTimeout(this));
this.mc.getSoundHandler().playSound(PositionedSoundRecord.create(new ResourceLocation("gui.button.press"), 1.0F));
}
}
}
void setToolTip(String str) {
tooltipString = str;
}
String addNewName;
String addNewAddr;
boolean addNewPrimary;
public void confirmClicked(boolean par1, int par2) {
if(par1) {
if(addingNew) {
RelayManager.relayManager.addNew(addNewAddr, addNewName, addNewPrimary);
addNewAddr = null;
addNewName = null;
addNewPrimary = false;
selected = -1;
updateButtons();
}else if(deleting) {
RelayManager.relayManager.remove(par2);
selected = -1;
updateButtons();
}
}
addingNew = false;
deleting = false;
this.mc.displayGuiScreen(this);
}
static Minecraft getMinecraft(GuiScreenRelay screen) {
return screen.mc;
}
@Override
public void handleMouseInput() throws IOException {
super.handleMouseInput();
this.slots.handleMouseInput();
}
}

View File

@ -0,0 +1,127 @@
package net.lax1dude.eaglercraft.v1_8.sp.gui;
import java.io.IOException;
import net.lax1dude.eaglercraft.v1_8.profile.EaglerProfile;
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;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiDisconnected;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.client.resources.I18n;
import net.minecraft.network.EnumConnectionState;
import net.minecraft.network.login.client.C00PacketLoginStart;
import net.minecraft.util.ChatComponentText;
/**
* 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.
*
*/
public class GuiScreenSingleplayerConnecting extends GuiScreen {
private GuiScreen menu;
private String message;
private GuiButton killTask;
private ClientIntegratedServerNetworkManager networkManager = null;
private int timer = 0;
private long startStartTime;
private boolean hasOpened = false;
public GuiScreenSingleplayerConnecting(GuiScreen menu, String message) {
this.menu = menu;
this.message = message;
}
public void initGui() {
if(startStartTime == 0) this.startStartTime = System.currentTimeMillis();
this.buttonList.add(killTask = new GuiButton(0, this.width / 2 - 100, this.height / 3 + 50, I18n.format("singleplayer.busy.killTask")));
killTask.enabled = false;
}
public void drawScreen(int par1, int par2, float par3) {
this.drawDefaultBackground();
float f = 2.0f;
int top = this.height / 3;
long millis = System.currentTimeMillis();
long dots = (millis / 500l) % 4l;
this.drawString(fontRendererObj, message + (dots > 0 ? "." : "") + (dots > 1 ? "." : "") + (dots > 2 ? "." : ""), (this.width - this.fontRendererObj.getStringWidth(message)) / 2, top + 10, 0xFFFFFF);
long elapsed = (millis - startStartTime) / 1000l;
if(elapsed > 3) {
this.drawCenteredString(fontRendererObj, "(" + elapsed + "s)", this.width / 2, top + 25, 0xFFFFFF);
}
super.drawScreen(par1, par2, par3);
}
public boolean doesGuiPauseGame() {
return false;
}
public void updateScreen() {
++timer;
if (timer > 1) {
if (this.networkManager == null) {
this.networkManager = SingleplayerServerController.localPlayerNetworkManager;
this.networkManager.connect();
} else {
if (this.networkManager.isChannelOpen()) {
if (!hasOpened) {
hasOpened = true;
this.mc.getSession().setLAN();
this.mc.clearTitles();
this.networkManager.setConnectionState(EnumConnectionState.LOGIN);
this.networkManager.setNetHandler(new NetHandlerSingleplayerLogin(this.networkManager, this.mc, this.menu));
this.networkManager.sendPacket(new C00PacketLoginStart(this.mc.getSession().getProfile(), EaglerProfile.getSkinPacket()));
}
try {
this.networkManager.processReceivedPackets();
} catch (IOException ex) {
}
} else {
if (this.networkManager.checkDisconnected()) {
this.mc.getSession().reset();
if (mc.currentScreen == this) {
mc.loadWorld(null);
mc.displayGuiScreen(new GuiDisconnected(menu, "connect.failed", new ChatComponentText("Worker Connection Refused")));
}
}
}
}
}
long millis = System.currentTimeMillis();
if(millis - startStartTime > 6000l && SingleplayerServerController.canKillWorker()) {
killTask.enabled = true;
}
}
protected void actionPerformed(GuiButton par1GuiButton) {
if(par1GuiButton.id == 0) {
SingleplayerServerController.killWorker();
this.mc.loadWorld((WorldClient)null);
this.mc.getSession().reset();
this.mc.displayGuiScreen(menu);
}
}
public boolean shouldHangupIntegratedServer() {
return false;
}
}

View File

@ -0,0 +1,198 @@
package net.lax1dude.eaglercraft.v1_8.sp.gui;
import net.lax1dude.eaglercraft.v1_8.internal.PlatformWebRTC;
import net.lax1dude.eaglercraft.v1_8.sp.SingleplayerServerController;
import net.lax1dude.eaglercraft.v1_8.sp.lan.LANServerController;
import net.minecraft.client.LoadingScreenRenderer;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.GuiTextField;
import net.minecraft.client.resources.I18n;
import net.minecraft.util.ChatComponentText;
import net.minecraft.world.WorldSettings;
/**
* Copyright (c) 2022-2024 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
* 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.
*
*/
public class GuiShareToLan extends GuiScreen {
/**
* A reference to the screen object that created this. Used for navigating
* between screens.
*/
private final GuiScreen parentScreen;
private GuiButton buttonAllowCommandsToggle;
private GuiButton buttonGameMode;
private GuiButton buttonHiddenToggle;
/**
* The currently selected game mode. One of 'survival', 'creative', or
* 'adventure'
*/
private String gameMode;
/**
* True if 'Allow Cheats' is currently enabled
*/
private boolean allowCommands = false;
private final GuiNetworkSettingsButton relaysButton;
private boolean hiddenToggle = false;
private GuiTextField codeTextField;
public GuiShareToLan(GuiScreen par1GuiScreen, String gameMode) {
this.parentScreen = par1GuiScreen;
this.relaysButton = new GuiNetworkSettingsButton(this);
this.gameMode = gameMode;
}
/**
* Adds the buttons (and other controls) to the screen in question.
*/
public void initGui() {
this.buttonList.clear();
this.buttonList.add(new GuiButton(101, this.width / 2 - 155, this.height - 28, 140, 20,
I18n.format("lanServer.start")));
this.buttonList.add(new GuiButton(102, this.width / 2 + 5, this.height - 28, 140, 20,
I18n.format("gui.cancel")));
this.buttonList.add(this.buttonGameMode = new GuiButton(104, this.width / 2 - 155, 135, 140, 20,
I18n.format("selectWorld.gameMode")));
this.buttonList.add(this.buttonAllowCommandsToggle = new GuiButton(103, this.width / 2 + 5, 135, 140, 20,
I18n.format("selectWorld.allowCommands")));
this.buttonGameMode.enabled = this.buttonAllowCommandsToggle.enabled = !mc.isDemo();
this.buttonList.add(this.buttonHiddenToggle = new GuiButton(105, this.width / 2 - 75, 165, 140, 20,
I18n.format("lanServer.hidden")));
this.codeTextField = new GuiTextField(0, this.fontRendererObj, this.width / 2 - 100, 80, 200, 20);
this.codeTextField.setText(mc.thePlayer.getName() + "'s World");
this.codeTextField.setFocused(true);
this.codeTextField.setMaxStringLength(252);
this.func_74088_g();
}
private void func_74088_g() {
this.buttonGameMode.displayString = I18n.format("selectWorld.gameMode") + ": "
+ I18n.format("selectWorld.gameMode." + this.gameMode);
this.buttonAllowCommandsToggle.displayString = I18n.format("selectWorld.allowCommands")
+ " ";
this.buttonHiddenToggle.displayString = I18n.format("lanServer.hidden")
+ " ";
if (this.allowCommands) {
this.buttonAllowCommandsToggle.displayString = this.buttonAllowCommandsToggle.displayString
+ I18n.format("options.on");
} else {
this.buttonAllowCommandsToggle.displayString = this.buttonAllowCommandsToggle.displayString
+ I18n.format("options.off");
}
if (this.hiddenToggle) {
this.buttonHiddenToggle.displayString = this.buttonHiddenToggle.displayString
+ I18n.format("options.on");
} else {
this.buttonHiddenToggle.displayString = this.buttonHiddenToggle.displayString
+ I18n.format("options.off");
}
}
/**
* Fired when a control is clicked. This is the equivalent of
* ActionListener.actionPerformed(ActionEvent e).
*/
protected void actionPerformed(GuiButton par1GuiButton) {
if (par1GuiButton.id == 102) {
this.mc.displayGuiScreen(this.parentScreen);
} else if (par1GuiButton.id == 104) {
if(!mc.isDemo()) {
if (this.gameMode.equals("survival")) {
this.gameMode = "creative";
} else if (this.gameMode.equals("creative")) {
this.gameMode = "adventure";
} else if (this.gameMode.equals("adventure")) {
this.gameMode = "spectator";
} else {
this.gameMode = "survival";
}
this.func_74088_g();
}
} else if (par1GuiButton.id == 103) {
if(!mc.isDemo()) {
this.allowCommands = !this.allowCommands;
this.func_74088_g();
}
} else if (par1GuiButton.id == 105) {
this.hiddenToggle = !this.hiddenToggle;
this.func_74088_g();
} else if (par1GuiButton.id == 101) {
if (LANServerController.isLANOpen()) {
return;
}
PlatformWebRTC.startRTCLANServer();
String worldName = this.codeTextField.getText().trim();
if (worldName.isEmpty()) {
worldName = mc.thePlayer.getName() + "'s World";
}
if (worldName.length() >= 252) {
worldName = worldName.substring(0, 252);
}
this.mc.displayGuiScreen(null);
LoadingScreenRenderer ls = mc.loadingScreen;
String code = LANServerController.shareToLAN((str) -> ls.resetProgressAndMessage(str), worldName, hiddenToggle);
if (code != null) {
SingleplayerServerController.configureLAN(WorldSettings.GameType.getByName(this.gameMode), this.allowCommands);
this.mc.ingameGUI.getChatGUI().printChatMessage(new ChatComponentText(I18n.format("lanServer.opened")
.replace("$relay$", LANServerController.getCurrentURI()).replace("$code$", code)));
} else {
SingleplayerServerController.configureLAN(mc.theWorld.getWorldInfo().getGameType(), false);
this.mc.displayGuiScreen(new GuiScreenNoRelays(this, "noRelay.titleFail"));
}
}
}
/**
* Draws the screen and all the components in it.
*/
public void drawScreen(int par1, int par2, float par3) {
this.drawDefaultBackground();
this.drawCenteredString(this.fontRendererObj, I18n.format("lanServer.title"), this.width / 2,
35, 16777215);
this.drawCenteredString(this.fontRendererObj, I18n.format("lanServer.worldName"), this.width / 2,
62, 16777215);
this.drawCenteredString(this.fontRendererObj, I18n.format("lanServer.otherPlayers"),
this.width / 2, 112, 16777215);
this.drawCenteredString(this.fontRendererObj, I18n.format("lanServer.ipGrabNote"),
this.width / 2, 195, 16777215);
super.drawScreen(par1, par2, par3);
this.relaysButton.drawScreen(par1, par2);
this.codeTextField.drawTextBox();
}
public void mouseClicked(int par1, int par2, int par3) {
super.mouseClicked(par1, par2, par3);
this.relaysButton.mouseClicked(par1, par2, par3);
this.codeTextField.mouseClicked(par1, par2, par3);
}
protected void keyTyped(char c, int k) {
super.keyTyped(c, k);
this.codeTextField.textboxKeyTyped(c, k);
}
public void updateScreen() {
super.updateScreen();
this.codeTextField.updateCursorCounter();
}
}

View File

@ -0,0 +1,103 @@
package net.lax1dude.eaglercraft.v1_8.sp.gui;
import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
/**
* Copyright (c) 2022-2024 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
* 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.
*
*/
public class GuiSlider2 extends GuiButton {
/** The value of this slider control. */
public float sliderValue = 1.0F;
public float sliderMax = 1.0F;
/** Is this slider control being dragged. */
public boolean dragging = false;
public GuiSlider2(int par1, int par2, int par3, int par4, int par5, float par6, float par7) {
super(par1, par2, par3, par4, par5, (int)(par6 * par7 * 100.0F) + "%");
this.sliderValue = par6;
this.sliderMax = par7;
}
/**
* Returns 0 if the button is disabled, 1 if the mouse is NOT hovering over this
* button and 2 if it IS hovering over this button.
*/
protected int getHoverState(boolean par1) {
return 0;
}
/**
* Fired when the mouse button is dragged. Equivalent of
* MouseListener.mouseDragged(MouseEvent e).
*/
protected void mouseDragged(Minecraft par1Minecraft, int par2, int par3) {
if (this.visible) {
if (this.dragging) {
this.sliderValue = (float) (par2 - (this.xPosition + 4)) / (float) (this.width - 8);
if (this.sliderValue < 0.0F) {
this.sliderValue = 0.0F;
}
if (this.sliderValue > 1.0F) {
this.sliderValue = 1.0F;
}
this.displayString = (int)(this.sliderValue * this.sliderMax * 100.0F) + "%";
}
if(this.enabled) {
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
this.drawTexturedModalRect(this.xPosition + (int) (this.sliderValue * (float) (this.width - 8)), this.yPosition, 0, 66, 4, 20);
this.drawTexturedModalRect(this.xPosition + (int) (this.sliderValue * (float) (this.width - 8)) + 4, this.yPosition, 196, 66, 4, 20);
}
}
}
/**
* Returns true if the mouse has been pressed on this control. Equivalent of
* MouseListener.mousePressed(MouseEvent e).
*/
public boolean mousePressed(Minecraft par1Minecraft, int par2, int par3) {
if (super.mousePressed(par1Minecraft, par2, par3)) {
this.sliderValue = (float) (par2 - (this.xPosition + 4)) / (float) (this.width - 8);
if (this.sliderValue < 0.0F) {
this.sliderValue = 0.0F;
}
if (this.sliderValue > 1.0F) {
this.sliderValue = 1.0F;
}
this.displayString = (int)(this.sliderValue * this.sliderMax * 100.0F) + "%";
this.dragging = true;
return true;
} else {
return false;
}
}
/**
* Fired when the mouse button is released. Equivalent of
* MouseListener.mouseReleased(MouseEvent e).
*/
public void mouseReleased(int par1, int par2) {
this.dragging = false;
}
}

View File

@ -0,0 +1,150 @@
package net.lax1dude.eaglercraft.v1_8.sp.gui;
import net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager;
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayManager;
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayQuery;
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayServer;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.gui.GuiSlot;
import net.minecraft.util.ResourceLocation;
/**
* Copyright (c) 2022-2024 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
* 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.
*
*/
class GuiSlotRelay extends GuiSlot {
private static final ResourceLocation eaglerGuiTex = new ResourceLocation("eagler:gui/eagler_gui.png");
final GuiScreenRelay screen;
final RelayManager relayManager;
public GuiSlotRelay(GuiScreenRelay screen) {
super(GuiScreenRelay.getMinecraft(screen), screen.width, screen.height, 32, screen.height - 64, 26);
this.screen = screen;
this.relayManager = RelayManager.relayManager;
}
@Override
protected int getSize() {
return relayManager.count();
}
@Override
protected void elementClicked(int var1, boolean var2, int var3, int var4) {
screen.selected = var1;
screen.updateButtons();
}
@Override
protected boolean isSelected(int var1) {
return screen.selected == var1;
}
@Override
protected void drawBackground() {
screen.drawDefaultBackground();
}
@Override
protected void drawSlot(int id, int xx, int yy, int width, int height, int ii) {
if(id < relayManager.count()) {
this.mc.getTextureManager().bindTexture(Gui.icons);
RelayServer srv = relayManager.get(id);
String comment = srv.comment;
int var15 = 0;
int var16 = 0;
String str = null;
int h = 12;
long ping = srv.getPing();
if(ping == 0l) {
var16 = 5;
str = "No Connection";
}else if(ping < 0l) {
var15 = 1;
var16 = (int) (Minecraft.getSystemTime() / 100L + (long) (id * 2) & 7L);
if (var16 > 4) {
var16 = 8 - var16;
}
str = "Polling...";
}else {
RelayQuery.VersionMismatch vm = srv.getPingCompatible();
if(!vm.isCompatible()) {
var16 = 5;
switch(vm) {
case CLIENT_OUTDATED:
str = "Outdated Client!";
break;
case RELAY_OUTDATED:
str = "Outdated Relay!";
break;
default:
case UNKNOWN:
str = "Incompatible Relay!";
break;
}
GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f);
GlStateManager.pushMatrix();
GlStateManager.translate(xx + 205, yy + 11, 0.0f);
GlStateManager.scale(0.6f, 0.6f, 0.6f);
screen.drawTexturedModalRect(0, 0, 0, 144, 16, 16);
GlStateManager.popMatrix();
h += 10;
}else {
String pingComment = srv.getPingComment().trim();
if(pingComment.length() > 0) {
comment = pingComment;
}
str = "" + ping + "ms";
if (ping < 150L) {
var16 = 0;
} else if (ping < 300L) {
var16 = 1;
} else if (ping < 600L) {
var16 = 2;
} else if (ping < 1000L) {
var16 = 3;
} else {
var16 = 4;
}
}
}
GlStateManager.color(1.0f, 1.0f, 1.0f, 1.0f);
screen.drawTexturedModalRect(xx + 205, yy, 0 + var15 * 10, 176 + var16 * 8, 10, 8);
if(srv.isPrimary()) {
GlStateManager.pushMatrix();
GlStateManager.translate(xx + 4, yy + 5, 0.0f);
GlStateManager.scale(0.8f, 0.8f, 0.8f);
this.mc.getTextureManager().bindTexture(eaglerGuiTex);
screen.drawTexturedModalRect(0, 0, 48, 0, 16, 16);
GlStateManager.popMatrix();
}
screen.drawString(mc.fontRendererObj, comment, xx + 22, yy + 2, 0xFFFFFFFF);
screen.drawString(mc.fontRendererObj, srv.address, xx + 22, yy + 12, 0xFF999999);
if(str != null) {
int mx = screen.getFrameMouseX();
int my = screen.getFrameMouseY();
int rx = xx + 202;
if(mx > rx && mx < rx + 13 && my > yy - 1 && my < yy + h) {
screen.setToolTip(str);
}
}
}
}
}

View File

@ -0,0 +1,84 @@
package net.lax1dude.eaglercraft.v1_8.sp.ipc;
import java.io.IOException;
import java.io.InputStream;
/**
* Copyright (c) 2023-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.
*
*/
public class IPCInputStream extends InputStream {
private byte[] currentBuffer = null;
private int idx = 0;
private int markIDX = 0;
private String errorName = null;
public void feedBuffer(byte[] b) {
currentBuffer = b;
idx = 0;
errorName = null;
markIDX = 0;
}
public void nameBuffer(String str) {
errorName = str;
}
@Override
public int read() throws IOException {
try {
return ((int)currentBuffer[idx++]) & 0xFF;
}catch(ArrayIndexOutOfBoundsException a) {
throw new IOException("IPCInputStream buffer underflow" + (errorName == null ? "," : (" (while deserializing '" + errorName + "')")) + " no bytes remaining", a);
}
}
@Override
public int read(byte b[], int off, int len) throws IOException {
if(idx + len > currentBuffer.length) {
throw new IOException("IPCInputStream buffer underflow" + (errorName == null ? "," : (" (while deserializing '" + errorName + "')")) + " tried to read " + len + " when there are only " + (currentBuffer.length - idx) + " bytes remaining", new ArrayIndexOutOfBoundsException(idx + len - 1));
}
if(off + len > b.length) {
throw new ArrayIndexOutOfBoundsException(off + len - 1);
}
System.arraycopy(currentBuffer, idx, b, off, len);
idx += len;
return len;
}
public void markIndex() {
markIDX = idx;
}
public void rewindIndex() {
idx = markIDX;
}
public byte[] getLeftover() {
if(currentBuffer.length - idx <= 0) {
return null;
}
byte[] buf = new byte[currentBuffer.length - idx];
System.arraycopy(currentBuffer, idx, buf, 0, currentBuffer.length - idx);
return buf;
}
public int getLeftoverCount() {
return currentBuffer.length - idx;
}
}

View File

@ -0,0 +1,69 @@
package net.lax1dude.eaglercraft.v1_8.sp.ipc;
import java.io.IOException;
import java.io.OutputStream;
/**
* Copyright (c) 2023-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.
*
*/
public class IPCOutputStream extends OutputStream {
private String className = null;
private byte[] currentBuffer = null;
private int idx = 0;
private int originalSize = 0;
public void feedBuffer(byte[] buf, String clazzName) {
currentBuffer = buf;
idx = 0;
originalSize = buf.length;
className = clazzName;
}
public byte[] returnBuffer() {
if(className != null && currentBuffer.length != originalSize) {
System.err.println("WARNING: Packet '" + className + "' was supposed to be " + originalSize + " bytes but buffer has grown by " + (currentBuffer.length - originalSize) + " to " + currentBuffer.length + " bytes");
}
return currentBuffer;
}
void growBuffer(int i) {
int ii = currentBuffer.length;
int iii = i - ii;
if(iii > 0) {
byte[] n = new byte[i];
System.arraycopy(currentBuffer, 0, n, 0, ii);
currentBuffer = n;
}
}
@Override
public void write(int b) throws IOException {
if(idx >= currentBuffer.length) {
growBuffer(idx + 1);
}
currentBuffer[idx++] = (byte) b;
}
@Override
public void write(byte b[], int off, int len) throws IOException {
if(idx + len > currentBuffer.length) {
growBuffer(idx + len);
}
System.arraycopy(b, off, currentBuffer, idx, len);
idx += len;
}
}

View File

@ -0,0 +1,71 @@
package net.lax1dude.eaglercraft.v1_8.sp.ipc;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* Copyright (c) 2023-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.
*
*/
public class IPCPacket00StartServer implements IPCPacketBase {
public static final int ID = 0x00;
public String worldName;
public String ownerName;
public int initialDifficulty;
public int initialViewDistance;
public boolean demoMode;
public IPCPacket00StartServer() {
}
public IPCPacket00StartServer(String worldName, String ownerName, int initialDifficulty, int initialViewDistance, boolean demoMode) {
this.worldName = worldName;
this.ownerName = ownerName;
this.initialDifficulty = initialDifficulty;
this.initialViewDistance = initialViewDistance;
this.demoMode = demoMode;
}
@Override
public void deserialize(DataInput bin) throws IOException {
worldName = bin.readUTF();
ownerName = bin.readUTF();
initialDifficulty = bin.readByte();
initialViewDistance = bin.readByte();
demoMode = bin.readBoolean();
}
@Override
public void serialize(DataOutput bin) throws IOException {
bin.writeUTF(worldName);
bin.writeUTF(ownerName);
bin.writeByte(initialDifficulty);
bin.writeByte(initialViewDistance);
bin.writeBoolean(demoMode);
}
@Override
public int id() {
return ID;
}
@Override
public int size() {
return IPCPacketBase.strLen(worldName) + IPCPacketBase.strLen(ownerName) + 3;
}
}

View File

@ -0,0 +1,47 @@
package net.lax1dude.eaglercraft.v1_8.sp.ipc;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* Copyright (c) 2023-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.
*
*/
public class IPCPacket01StopServer implements IPCPacketBase {
public static final int ID = 0x01;
public IPCPacket01StopServer() {
}
@Override
public void deserialize(DataInput bin) throws IOException {
}
@Override
public void serialize(DataOutput bin) throws IOException {
}
@Override
public int id() {
return ID;
}
@Override
public int size() {
return 0;
}
}

View File

@ -0,0 +1,87 @@
package net.lax1dude.eaglercraft.v1_8.sp.ipc;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* Copyright (c) 2023-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.
*
*/
public class IPCPacket02InitWorld implements IPCPacketBase {
public static final int ID = 0x02;
public String worldName;
public byte gamemode;
public byte worldType;
public String worldArgs;
public long seed;
public boolean cheats;
public boolean structures;
public boolean bonusChest;
public boolean hardcore;
public IPCPacket02InitWorld() {
}
public IPCPacket02InitWorld(String worldName, int gamemode, int worldType, String worldArgs, long seed, boolean cheats, boolean structures, boolean bonusChest, boolean hardcore) {
this.worldName = worldName;
this.gamemode = (byte)gamemode;
this.worldType = (byte)worldType;
this.worldArgs = worldArgs;
this.seed = seed;
this.cheats = cheats;
this.structures = structures;
this.bonusChest = bonusChest;
this.hardcore = hardcore;
}
@Override
public void deserialize(DataInput bin) throws IOException {
worldName = bin.readUTF();
gamemode = bin.readByte();
worldType = bin.readByte();
worldArgs = bin.readUTF();
seed = bin.readLong();
cheats = bin.readBoolean();
structures = bin.readBoolean();
bonusChest = bin.readBoolean();
hardcore = bin.readBoolean();
}
@Override
public void serialize(DataOutput bin) throws IOException {
bin.writeUTF(worldName);
bin.writeByte(gamemode);
bin.writeByte(worldType);
bin.writeUTF(worldArgs);
bin.writeLong(seed);
bin.writeBoolean(cheats);
bin.writeBoolean(structures);
bin.writeBoolean(bonusChest);
bin.writeBoolean(hardcore);
}
@Override
public int id() {
return ID;
}
@Override
public int size() {
return IPCPacketBase.strLen(worldName) + 1 + 1 + IPCPacketBase.strLen(worldArgs) + 8 + 4;
}
}

View File

@ -0,0 +1,55 @@
package net.lax1dude.eaglercraft.v1_8.sp.ipc;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* Copyright (c) 2023-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.
*
*/
public class IPCPacket03DeleteWorld implements IPCPacketBase {
public static final int ID = 0x03;
public String worldName;
public IPCPacket03DeleteWorld() {
}
public IPCPacket03DeleteWorld(String worldName) {
this.worldName = worldName;
}
@Override
public void deserialize(DataInput bin) throws IOException {
worldName = bin.readUTF();
}
@Override
public void serialize(DataOutput bin) throws IOException {
bin.writeUTF(worldName);
}
@Override
public int id() {
return ID;
}
@Override
public int size() {
return IPCPacketBase.strLen(worldName);
}
}

View File

@ -0,0 +1,67 @@
package net.lax1dude.eaglercraft.v1_8.sp.ipc;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* Copyright (c) 2023-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.
*
*/
public class IPCPacket04RenameWorld implements IPCPacketBase {
public static final int ID = 0x04;
public String worldOldName;
public String worldNewName;
public String displayName;
public boolean copy;
public IPCPacket04RenameWorld() {
}
public IPCPacket04RenameWorld(String worldOldName, String worldNewName, String displayName, boolean copy) {
this.worldOldName = worldOldName;
this.worldNewName = worldNewName;
this.displayName = displayName;
this.copy = copy;
}
@Override
public void deserialize(DataInput bin) throws IOException {
worldOldName = bin.readUTF();
worldNewName = bin.readUTF();
displayName = bin.readUTF();
copy = bin.readBoolean();
}
@Override
public void serialize(DataOutput bin) throws IOException {
bin.writeUTF(worldOldName);
bin.writeUTF(worldNewName);
bin.writeUTF(displayName);
bin.writeBoolean(copy);
}
@Override
public int id() {
return ID;
}
@Override
public int size() {
return IPCPacketBase.strLen(worldOldName) + IPCPacketBase.strLen(worldNewName) + IPCPacketBase.strLen(displayName) + 1;
}
}

View File

@ -0,0 +1,63 @@
package net.lax1dude.eaglercraft.v1_8.sp.ipc;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* Copyright (c) 2023-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.
*
*/
public class IPCPacket05RequestData implements IPCPacketBase {
public static final int ID = 0x05;
public static final byte REQUEST_LEVEL_DAT = 0x00;
public static final byte REQUEST_LEVEL_EAG = 0x01;
public static final byte REQUEST_LEVEL_MCA = 0x02;
public String worldName;
public byte request;
public IPCPacket05RequestData() {
}
public IPCPacket05RequestData(String worldName, byte request) {
this.worldName = worldName;
this.request = request;
}
@Override
public void deserialize(DataInput bin) throws IOException {
worldName = bin.readUTF();
request = bin.readByte();
}
@Override
public void serialize(DataOutput bin) throws IOException {
bin.writeUTF(worldName);
bin.writeByte(request);
}
@Override
public int id() {
return ID;
}
@Override
public int size() {
return IPCPacketBase.strLen(worldName) + 1;
}
}

View File

@ -0,0 +1,63 @@
package net.lax1dude.eaglercraft.v1_8.sp.ipc;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* Copyright (c) 2023-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.
*
*/
public class IPCPacket06RenameWorldNBT implements IPCPacketBase {
public static final int ID = 0x06;
public String worldName;
public String displayName;
public boolean duplicate;
public IPCPacket06RenameWorldNBT() {
}
public IPCPacket06RenameWorldNBT(String worldName, String displayName, boolean duplicate) {
this.worldName = worldName;
this.displayName = displayName;
this.duplicate = duplicate;
}
@Override
public void deserialize(DataInput bin) throws IOException {
this.worldName = bin.readUTF();
this.displayName = bin.readUTF();
this.duplicate = bin.readBoolean();
}
@Override
public void serialize(DataOutput bin) throws IOException {
bin.writeUTF(worldName);
bin.writeUTF(displayName);
bin.writeBoolean(duplicate);
}
@Override
public int id() {
return ID;
}
@Override
public int size() {
return IPCPacketBase.strLen(worldName) + IPCPacketBase.strLen(displayName) + 1;
}
}

View File

@ -0,0 +1,72 @@
package net.lax1dude.eaglercraft.v1_8.sp.ipc;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* Copyright (c) 2023-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.
*
*/
public class IPCPacket07ImportWorld implements IPCPacketBase {
public static final int ID = 0x07;
public byte gameRules;
public String worldName;
public byte[] worldData;
public byte worldFormat;
public static final byte WORLD_FORMAT_EAG = 0x00;
public static final byte WORLD_FORMAT_MCA = 0x01;
public IPCPacket07ImportWorld() {
}
public IPCPacket07ImportWorld(String worldName, byte[] worldData, byte worldFormat, byte gameRules) {
this.worldName = worldName;
this.worldData = worldData;
this.worldFormat = worldFormat;
this.gameRules = gameRules;
}
@Override
public void deserialize(DataInput bin) throws IOException {
worldName = bin.readUTF();
worldData = new byte[bin.readInt()];
worldFormat = bin.readByte();
gameRules = bin.readByte();
bin.readFully(worldData);
}
@Override
public void serialize(DataOutput bin) throws IOException {
bin.writeUTF(worldName);
bin.writeInt(worldData.length);
bin.writeByte(worldFormat);
bin.writeByte(gameRules);
bin.write(worldData);
}
@Override
public int id() {
return ID;
}
@Override
public int size() {
return IPCPacketBase.strLen(worldName) + worldData.length + 6;
}
}

View File

@ -0,0 +1,57 @@
package net.lax1dude.eaglercraft.v1_8.sp.ipc;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* Copyright (c) 2023-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.
*
*/
public class IPCPacket09RequestResponse implements IPCPacketBase {
public static final int ID = 0x09;
public byte[] response;
public IPCPacket09RequestResponse() {
}
public IPCPacket09RequestResponse(byte[] dat) {
this.response = dat;
}
@Override
public void deserialize(DataInput bin) throws IOException {
response = new byte[bin.readInt()];
bin.readFully(response);
}
@Override
public void serialize(DataOutput bin) throws IOException {
bin.writeInt(response.length);
bin.write(response);
}
@Override
public int id() {
return ID;
}
@Override
public int size() {
return 4 + response.length;
}
}

View File

@ -0,0 +1,55 @@
package net.lax1dude.eaglercraft.v1_8.sp.ipc;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* Copyright (c) 2023-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.
*
*/
public class IPCPacket0ASetWorldDifficulty implements IPCPacketBase {
public static final int ID = 0x0A;
public byte difficulty;
public IPCPacket0ASetWorldDifficulty() {
}
public IPCPacket0ASetWorldDifficulty(byte difficulty) {
this.difficulty = difficulty;
}
@Override
public void deserialize(DataInput bin) throws IOException {
difficulty = bin.readByte();
}
@Override
public void serialize(DataOutput bin) throws IOException {
bin.writeByte(difficulty);
}
@Override
public int id() {
return ID;
}
@Override
public int size() {
return 1;
}
}

View File

@ -0,0 +1,55 @@
package net.lax1dude.eaglercraft.v1_8.sp.ipc;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* Copyright (c) 2023-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.
*
*/
public class IPCPacket0BPause implements IPCPacketBase {
public static final int ID = 0x0B;
public boolean pause;
public IPCPacket0BPause() {
}
public IPCPacket0BPause(boolean pause) {
this.pause = pause;
}
@Override
public void deserialize(DataInput bin) throws IOException {
pause = bin.readBoolean();
}
@Override
public void serialize(DataOutput bin) throws IOException {
bin.writeBoolean(pause);
}
@Override
public int id() {
return ID;
}
@Override
public int size() {
return 1;
}
}

View File

@ -0,0 +1,59 @@
package net.lax1dude.eaglercraft.v1_8.sp.ipc;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* Copyright (c) 2023-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.
*
*/
public class IPCPacket0CPlayerChannel implements IPCPacketBase {
public static final int ID = 0x0C;
public String channel;
public boolean open;
public IPCPacket0CPlayerChannel() {
}
public IPCPacket0CPlayerChannel(String channel, boolean open) {
this.channel = channel;
this.open = open;
}
@Override
public void deserialize(DataInput bin) throws IOException {
channel = bin.readUTF();
open = bin.readBoolean();
}
@Override
public void serialize(DataOutput bin) throws IOException {
bin.writeUTF(channel);
bin.writeBoolean(open);
}
@Override
public int id() {
return ID;
}
@Override
public int size() {
return IPCPacketBase.strLen(channel) + 1;
}
}

View File

@ -0,0 +1,59 @@
package net.lax1dude.eaglercraft.v1_8.sp.ipc;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* Copyright (c) 2023-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.
*
*/
public class IPCPacket0DProgressUpdate implements IPCPacketBase {
public static final int ID = 0x0D;
public String updateMessage;
public float updateProgress;
public IPCPacket0DProgressUpdate() {
}
public IPCPacket0DProgressUpdate(String updateMessage, float updateProgress) {
this.updateMessage = updateMessage == null ? "" : updateMessage;
this.updateProgress = updateProgress;
}
@Override
public void deserialize(DataInput bin) throws IOException {
updateMessage = bin.readUTF();
updateProgress = bin.readFloat();
}
@Override
public void serialize(DataOutput bin) throws IOException {
bin.writeUTF(updateMessage);
bin.writeFloat(updateProgress);
}
@Override
public int id() {
return ID;
}
@Override
public int size() {
return IPCPacketBase.strLen(updateMessage) + 4;
}
}

View File

@ -0,0 +1,47 @@
package net.lax1dude.eaglercraft.v1_8.sp.ipc;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* Copyright (c) 2023-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.
*
*/
public class IPCPacket0EListWorlds implements IPCPacketBase {
public static final int ID = 0x0E;
public IPCPacket0EListWorlds() {
}
@Override
public void deserialize(DataInput bin) throws IOException {
}
@Override
public void serialize(DataOutput bin) throws IOException {
}
@Override
public int id() {
return ID;
}
@Override
public int size() {
return 0;
}
}

View File

@ -0,0 +1,55 @@
package net.lax1dude.eaglercraft.v1_8.sp.ipc;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* Copyright (c) 2023-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.
*
*/
public class IPCPacket0FListFiles implements IPCPacketBase {
public static final int ID = 0x0F;
public String path;
public IPCPacket0FListFiles() {
}
public IPCPacket0FListFiles(String path) {
this.path = path;
}
@Override
public void deserialize(DataInput bin) throws IOException {
this.path = bin.readUTF();
}
@Override
public void serialize(DataOutput bin) throws IOException {
bin.writeUTF(path);
}
@Override
public int id() {
return ID;
}
@Override
public int size() {
return IPCPacketBase.strLen(path);
}
}

View File

@ -0,0 +1,55 @@
package net.lax1dude.eaglercraft.v1_8.sp.ipc;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* Copyright (c) 2023-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.
*
*/
public class IPCPacket10FileRead implements IPCPacketBase {
public static final int ID = 0x10;
public String file;
public IPCPacket10FileRead() {
}
public IPCPacket10FileRead(String file) {
this.file = file;
}
@Override
public void deserialize(DataInput bin) throws IOException {
file = bin.readUTF();
}
@Override
public void serialize(DataOutput bin) throws IOException {
bin.writeUTF(file);
}
@Override
public int id() {
return ID;
}
@Override
public int size() {
return IPCPacketBase.strLen(file);
}
}

View File

@ -0,0 +1,59 @@
package net.lax1dude.eaglercraft.v1_8.sp.ipc;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* Copyright (c) 2023-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.
*
*/
public class IPCPacket12FileWrite implements IPCPacketBase {
public static final int ID = 0x12;
public String path;
public byte[] data;
public IPCPacket12FileWrite() {
}
public IPCPacket12FileWrite(String path, byte[] data) {
this.path = path;
this.data = data;
}
@Override
public void deserialize(DataInput bin) throws IOException {
path = bin.readUTF();
}
@Override
public void serialize(DataOutput bin) throws IOException {
bin.writeUTF(path);
bin.writeInt(data.length);
bin.write(data);
}
@Override
public int id() {
return ID;
}
@Override
public int size() {
return IPCPacketBase.strLen(path) + 4 + data.length;
}
}

View File

@ -0,0 +1,63 @@
package net.lax1dude.eaglercraft.v1_8.sp.ipc;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* Copyright (c) 2023-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.
*
*/
public class IPCPacket13FileCopyMove implements IPCPacketBase {
public static final int ID = 0x13;
public String fileOldName;
public String fileNewName;
public boolean copy;
public IPCPacket13FileCopyMove() {
}
public IPCPacket13FileCopyMove(String fileOldName, String fileNewName, boolean copy) {
this.fileOldName = fileOldName;
this.fileNewName = fileNewName;
this.copy = copy;
}
@Override
public void deserialize(DataInput bin) throws IOException {
fileOldName = bin.readUTF();
fileNewName = bin.readUTF();
copy = bin.readBoolean();
}
@Override
public void serialize(DataOutput bin) throws IOException {
bin.writeUTF(fileOldName);
bin.writeUTF(fileNewName);
bin.writeBoolean(copy);
}
@Override
public int id() {
return ID;
}
@Override
public int size() {
return IPCPacketBase.strLen(fileOldName) + IPCPacketBase.strLen(fileNewName) + 1;
}
}

View File

@ -0,0 +1,95 @@
package net.lax1dude.eaglercraft.v1_8.sp.ipc;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* Copyright (c) 2023-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.
*
*/
public class IPCPacket14StringList implements IPCPacketBase {
public static final int ID = 0x14;
public static final int FILE_LIST = 0x0;
public static final int LOCALE = 0x1;
public static final int STAT_GUID = 0x2;
public static final int SERVER_TPS = 0x3;
public int opCode;
public final List<String> stringList;
public IPCPacket14StringList() {
stringList = new ArrayList();
}
public IPCPacket14StringList(int opcode, String[] list) {
stringList = new ArrayList();
for(String s : list) {
s = s.trim();
if(s.length() > 0) {
stringList.add(s);
}
}
this.opCode = opcode;
}
public IPCPacket14StringList(int opcode, List<String> list) {
stringList = new ArrayList();
for(String s : list) {
s = s.trim();
if(s.length() > 0) {
stringList.add(s);
}
}
this.opCode = opcode;
}
@Override
public void deserialize(DataInput bin) throws IOException {
stringList.clear();
opCode = bin.readByte();
int len = bin.readInt();
for(int i = 0; i < len; ++i) {
stringList.add(bin.readUTF());
}
}
@Override
public void serialize(DataOutput bin) throws IOException {
bin.writeByte(opCode);
bin.writeInt(stringList.size());
for(String str : stringList) {
bin.writeUTF(str);
}
}
@Override
public int id() {
return ID;
}
@Override
public int size() {
int len = 5;
for(String str : stringList) {
len += IPCPacketBase.strLen(str);
}
return len;
}
}

View File

@ -0,0 +1,58 @@
package net.lax1dude.eaglercraft.v1_8.sp.ipc;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Copyright (c) 2023-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.
*
*/
public class IPCPacket15Crashed implements IPCPacketBase {
public static final int ID = 0x15;
public String crashReport;
public IPCPacket15Crashed() {
}
public IPCPacket15Crashed(String crashReport) {
this.crashReport = crashReport;
}
@Override
public void deserialize(DataInput bin) throws IOException {
crashReport = bin.readUTF();
}
@Override
public void serialize(DataOutput bin) throws IOException {
bin.writeUTF(crashReport);
}
@Override
public int id() {
return ID;
}
@Override
public int size() {
return IPCPacketBase.strLen(crashReport);
}
}

View File

@ -0,0 +1,110 @@
package net.lax1dude.eaglercraft.v1_8.sp.ipc;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.nbt.NBTTagCompound;
/**
* Copyright (c) 2023-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.
*
*/
public class IPCPacket16NBTList implements IPCPacketBase {
public static final int ID = 0x16;
public static final int WORLD_LIST = 0x0;
public int opCode;
public final List<byte[]> tagList;
public final List<NBTTagCompound> nbtTagList;
public IPCPacket16NBTList() {
tagList = new LinkedList();
nbtTagList = new LinkedList();
}
public IPCPacket16NBTList(int opcode, NBTTagCompound[] list) {
this(opcode, Arrays.asList(list));
}
public IPCPacket16NBTList(int opcode, List<NBTTagCompound> list) {
tagList = new LinkedList();
nbtTagList = list;
for(int i = 0, size = list.size(); i < size; ++i) {
NBTTagCompound tag = list.get(i);
try {
ByteArrayOutputStream bao = new ByteArrayOutputStream();
CompressedStreamTools.write(tag, new DataOutputStream(bao));
tagList.add(bao.toByteArray());
}catch(IOException e) {
System.err.println("Failed to write tag '" + tag.getId() + "' (#" + i + ") in IPCPacket16NBTList");
}
}
opCode = opcode;
}
@Override
public void deserialize(DataInput bin) throws IOException {
tagList.clear();
nbtTagList.clear();
opCode = bin.readInt();
int count = bin.readInt();
for(int i = 0; i < count; ++i) {
byte[] toRead = new byte[bin.readInt()];
bin.readFully(toRead);
tagList.add(toRead);
try {
nbtTagList.add(CompressedStreamTools.read(new DataInputStream(new ByteArrayInputStream(toRead))));
}catch(IOException e) {
System.err.println("Failed to read tag #" + i + " in IPCPacket16NBTList");
}
}
}
@Override
public void serialize(DataOutput bin) throws IOException {
bin.writeInt(opCode);
bin.writeInt(tagList.size());
for(byte[] str : tagList) {
bin.writeInt(str.length);
bin.write(str);
}
}
@Override
public int id() {
return ID;
}
@Override
public int size() {
int len = 8;
for(byte[] str : tagList) {
len += 4;
len += str.length;
}
return len;
}
}

View File

@ -0,0 +1,78 @@
package net.lax1dude.eaglercraft.v1_8.sp.ipc;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* Copyright (c) 2023-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.
*
*/
public class IPCPacket17ConfigureLAN implements IPCPacketBase {
public static final int ID = 0x17;
public int gamemode;
public boolean cheats;
public final List<String> iceServers;
public IPCPacket17ConfigureLAN() {
iceServers = new ArrayList();
}
public IPCPacket17ConfigureLAN(int gamemode, boolean cheats, List<String> iceServers) {
this.gamemode = gamemode;
this.cheats = cheats;
this.iceServers = iceServers;
}
@Override
public void deserialize(DataInput bin) throws IOException {
gamemode = bin.readUnsignedByte();
cheats = bin.readBoolean();
iceServers.clear();
int iceCount = bin.readUnsignedByte();
for(int i = 0; i < iceCount; ++i) {
iceServers.add(bin.readUTF());
}
}
@Override
public void serialize(DataOutput bin) throws IOException {
bin.writeByte(gamemode);
bin.writeBoolean(cheats);
bin.writeByte(iceServers.size());
for(int i = 0, l = iceServers.size(); i < l; ++i) {
bin.writeUTF(iceServers.get(i));
}
}
@Override
public int id() {
return ID;
}
@Override
public int size() {
int s = 0;
for(int i = 0, l = iceServers.size(); i < l; ++i) {
s += 2;
s += iceServers.get(i).length();
}
return 2 + 1 + s;
}
}

View File

@ -0,0 +1,55 @@
package net.lax1dude.eaglercraft.v1_8.sp.ipc;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* Copyright (c) 2023-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.
*
*/
public class IPCPacket18ClearPlayers implements IPCPacketBase {
public static final int ID = 0x18;
public String worldName = null;
public IPCPacket18ClearPlayers(String worldName) {
this.worldName = worldName;
}
public IPCPacket18ClearPlayers() {
}
@Override
public void deserialize(DataInput bin) throws IOException {
worldName = bin.readUTF();
}
@Override
public void serialize(DataOutput bin) throws IOException {
bin.writeUTF(worldName);
}
@Override
public int id() {
return ID;
}
@Override
public int size() {
return IPCPacketBase.strLen(worldName);
}
}

View File

@ -0,0 +1,47 @@
package net.lax1dude.eaglercraft.v1_8.sp.ipc;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* Copyright (c) 2023-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.
*
*/
public class IPCPacket19Autosave implements IPCPacketBase {
public static final int ID = 0x19;
public IPCPacket19Autosave() {
}
@Override
public void deserialize(DataInput bin) throws IOException {
}
@Override
public void serialize(DataOutput bin) throws IOException {
}
@Override
public int id() {
return ID;
}
@Override
public int size() {
return 0;
}
}

View File

@ -0,0 +1,64 @@
package net.lax1dude.eaglercraft.v1_8.sp.ipc;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* Copyright (c) 2023-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.
*
*/
public class IPCPacket20LoggerMessage implements IPCPacketBase {
public static final int ID = 0x20;
public String logMessage;
public boolean isError;
public IPCPacket20LoggerMessage() {
}
public IPCPacket20LoggerMessage(String logMessage, boolean isError) {
this.logMessage = logMessage;
this.isError = isError;
}
public IPCPacket20LoggerMessage(String logMessage) {
this.logMessage = logMessage;
this.isError = false;
}
@Override
public void deserialize(DataInput bin) throws IOException {
this.logMessage = bin.readUTF();
this.isError = bin.readBoolean();
}
@Override
public void serialize(DataOutput bin) throws IOException {
bin.writeUTF(this.logMessage);
bin.writeBoolean(this.isError);
}
@Override
public int id() {
return ID;
}
@Override
public int size() {
return IPCPacketBase.strLen(logMessage) + 1;
}
}

View File

@ -0,0 +1,55 @@
package net.lax1dude.eaglercraft.v1_8.sp.ipc;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* Copyright (c) 2023-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.
*
*/
public class IPCPacket21EnableLogging implements IPCPacketBase {
public static final int ID = 0x21;
public boolean enable;
public IPCPacket21EnableLogging() {
}
public IPCPacket21EnableLogging(boolean enable) {
this.enable = enable;
}
@Override
public void deserialize(DataInput bin) throws IOException {
enable = bin.readBoolean();
}
@Override
public void serialize(DataOutput bin) throws IOException {
bin.writeBoolean(enable);
}
@Override
public int id() {
return ID;
}
@Override
public int size() {
return 1;
}
}

View File

@ -0,0 +1,48 @@
package net.lax1dude.eaglercraft.v1_8.sp.ipc;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* Copyright (c) 2023-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.
*
*/
public interface IPCPacketBase {
public void deserialize(DataInput bin) throws IOException;
public void serialize(DataOutput bin) throws IOException;
public int id();
public int size();
public static int strLen(String s) {
int strlen = s.length();
int utflen = 2;
int c;
for (int i = 0; i < strlen; ++i) {
c = s.charAt(i);
if ((c >= 0x0001) && (c <= 0x007F)) {
++utflen;
} else if (c > 0x07FF) {
utflen += 3;
} else {
utflen += 2;
}
}
return utflen;
}
}

View File

@ -0,0 +1,59 @@
package net.lax1dude.eaglercraft.v1_8.sp.ipc;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* Copyright (c) 2023-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.
*
*/
public class IPCPacketFFProcessKeepAlive implements IPCPacketBase {
public static final int ID = 0xFF;
public static final int KEEPALIVE = 0;
public static final int FAILURE = 0xFE;
public static final int EXITED = 0xFC;
public int ack;
public IPCPacketFFProcessKeepAlive() {
}
public IPCPacketFFProcessKeepAlive(int ack) {
this.ack = ack;
}
@Override
public void deserialize(DataInput bin) throws IOException {
ack = bin.readUnsignedByte();
}
@Override
public void serialize(DataOutput bin) throws IOException {
bin.writeByte(ack);
}
@Override
public int id() {
return ID;
}
@Override
public int size() {
return 1;
}
}

View File

@ -0,0 +1,96 @@
package net.lax1dude.eaglercraft.v1_8.sp.ipc;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.function.Supplier;
/**
* Copyright (c) 2023-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.
*
*/
public class IPCPacketManager {
public static final HashMap<Integer, Supplier<IPCPacketBase>> mappings = new HashMap();
public static final IPCInputStream IPC_INPUT_STREAM = new IPCInputStream();
public static final IPCOutputStream IPC_OUTPUT_STREAM = new IPCOutputStream();
public static final DataInputStream IPC_DATA_INPUT_STREAM = new DataInputStream(IPC_INPUT_STREAM);
public static final DataOutputStream IPC_DATA_OUTPUT_STREAM = new DataOutputStream(IPC_OUTPUT_STREAM);
static {
mappings.put(IPCPacket00StartServer.ID, () -> new IPCPacket00StartServer());
mappings.put(IPCPacket01StopServer.ID, () -> new IPCPacket01StopServer());
mappings.put(IPCPacket02InitWorld.ID, () -> new IPCPacket02InitWorld());
mappings.put(IPCPacket03DeleteWorld.ID, () -> new IPCPacket03DeleteWorld());
mappings.put(IPCPacket05RequestData.ID, () -> new IPCPacket05RequestData());
mappings.put(IPCPacket06RenameWorldNBT.ID, () -> new IPCPacket06RenameWorldNBT());
mappings.put(IPCPacket07ImportWorld.ID, () -> new IPCPacket07ImportWorld());
mappings.put(IPCPacket09RequestResponse.ID, () -> new IPCPacket09RequestResponse());
mappings.put(IPCPacket0ASetWorldDifficulty.ID, () -> new IPCPacket0ASetWorldDifficulty());
mappings.put(IPCPacket0BPause.ID, () -> new IPCPacket0BPause());
mappings.put(IPCPacket0CPlayerChannel.ID, () -> new IPCPacket0CPlayerChannel());
mappings.put(IPCPacket0DProgressUpdate.ID, () -> new IPCPacket0DProgressUpdate());
mappings.put(IPCPacket0EListWorlds.ID, () -> new IPCPacket0EListWorlds());
mappings.put(IPCPacket0FListFiles.ID, () -> new IPCPacket0FListFiles());
mappings.put(IPCPacket10FileRead.ID, () -> new IPCPacket10FileRead());
mappings.put(IPCPacket12FileWrite.ID, () -> new IPCPacket12FileWrite());
mappings.put(IPCPacket13FileCopyMove.ID, () -> new IPCPacket13FileCopyMove());
mappings.put(IPCPacket14StringList.ID, () -> new IPCPacket14StringList());
mappings.put(IPCPacket15Crashed.ID, () -> new IPCPacket15Crashed());
mappings.put(IPCPacket16NBTList.ID, () -> new IPCPacket16NBTList());
mappings.put(IPCPacket17ConfigureLAN.ID, () -> new IPCPacket17ConfigureLAN());
mappings.put(IPCPacket18ClearPlayers.ID, () -> new IPCPacket18ClearPlayers());
mappings.put(IPCPacket19Autosave.ID, () -> new IPCPacket19Autosave());
mappings.put(IPCPacket20LoggerMessage.ID, () -> new IPCPacket20LoggerMessage());
mappings.put(IPCPacket21EnableLogging.ID, () -> new IPCPacket21EnableLogging());
mappings.put(IPCPacketFFProcessKeepAlive.ID, () -> new IPCPacketFFProcessKeepAlive());
}
public static byte[] IPCSerialize(IPCPacketBase pkt) throws IOException {
IPC_OUTPUT_STREAM.feedBuffer(new byte[pkt.size() + 1], pkt.getClass().getSimpleName());
IPC_OUTPUT_STREAM.write(pkt.id());
pkt.serialize(IPC_DATA_OUTPUT_STREAM);
return IPC_OUTPUT_STREAM.returnBuffer();
}
public static IPCPacketBase IPCDeserialize(byte[] pkt) throws IOException {
IPC_INPUT_STREAM.feedBuffer(pkt);
int i = IPC_INPUT_STREAM.read();
Supplier<IPCPacketBase> pk = mappings.get(Integer.valueOf(i));
if(pk == null) {
throw new IOException("Packet type 0x" + Integer.toHexString(i) + " doesn't exist");
}
IPCPacketBase p = pk.get();
IPC_INPUT_STREAM.nameBuffer(p.getClass().getSimpleName());
p.deserialize(IPC_DATA_INPUT_STREAM);
int lo = IPC_INPUT_STREAM.getLeftoverCount();
if(lo > 0) {
System.err.println("Packet type 0x" + Integer.toHexString(i) + " class '" + p.getClass().getSimpleName() + "' was size " + (pkt.length - 1) + " but only " + (pkt.length - 1 - lo) + " bytes were read");
}
return p;
}
}

View File

@ -0,0 +1,413 @@
package net.lax1dude.eaglercraft.v1_8.sp.lan;
import net.lax1dude.eaglercraft.v1_8.EagUtils;
import net.lax1dude.eaglercraft.v1_8.EaglerZLIB;
import net.lax1dude.eaglercraft.v1_8.internal.EnumEaglerConnectionState;
import net.lax1dude.eaglercraft.v1_8.internal.PlatformWebRTC;
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
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.EaglercraftNetworkManager;
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayServerSocket;
import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.*;
import net.minecraft.network.EnumPacketDirection;
import net.minecraft.network.Packet;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.ChatComponentTranslation;
import net.minecraft.util.IChatComponent;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
/**
* Copyright (c) 2022-2024 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
* 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.
*
*/
public class LANClientNetworkManager extends EaglercraftNetworkManager {
private static final Logger logger = LogManager.getLogger("LANClientNetworkManager");
private static final int PRE = 0, INIT = 1, SENT_ICE_CANDIDATE = 2, SENT_DESCRIPTION = 3;
public static final int fragmentSize = 0xFF00;
private static final String[] initStateNames = new String[] { "PRE", "INIT", "SENT_ICE_CANDIDATE", "SENT_DESCRIPTION" };
public final String displayCode;
public final String displayRelay;
private boolean firstPacket = true;
private LANClientNetworkManager(String displayCode, String displayRelay) {
super("");
this.displayCode = displayCode;
this.displayRelay = displayRelay;
this.nethandler = null;
}
@Override
public void connect() {
fragmentedPacket.clear();
firstPacket = true;
}
@Override
public EnumEaglerConnectionState getConnectStatus() {
return clientDisconnected ? EnumEaglerConnectionState.CLOSED : EnumEaglerConnectionState.CONNECTED;
}
public static LANClientNetworkManager connectToWorld(RelayServerSocket sock, String displayCode, String displayRelay) {
PlatformWebRTC.clearLANClientState();
int connectState = PRE;
IPacket pkt;
mainLoop: while(!sock.isClosed()) {
if((pkt = sock.readPacket()) != null) {
if(pkt instanceof IPacket00Handshake) {
if(connectState == PRE) {
// %%%%%% Process IPacket00Handshake %%%%%%
logger.info("Relay [{}|{}] recieved handshake, client id: {}", displayRelay, displayCode, ((IPacket00Handshake)pkt).connectionCode);
connectState = INIT;
}else {
sock.close();
logger.error("Relay [{}|{}] unexpected packet: IPacket00Handshake in state {}", displayRelay, displayCode, initStateNames[connectState]);
return null;
}
}else if(pkt instanceof IPacket01ICEServers) {
if(connectState == INIT) {
// %%%%%% Process IPacket01ICEServers %%%%%%
IPacket01ICEServers ipkt = (IPacket01ICEServers) pkt;
// print servers
logger.info("Relay [{}|{}] provided ICE servers:", displayRelay, displayCode);
List<String> servers = new ArrayList();
for(ICEServerSet.RelayServer srv : ipkt.servers) {
logger.info("Relay [{}|{}] {}: {}", displayRelay, displayCode, srv.type.name(), srv.address);
servers.add(srv.getICEString());
}
// process
PlatformWebRTC.clientLANSetICEServersAndConnect(servers.toArray(new String[servers.size()]));
// await result
long lm = System.currentTimeMillis();
do {
String c = PlatformWebRTC.clientLANAwaitDescription();
if(c != null) {
logger.info("Relay [{}|{}] client sent description", displayRelay, displayCode);
// 'this.descriptionHandler' was called, send result:
sock.writePacket(new IPacket04Description("", c));
connectState = SENT_DESCRIPTION;
continue mainLoop;
}
EagUtils.sleep(20l);
}while(System.currentTimeMillis() - lm < 5000l);
// no description was sent
sock.close();
logger.error("Relay [{}|{}] client provide description timeout", displayRelay, displayCode);
return null;
}else {
sock.close();
logger.error("Relay [{}|{}] unexpected packet: IPacket01ICEServers in state {}", displayRelay, displayCode, initStateNames[connectState]);
return null;
}
}else if(pkt instanceof IPacket03ICECandidate) {
if(connectState == SENT_ICE_CANDIDATE) {
// %%%%%% Process IPacket03ICECandidate %%%%%%
IPacket03ICECandidate ipkt = (IPacket03ICECandidate) pkt;
// process
logger.info("Relay [{}|{}] recieved server ICE candidate", displayRelay, displayCode);
PlatformWebRTC.clientLANSetICECandidate(ipkt.candidate);
// await result
long lm = System.currentTimeMillis();
do {
if(PlatformWebRTC.clientLANAwaitChannel()) {
logger.info("Relay [{}|{}] client opened data channel", displayRelay, displayCode);
// 'this.remoteDataChannelHandler' was called, success
sock.writePacket(new IPacket05ClientSuccess(ipkt.peerId));
sock.close();
return new LANClientNetworkManager(displayCode, displayRelay);
}
EagUtils.sleep(20l);
}while(System.currentTimeMillis() - lm < 5000l);
// no channel was opened
sock.writePacket(new IPacket06ClientFailure(ipkt.peerId));
sock.close();
logger.error("Relay [{}|{}] client open data channel timeout", displayRelay, displayCode);
return null;
}else {
sock.close();
logger.error("Relay [{}|{}] unexpected packet: IPacket03ICECandidate in state {}", displayRelay, displayCode, initStateNames[connectState]);
return null;
}
}else if(pkt instanceof IPacket04Description) {
if(connectState == SENT_DESCRIPTION) {
// %%%%%% Process IPacket04Description %%%%%%
IPacket04Description ipkt = (IPacket04Description) pkt;
// process
logger.info("Relay [{}|{}] recieved server description", displayRelay, displayCode);
PlatformWebRTC.clientLANSetDescription(ipkt.description);
// await result
long lm = System.currentTimeMillis();
do {
String c = PlatformWebRTC.clientLANAwaitICECandidate();
if(c != null) {
logger.info("Relay [{}|{}] client sent ICE candidate", displayRelay, displayCode);
// 'this.iceCandidateHandler' was called, send result:
sock.writePacket(new IPacket03ICECandidate("", c));
connectState = SENT_ICE_CANDIDATE;
continue mainLoop;
}
EagUtils.sleep(20l);
}while(System.currentTimeMillis() - lm < 5000l);
// no ice candidates were sent
sock.close();
logger.error("Relay [{}|{}] client provide ICE candidate timeout", displayRelay, displayCode);
return null;
}else {
sock.close();
logger.error("Relay [{}|{}] unexpected packet: IPacket04Description in state {}", displayRelay, displayCode, initStateNames[connectState]);
return null;
}
}else if(pkt instanceof IPacketFFErrorCode) {
// %%%%%% Process IPacketFFErrorCode %%%%%%
IPacketFFErrorCode ipkt = (IPacketFFErrorCode) pkt;
logger.error("Relay [{}|{}] connection failed: {}({}): {}", displayRelay, displayCode, IPacketFFErrorCode.code2string(ipkt.code), ipkt.code, ipkt.desc);
Throwable t;
while((t = sock.getException()) != null) {
logger.error(t);
}
sock.close();
return null;
}else {
// %%%%%% Unexpected Packet %%%%%%
logger.error("Relay [{}|{}] unexpected packet: {}", displayRelay, displayCode, pkt.getClass().getSimpleName());
sock.close();
return null;
}
}
EagUtils.sleep(20l);
}
return null;
}
@Override
public void sendPacket(Packet pkt) {
if(!isChannelOpen()) {
logger.error("Packet was sent on a closed connection: {}", pkt.getClass().getSimpleName());
return;
}
int i;
try {
i = packetState.getPacketId(EnumPacketDirection.SERVERBOUND, pkt);
}catch(Throwable t) {
logger.error("Incorrect packet for state: {}", pkt.getClass().getSimpleName());
return;
}
temporaryBuffer.clear();
temporaryBuffer.writeVarIntToBuffer(i);
try {
pkt.writePacketData(temporaryBuffer);
}catch(IOException ex) {
logger.error("Failed to write packet {}!", pkt.getClass().getSimpleName());
return;
}
int len = temporaryBuffer.readableBytes();
int fragmentSizeN1 = fragmentSize - 1;
if(len > fragmentSizeN1) {
do {
int readLen = len > fragmentSizeN1 ? fragmentSizeN1 : len;
byte[] frag = new byte[readLen + 1];
temporaryBuffer.readBytes(frag, 1, readLen);
frag[0] = temporaryBuffer.readableBytes() == 0 ? (byte)0 : (byte)1;
PlatformWebRTC.clientLANSendPacket(frag);
}while((len = temporaryBuffer.readableBytes()) > 0);
}else {
byte[] bytes = new byte[len + 1];
bytes[0] = 0;
temporaryBuffer.readBytes(bytes, 1, len);
PlatformWebRTC.clientLANSendPacket(bytes);
}
}
@Override
public boolean isLocalChannel() {
return true;
}
@Override
public boolean isChannelOpen() {
if (PlatformWebRTC.clientLANClosed()) {
clientDisconnected = true;
}
return !clientDisconnected;
}
private List<byte[]> fragmentedPacket = new ArrayList();
@Override
public void processReceivedPackets() throws IOException {
if(this.nethandler != null) {
List<byte[]> packets = PlatformWebRTC.clientLANReadAllPacket();
if(packets == null) {
return;
}
for(byte[] data : packets) {
byte[] fullData;
boolean compressed = false;
if (data[0] == 0 || data[0] == 2) {
if(fragmentedPacket.isEmpty()) {
fullData = new byte[data.length - 1];
System.arraycopy(data, 1, fullData, 0, fullData.length);
}else {
fragmentedPacket.add(data);
int len = 0;
int fragCount = fragmentedPacket.size();
for(int i = 0; i < fragCount; ++i) {
len += fragmentedPacket.get(i).length - 1;
}
fullData = new byte[len];
len = 0;
for(int i = 0; i < fragCount; ++i) {
byte[] f = fragmentedPacket.get(i);
System.arraycopy(f, 1, fullData, len, f.length - 1);
len += f.length - 1;
}
fragmentedPacket.clear();
}
compressed = data[0] == 2;
} else if (data[0] == 1) {
fragmentedPacket.add(data);
continue;
} else {
logger.error("Recieved {} byte fragment of unknown type: {}", data.length, ((int)data[0] & 0xFF));
continue;
}
if(compressed) {
if(fullData.length < 4) {
throw new IOException("Recieved invalid " + fullData.length + " byte compressed packet");
}
ByteArrayInputStream bi = new ByteArrayInputStream(fullData);
int i = (bi.read() << 24) | (bi.read() << 16) | (bi.read() << 8) | bi.read();
InputStream inflaterInputStream = EaglerZLIB.newInflaterInputStream(bi);
fullData = new byte[i];
inflaterInputStream.read(fullData);
}
if(firstPacket) {
// 1.5 kick packet
if(fullData.length == 31 && fullData[0] == (byte)0xFF && fullData[1] == (byte)0x00 && fullData[2] == (byte)0x0E) {
logger.error("Detected a 1.5 LAN server!");
this.closeChannel(new ChatComponentTranslation("singleplayer.outdatedLANServerKick"));
firstPacket = false;
return;
}
firstPacket = false;
}
ByteBuf nettyBuffer = Unpooled.buffer(fullData, fullData.length);
nettyBuffer.writerIndex(fullData.length);
PacketBuffer input = new PacketBuffer(nettyBuffer);
int pktId = input.readVarIntFromBuffer();
Packet pkt;
try {
pkt = packetState.getPacket(EnumPacketDirection.CLIENTBOUND, pktId);
}catch(IllegalAccessException | InstantiationException ex) {
throw new IOException("Recieved a packet with type " + pktId + " which is invalid!");
}
if(pkt == null) {
throw new IOException("Recieved packet type " + pktId + " which is undefined in state " + packetState);
}
try {
pkt.readPacketData(input);
}catch(Throwable t) {
throw new IOException("Failed to read packet type '" + pkt.getClass().getSimpleName() + "'", t);
}
try {
pkt.processPacket(nethandler);
}catch(Throwable t) {
logger.error("Failed to process {}! It'll be skipped for debug purposes.", pkt.getClass().getSimpleName());
logger.error(t);
}
}
}
}
@Override
public void closeChannel(IChatComponent reason) {
if(!PlatformWebRTC.clientLANClosed()) {
PlatformWebRTC.clientLANCloseConnection();
}
if(nethandler != null) {
nethandler.onDisconnect(reason);
}
clientDisconnected = true;
}
@Override
public boolean checkDisconnected() {
if(PlatformWebRTC.clientLANClosed()) {
clientDisconnected = false;
try {
processReceivedPackets(); // catch kick message
} catch (IOException e) {
}
doClientDisconnect(new ChatComponentTranslation("disconnect.endOfStream"));
}
return clientDisconnected;
}
}

View File

@ -0,0 +1,175 @@
package net.lax1dude.eaglercraft.v1_8.sp.lan;
import java.util.Iterator;
import java.util.List;
import net.lax1dude.eaglercraft.v1_8.EagUtils;
import net.lax1dude.eaglercraft.v1_8.internal.IPCPacketData;
import net.lax1dude.eaglercraft.v1_8.internal.PlatformWebRTC;
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
import net.lax1dude.eaglercraft.v1_8.sp.SingleplayerServerController;
import net.lax1dude.eaglercraft.v1_8.sp.internal.ClientPlatformSingleplayer;
import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.IPacket03ICECandidate;
import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.IPacket04Description;
/**
* Copyright (c) 2022-2024 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
* 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.
*
*/
class LANClientPeer {
private static final Logger logger = LogManager.getLogger("LANClientPeer");
private static final int PRE = 0, SENT_ICE_CANDIDATE = 2, SENT_DESCRIPTION = 3, CONNECTED = 4, CLOSED = 5;
protected final String clientId;
protected int state = PRE;
protected boolean dead = false;
protected LANClientPeer(String clientId) {
this.clientId = clientId;
PlatformWebRTC.serverLANCreatePeer(clientId);
}
protected void handleICECandidates(String candidates) {
if(state == SENT_DESCRIPTION) {
PlatformWebRTC.serverLANPeerICECandidates(clientId, candidates);
long millis = System.currentTimeMillis();
do {
LANPeerEvent evt;
if((evt = PlatformWebRTC.serverLANGetEvent(clientId)) != null) {
if(evt instanceof LANPeerEvent.LANPeerICECandidateEvent) {
LANServerController.lanRelaySocket.writePacket(new IPacket03ICECandidate(clientId, ((LANPeerEvent.LANPeerICECandidateEvent)evt).candidates));
state = SENT_ICE_CANDIDATE;
return;
}else if(evt instanceof LANPeerEvent.LANPeerDisconnectEvent) {
logger.error("LAN client '{}' disconnected while waiting for server ICE candidates", clientId);
}else {
logger.error("LAN client '{}' had an accident: {}", clientId, evt.getClass().getSimpleName());
}
disconnect();
return;
}
EagUtils.sleep(20l);
}while(System.currentTimeMillis() - millis < 5000l);
logger.error("Getting server ICE candidates for '{}' timed out!", clientId);
disconnect();
}else {
logger.error("Relay [{}] unexpected IPacket03ICECandidate for '{}'", LANServerController.lanRelaySocket.getURI(), clientId);
}
}
protected void handleDescription(String description) {
if(state == PRE) {
PlatformWebRTC.serverLANPeerDescription(clientId, description);
long millis = System.currentTimeMillis();
do {
LANPeerEvent evt;
if((evt = PlatformWebRTC.serverLANGetEvent(clientId)) != null) {
if(evt instanceof LANPeerEvent.LANPeerDescriptionEvent) {
LANServerController.lanRelaySocket.writePacket(new IPacket04Description(clientId, ((LANPeerEvent.LANPeerDescriptionEvent)evt).description));
state = SENT_DESCRIPTION;
return;
}else if(evt instanceof LANPeerEvent.LANPeerDisconnectEvent) {
logger.error("LAN client '{}' disconnected while waiting for server description", clientId);
}else {
logger.error("LAN client '{}' had an accident: {}", clientId, evt.getClass().getSimpleName());
}
disconnect();
return;
}
EagUtils.sleep(20l);
}while(System.currentTimeMillis() - millis < 5000l);
logger.error("Getting server description for '{}' timed out!", clientId);
disconnect();
}else {
logger.error("Relay [{}] unexpected IPacket04Description for '{}'", LANServerController.lanRelaySocket.getURI(), clientId);
}
}
protected void handleSuccess() {
if(state == SENT_ICE_CANDIDATE) {
long millis = System.currentTimeMillis();
do {
LANPeerEvent evt;
while((evt = PlatformWebRTC.serverLANGetEvent(clientId)) != null && evt instanceof LANPeerEvent.LANPeerICECandidateEvent) {
// skip ice candidates
}
if(evt != null) {
if(evt instanceof LANPeerEvent.LANPeerDataChannelEvent) {
SingleplayerServerController.openPlayerChannel(clientId);
state = CONNECTED;
return;
}else if(evt instanceof LANPeerEvent.LANPeerDisconnectEvent) {
logger.error("LAN client '{}' disconnected while waiting for connection", clientId);
}else {
logger.error("LAN client '{}' had an accident: {}", clientId, evt.getClass().getSimpleName());
}
disconnect();
return;
}
EagUtils.sleep(20l);
}while(System.currentTimeMillis() - millis < 5000l);
logger.error("Getting server description for '{}' timed out!", clientId);
disconnect();
}else {
logger.error("Relay [{}] unexpected IPacket05ClientSuccess for '{}'", LANServerController.lanRelaySocket.getURI(), clientId);
}
}
protected void handleFailure() {
if(state == SENT_ICE_CANDIDATE) {
logger.error("Client '{}' failed to connect", clientId);
disconnect();
}else {
logger.error("Relay [{}] unexpected IPacket06ClientFailure for '{}'", LANServerController.lanRelaySocket.getURI(), clientId);
}
}
protected void update() {
if(state == CONNECTED) {
List<LANPeerEvent> l = PlatformWebRTC.serverLANGetAllEvent(clientId);
if(l == null) {
return;
}
Iterator<LANPeerEvent> itr = l.iterator();
while(state == CONNECTED && itr.hasNext()) {
LANPeerEvent evt = itr.next();
if(evt instanceof LANPeerEvent.LANPeerPacketEvent) {
ClientPlatformSingleplayer.sendPacket(new IPCPacketData(clientId, ((LANPeerEvent.LANPeerPacketEvent)evt).payload));
}else if(evt instanceof LANPeerEvent.LANPeerDisconnectEvent) {
logger.info("LAN client '{}' disconnected", clientId);
disconnect();
}else {
logger.error("LAN client '{}' had an accident: {}", clientId, evt.getClass().getSimpleName());
disconnect();
}
}
}
}
protected void disconnect() {
if(!dead) {
if(state == CONNECTED) {
SingleplayerServerController.closePlayerChannel(clientId);
}
state = CLOSED;
PlatformWebRTC.serverLANDisconnectPeer(clientId);
dead = true;
}
}
}

View File

@ -0,0 +1,103 @@
package net.lax1dude.eaglercraft.v1_8.sp.lan;
/**
* Copyright (c) 2022-2024 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
* 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.
*
*/
public interface LANPeerEvent {
String getPeerId();
public static class LANPeerICECandidateEvent implements LANPeerEvent {
public final String clientId;
public final String candidates;
public LANPeerICECandidateEvent(String clientId, String candidates) {
this.clientId = clientId;
this.candidates = candidates;
}
@Override
public String getPeerId() {
return clientId;
}
}
public static class LANPeerDescriptionEvent implements LANPeerEvent {
public final String clientId;
public final String description;
public LANPeerDescriptionEvent(String clientId, String description) {
this.clientId = clientId;
this.description = description;
}
@Override
public String getPeerId() {
return clientId;
}
}
public static class LANPeerDataChannelEvent implements LANPeerEvent {
public final String clientId;
public LANPeerDataChannelEvent(String clientId) {
this.clientId = clientId;
}
@Override
public String getPeerId() {
return clientId;
}
}
public static class LANPeerPacketEvent implements LANPeerEvent {
public final String clientId;
public final byte[] payload;
public LANPeerPacketEvent(String clientId, byte[] payload) {
this.clientId = clientId;
this.payload = payload;
}
@Override
public String getPeerId() {
return clientId;
}
}
public static class LANPeerDisconnectEvent implements LANPeerEvent {
public final String clientId;
public LANPeerDisconnectEvent(String clientId) {
this.clientId = clientId;
}
@Override
public String getPeerId() {
return clientId;
}
}
}

View File

@ -0,0 +1,207 @@
package net.lax1dude.eaglercraft.v1_8.sp.lan;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import net.lax1dude.eaglercraft.v1_8.EagUtils;
import net.lax1dude.eaglercraft.v1_8.internal.PlatformWebRTC;
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayManager;
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayServerSocket;
import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.*;
/**
* Copyright (c) 2022-2024 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
* 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.
*
*/
public class LANServerController {
public static final Logger logger = LogManager.getLogger("IntegratedServerLAN");
public static final List<String> currentICEServers = new ArrayList();
static RelayServerSocket lanRelaySocket = null;
private static String currentCode = null;
public static String shareToLAN(Consumer<String> progressCallback, String worldName, boolean worldHidden) {
currentCode = null;
RelayServerSocket sock = RelayManager.relayManager.getWorkingRelay((str) -> progressCallback.accept("Connecting: " + str),
RelayManager.preferredRelayVersion, worldName + (worldHidden ? ";1" : ";0"));
if(sock == null) {
lanRelaySocket = null;
return null;
}else {
progressCallback.accept("Opening: " + sock.getURI());
IPacket00Handshake hs = (IPacket00Handshake)sock.readPacket();
lanRelaySocket = sock;
String code = hs.connectionCode;
logger.info("Relay [{}] connected as 'server', code: {}", sock.getURI(), code);
progressCallback.accept("Opened '" + code + "' on " + sock.getURI());
long millis = System.currentTimeMillis();
do {
if(sock.isClosed()) {
logger.info("Relay [{}] connection lost", sock.getURI());
lanRelaySocket = null;
return null;
}
IPacket pkt = sock.readPacket();
if(pkt != null) {
if(pkt instanceof IPacket01ICEServers) {
IPacket01ICEServers ipkt = (IPacket01ICEServers)pkt;
logger.info("Relay [{}] provided ICE servers:", sock.getURI());
currentICEServers.clear();
for(net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.ICEServerSet.RelayServer srv : ipkt.servers) {
logger.info("Relay [{}] {}: {}", sock.getURI(), srv.type.name(), srv.address);
currentICEServers.add(srv.getICEString());
}
PlatformWebRTC.serverLANInitializeServer(currentICEServers.toArray(new String[currentICEServers.size()]));
return currentCode = code;
}else {
logger.error("Relay [{}] unexpected packet: {}", sock.getURI(), pkt.getClass().getSimpleName());
closeLAN();
return null;
}
}
EagUtils.sleep(50l);
}while(System.currentTimeMillis() - millis < 1000l);
logger.info("Relay [{}] relay provide ICE servers timeout", sock.getURI());
closeLAN();
return null;
}
}
public static String getCurrentURI() {
return lanRelaySocket == null ? "<disconnected>" : lanRelaySocket.getURI();
}
public static String getCurrentCode() {
return currentCode == null ? "<undefined>" : currentCode;
}
public static void closeLAN() {
closeLANNoKick();
cleanupLAN();
if (isLANOpen()) {
PlatformWebRTC.serverLANCloseServer();
}
}
public static void closeLANNoKick() {
if(lanRelaySocket != null) {
lanRelaySocket.close();
lanRelaySocket = null;
currentCode = null;
}
}
public static void cleanupLAN() {
Iterator<LANClientPeer> itr = clients.values().iterator();
while(itr.hasNext()) {
itr.next().disconnect();
}
clients.clear();
}
public static boolean hasPeers() {
return PlatformWebRTC.countPeers() > 0;
}
public static boolean isHostingLAN() {
return lanRelaySocket != null || PlatformWebRTC.countPeers() > 0;
}
public static boolean isLANOpen() {
return lanRelaySocket != null;
}
private static final Map<String, LANClientPeer> clients = new HashMap();
public static void updateLANServer() {
if(lanRelaySocket != null) {
IPacket pkt;
while((pkt = lanRelaySocket.readPacket()) != null) {
if(pkt instanceof IPacket02NewClient) {
IPacket02NewClient ipkt = (IPacket02NewClient) pkt;
if(clients.containsKey(ipkt.clientId)) {
logger.error("Relay [{}] relay provided duplicate client '{}'", lanRelaySocket.getURI(), ipkt.clientId);
}else {
clients.put(ipkt.clientId, new LANClientPeer(ipkt.clientId));
}
}else if(pkt instanceof IPacket03ICECandidate) {
IPacket03ICECandidate ipkt = (IPacket03ICECandidate) pkt;
LANClientPeer c = clients.get(ipkt.peerId);
if(c != null) {
c.handleICECandidates(ipkt.candidate);
}else {
logger.error("Relay [{}] relay sent IPacket03ICECandidate for unknown client '{}'", lanRelaySocket.getURI(), ipkt.peerId);
}
}else if(pkt instanceof IPacket04Description) {
IPacket04Description ipkt = (IPacket04Description) pkt;
LANClientPeer c = clients.get(ipkt.peerId);
if(c != null) {
c.handleDescription(ipkt.description);
}else {
logger.error("Relay [{}] relay sent IPacket04Description for unknown client '{}'", lanRelaySocket.getURI(), ipkt.peerId);
}
}else if(pkt instanceof IPacket05ClientSuccess) {
IPacket05ClientSuccess ipkt = (IPacket05ClientSuccess) pkt;
LANClientPeer c = clients.get(ipkt.clientId);
if(c != null) {
c.handleSuccess();
}else {
logger.error("Relay [{}] relay sent IPacket05ClientSuccess for unknown client '{}'", lanRelaySocket.getURI(), ipkt.clientId);
}
}else if(pkt instanceof IPacket06ClientFailure) {
IPacket06ClientFailure ipkt = (IPacket06ClientFailure) pkt;
LANClientPeer c = clients.get(ipkt.clientId);
if(c != null) {
c.handleFailure();
}else {
logger.error("Relay [{}] relay sent IPacket06ClientFailure for unknown client '{}'", lanRelaySocket.getURI(), ipkt.clientId);
}
}else if(pkt instanceof IPacketFFErrorCode) {
IPacketFFErrorCode ipkt = (IPacketFFErrorCode) pkt;
logger.error("Relay [{}] error code thrown: {}({}): {}", lanRelaySocket.getURI(), IPacketFFErrorCode.code2string(ipkt.code), ipkt.code, ipkt.desc);
Throwable t;
while((t = lanRelaySocket.getException()) != null) {
logger.error(t);
}
}else {
logger.error("Relay [{}] unexpected packet: {}", lanRelaySocket.getURI(), pkt.getClass().getSimpleName());
}
}
if(lanRelaySocket.isClosed()) {
lanRelaySocket = null;
}
}
Iterator<LANClientPeer> itr = clients.values().iterator();
while(itr.hasNext()) {
LANClientPeer cl = itr.next();
cl.update();
if(cl.dead) {
itr.remove();
}
}
}
public static boolean supported() {
return PlatformWebRTC.supported();
}
}

View File

@ -0,0 +1,166 @@
package net.lax1dude.eaglercraft.v1_8.sp.lan;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import net.lax1dude.eaglercraft.v1_8.internal.PlatformWebRTC;
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayManager;
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayServer;
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayWorldsQuery;
import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.IPacket07LocalWorlds;
/**
* Copyright (c) 2022-2024 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
* 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.
*
*/
public class LANServerList {
private final List<LanServer> lanServersList = new LinkedList();
private final Map<String, RelayWorldsQuery> lanServersQueryList = new LinkedHashMap();
private final Set<String> deadURIs = new HashSet();
private long lastRefresh = 0l;
private int refreshCounter = 0;
public boolean update() {
long millis = System.currentTimeMillis();
if(millis - lastRefresh > 20000l) {
if(++refreshCounter < 10) {
refresh();
}else {
lastRefresh = millis;
}
}else {
boolean changed = false;
Iterator<Entry<String,RelayWorldsQuery>> itr = lanServersQueryList.entrySet().iterator();
while(itr.hasNext()) {
Entry<String,RelayWorldsQuery> etr = itr.next();
String uri = etr.getKey();
RelayWorldsQuery q = etr.getValue();
if(!q.isQueryOpen()) {
itr.remove();
if(q.isQueryFailed()) {
deadURIs.add(uri);
Iterator<LanServer> itr2 = lanServersList.iterator();
while(itr2.hasNext()) {
if(itr2.next().lanServerRelay.address.equals(uri)) {
itr2.remove();
changed = true;
}
}
}else {
RelayServer rl = RelayManager.relayManager.getByURI(uri);
Iterator<LanServer> itr2 = lanServersList.iterator();
while(itr2.hasNext()) {
LanServer l = itr2.next();
if(l.lanServerRelay.address.equals(uri)) {
l.flagged = false;
}
}
if(rl != null) {
Iterator<IPacket07LocalWorlds.LocalWorld> itr3 = q.getWorlds().iterator();
yee: while(itr3.hasNext()) {
IPacket07LocalWorlds.LocalWorld l = itr3.next();
itr2 = lanServersList.iterator();
while(itr2.hasNext()) {
LanServer l2 = itr2.next();
if(l2.lanServerRelay.address.equals(uri) && l2.lanServerCode.equals(l.worldCode)) {
l2.lanServerMotd = l.worldName;
l2.flagged = true;
continue yee;
}
}
lanServersList.add(new LanServer(l.worldName, rl, l.worldCode));
changed = true;
}
}
itr2 = lanServersList.iterator();
while(itr2.hasNext()) {
LanServer l = itr2.next();
if(l.lanServerRelay.address.equals(uri)) {
if(!l.flagged) {
itr2.remove();
changed = true;
}
}
}
}
}
}
return changed;
}
return false;
}
public void forceRefresh() {
deadURIs.clear();
refreshCounter = 0;
refresh();
}
private void refresh() {
lastRefresh = System.currentTimeMillis();
if(PlatformWebRTC.supported()) {
for(int i = 0, l = RelayManager.relayManager.count(); i < l; ++i) {
RelayServer srv = RelayManager.relayManager.get(i);
if(!lanServersQueryList.containsKey(srv.address) && !deadURIs.contains(srv.address)) {
lanServersQueryList.put(srv.address, PlatformWebRTC.openRelayWorldsQuery(srv.address));
}
}
}
}
public LanServer getServer(int idx) {
return lanServersList.get(idx);
}
public int countServers() {
return lanServersList.size();
}
public class LanServer {
private String lanServerMotd;
private RelayServer lanServerRelay;
private String lanServerCode;
protected boolean flagged = true;
protected LanServer(String lanServerMotd, RelayServer lanServerRelay, String lanServerCode) {
this.lanServerMotd = lanServerMotd;
this.lanServerRelay = lanServerRelay;
this.lanServerCode = lanServerCode;
}
public String getLanServerMotd() {
return lanServerMotd;
}
public RelayServer getLanServerRelay() {
return lanServerRelay;
}
public String getLanServerCode() {
return lanServerCode;
}
}
}

View File

@ -0,0 +1,30 @@
package net.lax1dude.eaglercraft.v1_8.sp.relay;
/**
* Copyright (c) 2022-2024 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
* 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.
*
*/
public class RelayEntry {
public final String address;
public final String comment;
public final boolean primary;
public RelayEntry(String address, String comment, boolean primary) {
this.address = address;
this.comment = comment;
this.primary = primary;
}
}

View File

@ -0,0 +1,360 @@
package net.lax1dude.eaglercraft.v1_8.sp.relay;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Consumer;
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
import net.lax1dude.eaglercraft.v1_8.EagUtils;
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.IPacket;
import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.IPacket00Handshake;
import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.IPacketFFErrorCode;
import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
/**
* Copyright (c) 2022-2024 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
* 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.
*
*/
public class RelayManager {
public static final Logger logger = LogManager.getLogger("RelayManager");
public static final RelayManager relayManager = new RelayManager();
public static final int preferredRelayVersion = 1;
private final List<RelayServer> relays = new ArrayList();
private long lastPingThrough = 0l;
public void load(NBTTagList relayConfig) {
relays.clear();
if(relayConfig != null && relayConfig.tagCount() > 0) {
boolean gotAPrimary = false;
for(int i = 0, l = relayConfig.tagCount(); i < l; ++i) {
NBTTagCompound relay = relayConfig.getCompoundTagAt(i);
boolean p = relay.getBoolean("primary");
if(p) {
if(gotAPrimary) {
p = false;
}else {
gotAPrimary = true;
}
}
relays.add(new RelayServer(relay.getString("addr"), relay.getString("comment"), p));
}
}
sort();
}
public void save() {
try {
NBTTagList lst = new NBTTagList();
for(int i = 0, l = relays.size(); i < l; ++i) {
RelayServer srv = relays.get(i);
NBTTagCompound etr = new NBTTagCompound();
etr.setString("addr", srv.address);
etr.setString("comment", srv.comment);
etr.setBoolean("primary", srv.isPrimary());
lst.appendTag(etr);
}
NBTTagCompound nbttagcompound = new NBTTagCompound();
nbttagcompound.setTag("relays", lst);
ByteArrayOutputStream bao = new ByteArrayOutputStream();
CompressedStreamTools.writeCompressed(nbttagcompound, bao);
EagRuntime.setStorage("r", bao.toByteArray());
} catch (Exception exception) {
logger.error("Couldn\'t save relay list!");
logger.error(exception);
}
}
private void sort() {
if(relays.isEmpty()) {
return;
}
int j = -1;
for(int i = 0, l = relays.size(); i < l; ++i) {
if(relays.get(i).isPrimary()) {
if(j == -1) {
j = i;
}else {
relays.get(i).setPrimary(false);
}
}
}
if(j == -1) {
boolean found = false;
for(int i = 0, l = relays.size(); i < l; ++i) {
RelayServer srv = relays.get(i);
if(srv.getPing() > 0l) {
found = true;
srv.setPrimary(true);
break;
}
}
if(!found) {
relays.get(0).setPrimary(true);
}
}else {
RelayServer srv = relays.remove(j);
relays.add(0, srv);
}
}
public void ping() {
lastPingThrough = System.currentTimeMillis();
for(int i = 0, l = relays.size(); i < l; ++i) {
relays.get(i).ping();
}
}
public void update() {
for(int i = 0, l = relays.size(); i < l; ++i) {
relays.get(i).update();
}
}
public void close() {
for(int i = 0, l = relays.size(); i < l; ++i) {
relays.get(i).close();
}
}
public int count() {
return relays.size();
}
public RelayServer get(int idx) {
return relays.get(idx);
}
public void add(String addr, String comment, boolean primary) {
lastPingThrough = 0l;
int i = relays.size();
relays.add(new RelayServer(addr, comment, false));
if(primary) {
setPrimary0(i);
}
save();
}
public void addNew(String addr, String comment, boolean primary) {
lastPingThrough = 0l;
int i = relays.size();
int j = primary || i == 0 ? 0 : 1;
RelayServer newServer = new RelayServer(addr, comment, false);
relays.add(j, newServer);
newServer.ping();
if(primary) {
setPrimary0(j);
}
save();
}
public void setPrimary(int idx) {
setPrimary0(idx);
save();
}
private void setPrimary0(int idx) {
if(idx >= 0 && idx < relays.size()) {
for(int i = 0, l = relays.size(); i < l; ++i) {
RelayServer srv = relays.get(i);
if(srv.isPrimary()) {
srv.setPrimary(false);
}
}
RelayServer pr = relays.remove(idx);
pr.setPrimary(true);
relays.add(0, pr);
}
}
public void remove(int idx) {
RelayServer srv = relays.remove(idx);
srv.close();
sort();
save();
}
public RelayServer getPrimary() {
if(!relays.isEmpty()) {
for(int i = 0, l = relays.size(); i < l; ++i) {
RelayServer srv = relays.get(i);
if(srv.isPrimary()) {
return srv;
}
}
sort();
save();
return getPrimary();
}else {
return null;
}
}
public RelayServerSocket connectHandshake(RelayServer relay, int type, String code) {
RelayServerSocket sock = relay.openSocket();
while(!sock.isClosed()) {
if(sock.isOpen()) {
sock.writePacket(new IPacket00Handshake(type, preferredRelayVersion, code));
while(!sock.isClosed()) {
IPacket pkt = sock.nextPacket();
if(pkt != null) {
if(pkt instanceof IPacket00Handshake) {
return sock;
}else if(pkt instanceof IPacketFFErrorCode) {
IPacketFFErrorCode ipkt = (IPacketFFErrorCode) pkt;
logger.error("Relay [{}] failed: {}({}): {}", relay.address, IPacketFFErrorCode.code2string(ipkt.code), ipkt.code, ipkt.desc);
Throwable t;
while((t = sock.getException()) != null) {
logger.error(t);
}
sock.close();
return null;
}else {
logger.error("Relay [{}] unexpected packet: {}", relay.address, pkt.getClass().getSimpleName());
sock.close();
return null;
}
}
EagUtils.sleep(20l);
}
}
EagUtils.sleep(20l);
}
logger.error("Relay [{}] connection failed!", relay.address);
Throwable t;
while((t = sock.getException()) != null) {
logger.error(t);
}
return null;
}
private final List<RelayServer> brokenServers = new LinkedList();
public RelayServerSocket getWorkingRelay(Consumer<String> progressCallback, int type, String code) {
brokenServers.clear();
if(!relays.isEmpty()) {
long millis = System.currentTimeMillis();
if(millis - lastPingThrough < 10000l) {
RelayServer relay = getPrimary();
if(relay.getPing() > 0l && relay.getPingCompatible().isCompatible()) {
progressCallback.accept(relay.address);
RelayServerSocket sock = connectHandshake(relay, type, code);
if(sock != null) {
if(!sock.isFailed()) {
return sock;
}
}else {
brokenServers.add(relay);
}
}
for(int i = 0, l = relays.size(); i < l; ++i) {
RelayServer relayEtr = relays.get(i);
if(relayEtr != relay) {
if(relayEtr.getPing() > 0l && relayEtr.getPingCompatible().isCompatible()) {
progressCallback.accept(relayEtr.address);
RelayServerSocket sock = connectHandshake(relayEtr, type, code);
if(sock != null) {
if(!sock.isFailed()) {
return sock;
}
}else {
brokenServers.add(relayEtr);
}
}
}
}
}
return getWorkingCodeRelayActive(progressCallback, type, code);
}else {
return null;
}
}
private RelayServerSocket getWorkingCodeRelayActive(Consumer<String> progressCallback, int type, String code) {
if(!relays.isEmpty()) {
for(int i = 0, l = relays.size(); i < l; ++i) {
RelayServer srv = relays.get(i);
if(!brokenServers.contains(srv)) {
progressCallback.accept(srv.address);
RelayServerSocket sock = connectHandshake(srv, type, code);
if(sock != null) {
if(!sock.isFailed()) {
return sock;
}
}else {
brokenServers.add(srv);
}
}
}
return null;
}else {
return null;
}
}
public void loadDefaults() {
int setPrimary = relays.size();
eee: for(RelayEntry etr : EagRuntime.getConfiguration().getRelays()) {
for(RelayServer exEtr : relays) {
if(exEtr.address.equalsIgnoreCase(etr.address)) {
continue eee;
}
}
relays.add(new RelayServer(etr));
}
setPrimary(setPrimary);
}
public String makeNewRelayName() {
String str = "Relay Server #" + (relays.size() + 1);
for(int i = relays.size() + 2, l = relays.size() + 50; i < l; ++i) {
if(str.equalsIgnoreCase("Relay Server #" + i)) {
str = "Relay Server #" + (i + 1);
}
}
eee: while(true) {
for(int i = 0, l = relays.size(); i < l; ++i) {
if(str.equalsIgnoreCase(relays.get(i).comment)) {
str = str + "_";
continue eee;
}
}
break;
}
return str;
}
public RelayServer getByURI(String uri) {
Iterator<RelayServer> itr = relays.iterator();
while(itr.hasNext()) {
RelayServer rl = itr.next();
if(rl.address.equals(uri)) {
return rl;
}
}
return null;
}
}

View File

@ -0,0 +1,43 @@
package net.lax1dude.eaglercraft.v1_8.sp.relay;
/**
* Copyright (c) 2022-2024 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
* 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.
*
*/
public interface RelayQuery {
enum RateLimit {
NONE, FAILED, BLOCKED, FAILED_POSSIBLY_LOCKED, LOCKED, NOW_LOCKED
}
enum VersionMismatch {
COMPATIBLE, CLIENT_OUTDATED, RELAY_OUTDATED, UNKNOWN;
public boolean isCompatible() {
return this == COMPATIBLE;
}
}
boolean isQueryOpen();
boolean isQueryFailed();
RateLimit isQueryRateLimit();
void close();
int getVersion();
String getComment();
String getBrand();
long getPing();
VersionMismatch getCompatible();
}

View File

@ -0,0 +1,144 @@
package net.lax1dude.eaglercraft.v1_8.sp.relay;
import net.lax1dude.eaglercraft.v1_8.EagUtils;
import net.lax1dude.eaglercraft.v1_8.internal.PlatformWebRTC;
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayQuery.VersionMismatch;
import net.minecraft.client.Minecraft;
/**
* Copyright (c) 2022-2024 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
* 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.
*
*/
public class RelayServer {
public final String address;
public final String comment;
private boolean primary;
private RelayQuery query = null;
private int queriedVersion = -1;
private String queriedComment;
private String queriedVendor;
private VersionMismatch queriedCompatible;
private long ping = 0l;
private long workingPing = 0l;
public long lastPing = 0l;
public RelayServer(String address, String comment, boolean primary) {
this.address = address;
this.comment = comment;
this.primary = primary;
}
public RelayServer(RelayEntry etr) {
this(etr.address, etr.comment, etr.primary);
}
public boolean isPrimary() {
return primary;
}
public void setPrimary(boolean primaryee) {
primary = primaryee;
}
public long getPing() {
return ping;
}
public long getWorkingPing() {
return workingPing;
}
public int getPingVersion() {
return queriedVersion;
}
public String getPingComment() {
return queriedComment == null ? "" : queriedComment;
}
public String getPingVendor() {
return queriedVendor == null ? "" : queriedVendor;
}
public VersionMismatch getPingCompatible() {
return queriedCompatible;
}
public void pingBlocking() {
ping();
while(getPing() < 0l) {
EagUtils.sleep(250l);
update();
}
}
public void ping() {
if(PlatformWebRTC.supported()) {
close();
query = PlatformWebRTC.openRelayQuery(address);
queriedVersion = -1;
queriedComment = null;
queriedVendor = null;
queriedCompatible = VersionMismatch.UNKNOWN;
ping = -1l;
}else {
query = null;
queriedVersion = 1;
queriedComment = "LAN NOT SUPPORTED";
queriedVendor = "NULL";
queriedCompatible = VersionMismatch.CLIENT_OUTDATED;
ping = -1l;
}
}
public void update() {
if(query != null && !query.isQueryOpen()) {
if(query.isQueryFailed()) {
queriedVersion = -1;
queriedComment = null;
queriedVendor = null;
queriedCompatible = VersionMismatch.UNKNOWN;
ping = 0l;
}else {
queriedVersion = query.getVersion();
queriedComment = query.getComment();
queriedVendor = query.getBrand();
ping = query.getPing();
queriedCompatible = query.getCompatible();
workingPing = ping;
}
lastPing = System.currentTimeMillis();
query = null;
}
}
public void close() {
if(query != null && query.isQueryOpen()) {
query.close();
query = null;
queriedVersion = -1;
queriedComment = null;
queriedVendor = null;
queriedCompatible = VersionMismatch.UNKNOWN;
ping = 0l;
}
}
public RelayServerSocket openSocket() {
return PlatformWebRTC.openRelayConnection(address, Minecraft.getMinecraft().gameSettings.relayTimeout * 1000);
}
}

View File

@ -0,0 +1,38 @@
package net.lax1dude.eaglercraft.v1_8.sp.relay;
import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.IPacket;
/**
* Copyright (c) 2022-2024 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
* 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.
*
*/
public interface RelayServerSocket {
boolean isOpen();
boolean isClosed();
void close();
boolean isFailed();
Throwable getException();
void writePacket(IPacket pkt);
IPacket readPacket();
IPacket nextPacket();
RelayQuery.RateLimit getRatelimitHistory();
String getURI();
}

View File

@ -0,0 +1,34 @@
package net.lax1dude.eaglercraft.v1_8.sp.relay;
import java.util.List;
import net.lax1dude.eaglercraft.v1_8.sp.relay.RelayQuery.VersionMismatch;
import net.lax1dude.eaglercraft.v1_8.sp.relay.pkt.IPacket07LocalWorlds;
/**
* Copyright (c) 2022-2024 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
* 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.
*
*/
public interface RelayWorldsQuery {
boolean isQueryOpen();
boolean isQueryFailed();
RelayQuery.RateLimit isQueryRateLimit();
void close();
List<IPacket07LocalWorlds.LocalWorld> getWorlds();
VersionMismatch getCompatible();
}

View File

@ -0,0 +1,55 @@
package net.lax1dude.eaglercraft.v1_8.sp.relay.pkt;
/**
* Copyright (c) 2022 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.
*
*/
public class ICEServerSet {
public static enum RelayType {
STUN, TURN;
}
public static class RelayServer {
public final RelayType type;
public final String address;
public final String username;
public final String password;
protected RelayServer(RelayType type, String address, String username, String password) {
this.type = type;
this.address = address;
this.username = username;
this.password = password;
}
protected RelayServer(RelayType type, String address) {
this.type = type;
this.address = address;
this.username = null;
this.password = null;
}
public String getICEString() {
if(username == null) {
return address;
}else {
return address + ";" + username + ";" + password;
}
}
}
}

View File

@ -0,0 +1,165 @@
package net.lax1dude.eaglercraft.v1_8.sp.relay.pkt;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
/**
* Copyright (c) 2022 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.
*
*/
public class IPacket {
private static final Logger logger = LogManager.getLogger("RelayPacket");
private static final Map<Integer,Class<? extends IPacket>> definedPacketClasses = new HashMap();
private static final Map<Class<? extends IPacket>,Integer> definedPacketIds = new HashMap();
private static void register(int id, Class<? extends IPacket> clazz) {
definedPacketClasses.put(id, clazz);
definedPacketIds.put(clazz, id);
}
static {
register(0x00, IPacket00Handshake.class);
register(0x01, IPacket01ICEServers.class);
register(0x02, IPacket02NewClient.class);
register(0x03, IPacket03ICECandidate.class);
register(0x04, IPacket04Description.class);
register(0x05, IPacket05ClientSuccess.class);
register(0x06, IPacket06ClientFailure.class);
register(0x07, IPacket07LocalWorlds.class);
register(0x69, IPacket69Pong.class);
register(0x70, IPacket70SpecialUpdate.class);
register(0xFE, IPacketFEDisconnectClient.class);
register(0xFF, IPacketFFErrorCode.class);
}
public static IPacket readPacket(DataInputStream input) throws IOException {
int i = input.read();
try {
Class<? extends IPacket> clazz = definedPacketClasses.get(i);
if(clazz == null) {
throw new IOException("Unknown packet type: " + i);
}
IPacket pkt = clazz.newInstance();
pkt.read(input);
return pkt;
} catch (InstantiationException | IllegalAccessException e) {
throw new IOException("Unknown packet type: " + i);
}
}
public static byte[] writePacket(IPacket packet) throws IOException {
Integer i = definedPacketIds.get(packet.getClass());
if(i != null) {
int len = packet.packetLength();
ByteArrayOutputStream bao = len == -1 ? new ByteArrayOutputStream() :
new ByteArrayOutputStream(len + 1);
bao.write(i);
packet.write(new DataOutputStream(bao));
byte[] ret = bao.toByteArray();
if(len != -1 && ret.length != len + 1) {
logger.error("writePacket buffer for packet {} {} by {} bytes", packet.getClass().getSimpleName(),
(len + 1 < ret.length ? "overflowed" : "underflowed"),
(len + 1 < ret.length ? ret.length - len - 1 : len + 1 - ret.length));
}
return ret;
}else {
throw new IOException("Unknown packet type: " + packet.getClass().getSimpleName());
}
}
public void read(DataInputStream input) throws IOException {
}
public void write(DataOutputStream output) throws IOException {
}
public int packetLength() {
return -1;
}
public static String readASCII(InputStream is, int len) throws IOException {
char[] ret = new char[len];
for(int i = 0; i < len; ++i) {
int j = is.read();
if(j < 0) {
return null;
}
ret[i] = (char)j;
}
return new String(ret);
}
public static void writeASCII(OutputStream is, String txt) throws IOException {
for(int i = 0, l = txt.length(); i < l; ++i) {
is.write((int)txt.charAt(i));
}
}
public static String readASCII8(InputStream is) throws IOException {
int i = is.read();
if(i < 0) {
return null;
}else {
return readASCII(is, i);
}
}
public static void writeASCII8(OutputStream is, String txt) throws IOException {
if(txt == null) {
is.write(0);
}else {
int l = txt.length();
is.write(l);
for(int i = 0; i < l; ++i) {
is.write((int)txt.charAt(i));
}
}
}
public static String readASCII16(InputStream is) throws IOException {
int hi = is.read();
int lo = is.read();
if(hi < 0 || lo < 0) {
return null;
}else {
return readASCII(is, (hi << 8) | lo);
}
}
public static void writeASCII16(OutputStream is, String txt) throws IOException {
if(txt == null) {
is.write(0);
is.write(0);
}else {
int l = txt.length();
is.write((l >> 8) & 0xFF);
is.write(l & 0xFF);
for(int i = 0; i < l; ++i) {
is.write((int)txt.charAt(i));
}
}
}
}

View File

@ -0,0 +1,57 @@
package net.lax1dude.eaglercraft.v1_8.sp.relay.pkt;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
/**
* Copyright (c) 2022 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.
*
*/
public class IPacket00Handshake extends IPacket {
public int connectionType = 0;
public int connectionVersion = 1;
public String connectionCode = null;
public IPacket00Handshake() {
}
public IPacket00Handshake(int connectionType, int connectionVersion,
String connectionCode) {
this.connectionType = connectionType;
this.connectionVersion = connectionVersion;
this.connectionCode = connectionCode;
}
@Override
public void read(DataInputStream input) throws IOException {
connectionType = input.read();
connectionVersion = input.read();
connectionCode = IPacket.readASCII8(input);
}
@Override
public void write(DataOutputStream output) throws IOException {
output.write(connectionType);
output.write(connectionVersion);
IPacket.writeASCII8(output, connectionCode);
}
@Override
public int packetLength() {
return 1 + 1 + (connectionCode != null ? 1 + connectionCode.length() : 0);
}
}

View File

@ -0,0 +1,53 @@
package net.lax1dude.eaglercraft.v1_8.sp.relay.pkt;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
/**
* Copyright (c) 2022 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.
*
*/
public class IPacket01ICEServers extends IPacket {
public final Collection<ICEServerSet.RelayServer> servers;
public IPacket01ICEServers() {
servers = new ArrayList();
}
public void read(DataInputStream input) throws IOException {
servers.clear();
int l = input.readUnsignedShort();
for(int i = 0; i < l; ++i) {
char type = (char)input.read();
ICEServerSet.RelayType typeEnum;
if(type == 'S') {
typeEnum = ICEServerSet.RelayType.STUN;
}else if(type == 'T') {
typeEnum = ICEServerSet.RelayType.TURN;
}else {
throw new IOException("Unknown/Unsupported Relay Type: '" + type + "'");
}
servers.add(new ICEServerSet.RelayServer(
typeEnum,
readASCII16(input),
readASCII8(input),
readASCII8(input)
));
}
}
}

View File

@ -0,0 +1,36 @@
package net.lax1dude.eaglercraft.v1_8.sp.relay.pkt;
import java.io.DataInputStream;
import java.io.IOException;
/**
* Copyright (c) 2022 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.
*
*/
public class IPacket02NewClient extends IPacket {
public String clientId;
public IPacket02NewClient(String clientId) {
this.clientId = clientId;
}
public IPacket02NewClient() {
}
public void read(DataInputStream input) throws IOException {
clientId = readASCII8(input);
}
}

View File

@ -0,0 +1,49 @@
package net.lax1dude.eaglercraft.v1_8.sp.relay.pkt;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
/**
* Copyright (c) 2022 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.
*
*/
public class IPacket03ICECandidate extends IPacket {
public String peerId;
public String candidate;
public IPacket03ICECandidate(String peerId, String desc) {
this.peerId = peerId;
this.candidate = desc;
}
public IPacket03ICECandidate() {
}
public void read(DataInputStream input) throws IOException {
peerId = readASCII8(input);
candidate = readASCII16(input);
}
public void write(DataOutputStream output) throws IOException {
writeASCII8(output, peerId);
writeASCII16(output, candidate);
}
public int packetLength() {
return 1 + peerId.length() + 2 + candidate.length();
}
}

View File

@ -0,0 +1,49 @@
package net.lax1dude.eaglercraft.v1_8.sp.relay.pkt;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
/**
* Copyright (c) 2022 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.
*
*/
public class IPacket04Description extends IPacket {
public String peerId;
public String description;
public IPacket04Description(String peerId, String desc) {
this.peerId = peerId;
this.description = desc;
}
public IPacket04Description() {
}
public void read(DataInputStream input) throws IOException {
peerId = readASCII8(input);
description = readASCII16(input);
}
public void write(DataOutputStream output) throws IOException {
writeASCII8(output, peerId);
writeASCII16(output, description);
}
public int packetLength() {
return 1 + peerId.length() + 2 + description.length();
}
}

View File

@ -0,0 +1,45 @@
package net.lax1dude.eaglercraft.v1_8.sp.relay.pkt;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
/**
* Copyright (c) 2022 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.
*
*/
public class IPacket05ClientSuccess extends IPacket {
public String clientId;
public IPacket05ClientSuccess() {
}
public IPacket05ClientSuccess(String clientId) {
this.clientId = clientId;
}
public void read(DataInputStream input) throws IOException {
clientId = readASCII8(input);
}
public void write(DataOutputStream output) throws IOException {
writeASCII8(output, clientId);
}
public int packetLength() {
return 1 + clientId.length();
}
}

View File

@ -0,0 +1,45 @@
package net.lax1dude.eaglercraft.v1_8.sp.relay.pkt;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
/**
* Copyright (c) 2022 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.
*
*/
public class IPacket06ClientFailure extends IPacket {
public String clientId;
public IPacket06ClientFailure() {
}
public IPacket06ClientFailure(String clientId) {
this.clientId = clientId;
}
public void read(DataInputStream input) throws IOException {
clientId = readASCII8(input);
}
public void write(DataOutputStream output) throws IOException {
writeASCII8(output, clientId);
}
public int packetLength() {
return 1 + clientId.length();
}
}

View File

@ -0,0 +1,50 @@
package net.lax1dude.eaglercraft.v1_8.sp.relay.pkt;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* Copyright (c) 2022 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.
*
*/
public class IPacket07LocalWorlds extends IPacket {
public static class LocalWorld {
public final String worldName;
public final String worldCode;
public LocalWorld(String worldName, String worldCode) {
this.worldName = worldName;
this.worldCode = worldCode;
}
}
public final List<LocalWorld> worldsList;
public IPacket07LocalWorlds() {
this.worldsList = new ArrayList();
}
public void read(DataInputStream input) throws IOException {
int l = input.read();
for(int i = 0; i < l; ++i) {
worldsList.add(new LocalWorld(readASCII8(input), readASCII8(input)));
}
}
}

View File

@ -0,0 +1,45 @@
package net.lax1dude.eaglercraft.v1_8.sp.relay.pkt;
import java.io.DataInputStream;
import java.io.IOException;
/**
* Copyright (c) 2022 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.
*
*/
public class IPacket69Pong extends IPacket {
public int protcolVersion;
public String comment;
public String brand;
public IPacket69Pong(int protcolVersion, String comment, String brand) {
if(comment.length() > 255) {
comment = comment.substring(0, 256);
}
this.protcolVersion = protcolVersion;
this.comment = comment;
this.brand = brand;
}
public IPacket69Pong() {
}
public void read(DataInputStream output) throws IOException {
protcolVersion = output.read();
comment = readASCII8(output);
brand = readASCII8(output);
}
}

View File

@ -0,0 +1,55 @@
package net.lax1dude.eaglercraft.v1_8.sp.relay.pkt;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
/**
* 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.
*
*/
public class IPacket70SpecialUpdate extends IPacket {
public static final int OPERATION_UPDATE_CERTIFICATE = 0x69;
public int operation;
public byte[] updatePacket;
public IPacket70SpecialUpdate() {
}
public IPacket70SpecialUpdate(int operation, byte[] updatePacket) {
this.operation = operation;
this.updatePacket = updatePacket;
}
@Override
public void read(DataInputStream input) throws IOException {
operation = input.read();
updatePacket = new byte[input.readUnsignedShort()];
input.read(updatePacket);
}
@Override
public void write(DataOutputStream output) throws IOException {
output.write(operation);
output.writeShort(updatePacket.length);
output.write(updatePacket);
}
@Override
public int packetLength() {
return 3 + updatePacket.length;
}
}

View File

@ -0,0 +1,67 @@
package net.lax1dude.eaglercraft.v1_8.sp.relay.pkt;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
/**
* Copyright (c) 2022 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.
*
*/
public class IPacketFEDisconnectClient extends IPacket {
public static final int TYPE_FINISHED_SUCCESS = 0x00;
public static final int TYPE_FINISHED_FAILED = 0x01;
public static final int TYPE_TIMEOUT = 0x02;
public static final int TYPE_INVALID_OPERATION = 0x03;
public static final int TYPE_INTERNAL_ERROR = 0x04;
public static final int TYPE_SERVER_DISCONNECT = 0x05;
public static final int TYPE_UNKNOWN = 0xFF;
public String clientId;
public int code;
public String reason;
public IPacketFEDisconnectClient() {
}
public IPacketFEDisconnectClient(String clientId, int code, String reason) {
this.clientId = clientId;
this.code = code;
this.reason = reason;
}
public void read(DataInputStream input) throws IOException {
clientId = readASCII8(input);
code = input.read();
reason = readASCII16(input);
}
public void write(DataOutputStream output) throws IOException {
writeASCII8(output, clientId);
output.write(code);
writeASCII16(output, reason);
}
public int packetLength() {
return -1;
}
public static final ByteBuffer ratelimitPacketTooMany = ByteBuffer.wrap(new byte[] { (byte)0xFC, (byte)0x00 });
public static final ByteBuffer ratelimitPacketBlock = ByteBuffer.wrap(new byte[] { (byte)0xFC, (byte)0x01 });
public static final ByteBuffer ratelimitPacketBlockLock = ByteBuffer.wrap(new byte[] { (byte)0xFC, (byte)0x02 });
public static final ByteBuffer ratelimitPacketLocked = ByteBuffer.wrap(new byte[] { (byte)0xFC, (byte)0x03 });
}

View File

@ -0,0 +1,82 @@
package net.lax1dude.eaglercraft.v1_8.sp.relay.pkt;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
/**
* Copyright (c) 2022 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.
*
*/
public class IPacketFFErrorCode extends IPacket {
public static final int TYPE_INTERNAL_ERROR = 0x00;
public static final int TYPE_PROTOCOL_VERSION = 0x01;
public static final int TYPE_INVALID_PACKET = 0x02;
public static final int TYPE_ILLEGAL_OPERATION = 0x03;
public static final int TYPE_CODE_LENGTH = 0x04;
public static final int TYPE_INCORRECT_CODE = 0x05;
public static final int TYPE_SERVER_DISCONNECTED = 0x06;
public static final int TYPE_UNKNOWN_CLIENT = 0x07;
public static final String[] packetTypes = new String[0x08];
static {
packetTypes[TYPE_INTERNAL_ERROR] = "TYPE_INTERNAL_ERROR";
packetTypes[TYPE_PROTOCOL_VERSION] = "TYPE_PROTOCOL_VERSION";
packetTypes[TYPE_INVALID_PACKET] = "TYPE_INVALID_PACKET";
packetTypes[TYPE_ILLEGAL_OPERATION] = "TYPE_ILLEGAL_OPERATION";
packetTypes[TYPE_CODE_LENGTH] = "TYPE_CODE_LENGTH";
packetTypes[TYPE_INCORRECT_CODE] = "TYPE_INCORRECT_CODE";
packetTypes[TYPE_SERVER_DISCONNECTED] = "TYPE_SERVER_DISCONNECTED";
packetTypes[TYPE_UNKNOWN_CLIENT] = "TYPE_UNKNOWN_CLIENT";
}
public static String code2string(int i) {
if(i >= 0 || i < packetTypes.length) {
return packetTypes[i];
}else {
return "UNKNOWN";
}
}
public int code;
public String desc;
public IPacketFFErrorCode() {
}
public IPacketFFErrorCode(int code, String desc) {
this.code = code;
this.desc = desc;
}
@Override
public void read(DataInputStream input) throws IOException {
code = input.read();
desc = readASCII16(input);
}
@Override
public void write(DataOutputStream input) throws IOException {
input.write(code);
writeASCII16(input, desc);
}
@Override
public int packetLength() {
return 1 + 2 + desc.length();
}
}

View File

@ -0,0 +1,55 @@
package net.lax1dude.eaglercraft.v1_8.sp.server;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.command.CommandBase;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.command.CommandException;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.command.ICommandSender;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.util.ChatComponentTranslation;
/**
* 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.
*
*/
public class ClientCommandDummy extends CommandBase {
private final String commandName;
private final int permissionLevel;
private final String commandUsage;
public ClientCommandDummy(String commandName, int permissionLevel, String commandUsage) {
this.commandName = commandName;
this.permissionLevel = permissionLevel;
this.commandUsage = commandUsage;
}
@Override
public String getCommandName() {
return commandName;
}
@Override
public int getRequiredPermissionLevel() {
return permissionLevel;
}
@Override
public String getCommandUsage(ICommandSender var1) {
return commandUsage;
}
@Override
public void processCommand(ICommandSender var1, String[] var2) throws CommandException {
var1.addChatMessage(new ChatComponentTranslation("command.clientStub"));
}
}

View File

@ -0,0 +1,71 @@
package net.lax1dude.eaglercraft.v1_8.sp.server;
import java.util.concurrent.Callable;
import net.lax1dude.eaglercraft.v1_8.HString;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.block.Block;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.block.state.IBlockState;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.util.BlockPos;
import net.minecraft.crash.CrashReportCategory;
/**
* Copyright (c) 2023-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.
*
*/
public class CrashReportHelper {
public static void addIntegratedServerBlockInfo(CrashReportCategory category, final BlockPos pos, final Block blockIn,
final int blockData) {
final int i = Block.getIdFromBlock(blockIn);
category.addCrashSectionCallable("Block type", new Callable<String>() {
public String call() throws Exception {
try {
return HString.format("ID #%d (%s // %s)", new Object[] { Integer.valueOf(i),
blockIn.getUnlocalizedName(), blockIn.getClass().getName() });
} catch (Throwable var2) {
return "ID #" + i;
}
}
});
category.addCrashSectionCallable("Block data value", new Callable<String>() {
public String call() throws Exception {
if (blockData < 0) {
return "Unknown? (Got " + blockData + ")";
} else {
String s = HString.format("%4s", new Object[] { Integer.toBinaryString(blockData) }).replace(" ",
"0");
return HString.format("%1$d / 0x%1$X / 0b%2$s", new Object[] { Integer.valueOf(blockData), s });
}
}
});
category.addCrashSectionCallable("Block location", new Callable<String>() {
public String call() throws Exception {
return CrashReportCategory.getCoordinateInfo(new net.minecraft.util.BlockPos(pos.getX(), pos.getY(), pos.getZ()));
}
});
}
public static void addIntegratedServerBlockInfo(CrashReportCategory category, final BlockPos pos, final IBlockState state) {
category.addCrashSectionCallable("Block", new Callable<String>() {
public String call() throws Exception {
return state.toString();
}
});
category.addCrashSectionCallable("Block location", new Callable<String>() {
public String call() throws Exception {
return CrashReportCategory.getCoordinateInfo(new net.minecraft.util.BlockPos(pos.getX(), pos.getY(), pos.getZ()));
}
});
}
}

View File

@ -0,0 +1,117 @@
package net.lax1dude.eaglercraft.v1_8.sp.server;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
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.sp.server.classes.net.minecraft.world.ChunkCoordIntPair;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.world.MinecraftException;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.world.World;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.world.chunk.Chunk;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.world.chunk.storage.AnvilChunkLoader;
import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.nbt.NBTTagCompound;
/**
* Copyright (c) 2023-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.
*
*/
public class EaglerChunkLoader extends AnvilChunkLoader {
private static final String hex = "0123456789ABCDEF";
private static final Logger logger = LogManager.getLogger("EaglerChunkLoader");
public static String getChunkPath(int x, int z) {
int unsignedX = x + 1900000;
int unsignedZ = z + 1900000;
char[] path = new char[12];
for(int i = 5; i >= 0; --i) {
path[i] = hex.charAt((unsignedX >> (i * 4)) & 0xF);
path[i + 6] = hex.charAt((unsignedZ >> (i * 4)) & 0xF);
}
return new String(path);
}
public static ChunkCoordIntPair getChunkCoords(String filename) {
String strX = filename.substring(0, 6);
String strZ = filename.substring(6);
int retX = 0;
int retZ = 0;
for(int i = 0; i < 6; ++i) {
retX |= hex.indexOf(strX.charAt(i)) << (i << 2);
retZ |= hex.indexOf(strZ.charAt(i)) << (i << 2);
}
return new ChunkCoordIntPair(retX - 1900000, retZ - 1900000);
}
public final VFile2 chunkDirectory;
public EaglerChunkLoader(VFile2 chunkDirectory) {
this.chunkDirectory = chunkDirectory;
}
@Override
public Chunk loadChunk(World var1, int var2, int var3) throws IOException {
VFile2 file = new VFile2(chunkDirectory, getChunkPath(var2, var3) + ".dat");
if(!file.exists()) {
return null;
}
try {
NBTTagCompound nbt;
try(InputStream is = file.getInputStream()) {
nbt = CompressedStreamTools.readCompressed(is);
}
return checkedReadChunkFromNBT(var1, var2, var3, nbt);
}catch(Throwable t) {
}
return null;
}
@Override
public void saveChunk(World var1, Chunk var2) throws IOException, MinecraftException {
NBTTagCompound chunkData = new NBTTagCompound();
this.writeChunkToNBT(var2, var1, chunkData);
NBTTagCompound fileData = new NBTTagCompound();
fileData.setTag("Level", chunkData);
VFile2 file = new VFile2(chunkDirectory, getChunkPath(var2.xPosition, var2.zPosition) + ".dat");
try(OutputStream os = file.getOutputStream()) {
CompressedStreamTools.writeCompressed(fileData, os);
}
}
@Override
public void saveExtraChunkData(World var1, Chunk var2) throws IOException {
// ?
}
@Override
public void chunkTick() {
// ?
}
@Override
public void saveExtraData() {
// ?
}
}

View File

@ -0,0 +1,499 @@
package net.lax1dude.eaglercraft.v1_8.sp.server;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
import net.lax1dude.eaglercraft.v1_8.EagUtils;
import net.lax1dude.eaglercraft.v1_8.internal.IPCPacketData;
import net.lax1dude.eaglercraft.v1_8.internal.vfs2.VFile2;
import net.lax1dude.eaglercraft.v1_8.log4j.ILogRedirector;
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
import net.lax1dude.eaglercraft.v1_8.sp.SingleplayerServerController;
import net.lax1dude.eaglercraft.v1_8.sp.ipc.*;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.network.EnumConnectionState;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.server.network.NetHandlerLoginServer;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.util.ChatComponentText;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.util.ReportedException;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.util.StringTranslate;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.world.EnumDifficulty;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.world.WorldSettings;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.world.WorldSettings.GameType;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.world.WorldType;
import net.lax1dude.eaglercraft.v1_8.sp.server.export.WorldConverterEPK;
import net.lax1dude.eaglercraft.v1_8.sp.server.export.WorldConverterMCA;
import net.lax1dude.eaglercraft.v1_8.sp.server.internal.ServerPlatformSingleplayer;
import net.lax1dude.eaglercraft.v1_8.sp.server.socket.IntegratedServerPlayerNetworkManager;
import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.nbt.NBTTagCompound;
/**
* Copyright (c) 2023-2024 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
* 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.
*
*/
public class EaglerIntegratedServerWorker {
public static final Logger logger = LogManager.getLogger("EaglerIntegratedServer");
private static EaglerMinecraftServer currentProcess = null;
private static WorldSettings newWorldSettings = null;
public static final EaglerSaveFormat saveFormat = new EaglerSaveFormat(EaglerSaveFormat.worldsFolder);
private static final Map<String, IntegratedServerPlayerNetworkManager> openChannels = new HashMap();
private static void processAsyncMessageQueue() {
List<IPCPacketData> pktList = ServerPlatformSingleplayer.recieveAllPacket();
if(pktList != null) {
IPCPacketData packetData;
for(int i = 0, l = pktList.size(); i < l; ++i) {
packetData = pktList.get(i);
if(packetData.channel.equals(SingleplayerServerController.IPC_CHANNEL)) {
IPCPacketBase ipc;
try {
ipc = IPCPacketManager.IPCDeserialize(packetData.contents);
}catch(IOException ex) {
throw new RuntimeException("Failed to deserialize IPC packet", ex);
}
handleIPCPacket(ipc);
}else {
IntegratedServerPlayerNetworkManager netHandler = openChannels.get(packetData.channel);
if(netHandler != null) {
netHandler.addRecievedPacket(packetData.contents);
}else {
logger.error("Recieved packet on channel that does not exist: \"{}\"", packetData.channel);
}
}
}
}
}
public static void tick() {
List<IntegratedServerPlayerNetworkManager> ocs = new ArrayList<>(openChannels.values());
for(IntegratedServerPlayerNetworkManager i : ocs) {
i.tick();
}
}
public static EaglerMinecraftServer getServer() {
return currentProcess;
}
public static boolean getChannelExists(String channel) {
return openChannels.containsKey(channel);
}
public static void closeChannel(String channel) {
IntegratedServerPlayerNetworkManager netmanager = openChannels.remove(channel);
if(netmanager != null) {
netmanager.closeChannel(new ChatComponentText("End of stream"));
sendIPCPacket(new IPCPacket0CPlayerChannel(channel, false));
}
}
private static void startPlayerConnnection(String channel) {
if(openChannels.containsKey(channel)) {
logger.error("Tried opening player channel that already exists: {}", channel);
return;
}
if(currentProcess == null) {
logger.error("Tried opening player channel while server is stopped: {}", channel);
return;
}
IntegratedServerPlayerNetworkManager networkmanager = new IntegratedServerPlayerNetworkManager(channel);
networkmanager.setConnectionState(EnumConnectionState.LOGIN);
networkmanager.setNetHandler(new NetHandlerLoginServer(currentProcess, networkmanager));
openChannels.put(channel, networkmanager);
}
private static void handleIPCPacket(IPCPacketBase ipc) {
int id = ipc.id();
try {
switch(id) {
case IPCPacket00StartServer.ID: {
IPCPacket00StartServer pkt = (IPCPacket00StartServer)ipc;
if(!isServerStopped()) {
currentProcess.stopServer();
}
currentProcess = new EaglerMinecraftServer(pkt.worldName, pkt.ownerName, pkt.initialViewDistance, newWorldSettings, pkt.demoMode);
currentProcess.setBaseServerProperties(EnumDifficulty.getDifficultyEnum(pkt.initialDifficulty), newWorldSettings == null ? GameType.SURVIVAL : newWorldSettings.getGameType());
currentProcess.startServer();
String[] worlds = EaglerSaveFormat.worldsList.getAllLines();
if(worlds == null || (worlds.length == 1 && worlds[0].trim().length() <= 0)) {
worlds = null;
}
if(worlds == null) {
EaglerSaveFormat.worldsList.setAllChars(pkt.worldName);
}else {
boolean found = false;
for(String s : worlds) {
if(s.equals(pkt.worldName)) {
found = true;
break;
}
}
if(!found) {
String[] s = new String[worlds.length + 1];
s[0] = pkt.worldName;
System.arraycopy(worlds, 0, s, 1, worlds.length);
EaglerSaveFormat.worldsList.setAllChars(String.join("\n", s));
}
}
sendIPCPacket(new IPCPacketFFProcessKeepAlive(IPCPacket00StartServer.ID));
break;
}
case IPCPacket01StopServer.ID: {
if(currentProcess != null) {
currentProcess.stopServer();
currentProcess = null;
}
sendIPCPacket(new IPCPacketFFProcessKeepAlive(IPCPacket01StopServer.ID));
break;
}
case IPCPacket02InitWorld.ID: {
tryStopServer();
IPCPacket02InitWorld pkt = (IPCPacket02InitWorld)ipc;
newWorldSettings = new WorldSettings(pkt.seed, GameType.getByID(pkt.gamemode), pkt.structures,
pkt.hardcore, WorldType.worldTypes[pkt.worldType]);
newWorldSettings.setWorldName(pkt.worldArgs); // "setWorldName" is actually for setting generator arguments, MCP fucked up
if(pkt.bonusChest) {
newWorldSettings.enableBonusChest();
}
if(pkt.cheats) {
newWorldSettings.enableCommands();
}
break;
}
case IPCPacket03DeleteWorld.ID: {
tryStopServer();
IPCPacket03DeleteWorld pkt = (IPCPacket03DeleteWorld)ipc;
if(!saveFormat.deleteWorldDirectory(pkt.worldName)) {
sendTaskFailed();
break;
}
String[] worldsTxt = EaglerSaveFormat.worldsList.getAllLines();
if(worldsTxt != null) {
List<String> newWorlds = new ArrayList();
for(String str : worldsTxt) {
if(!str.equalsIgnoreCase(pkt.worldName)) {
newWorlds.add(str);
}
}
EaglerSaveFormat.worldsList.setAllChars(String.join("\n", newWorlds));
}
sendIPCPacket(new IPCPacketFFProcessKeepAlive(IPCPacket03DeleteWorld.ID));
break;
}
case IPCPacket05RequestData.ID: {
tryStopServer();
IPCPacket05RequestData pkt = (IPCPacket05RequestData)ipc;
if(pkt.request == IPCPacket05RequestData.REQUEST_LEVEL_EAG) {
sendIPCPacket(new IPCPacket09RequestResponse(WorldConverterEPK.exportWorld(pkt.worldName)));
}else if(pkt.request == IPCPacket05RequestData.REQUEST_LEVEL_MCA) {
sendIPCPacket(new IPCPacket09RequestResponse(WorldConverterMCA.exportWorld(pkt.worldName)));
}else {
logger.error("Unknown IPCPacket05RequestData type {}", ((int)pkt.request & 0xFF));
sendTaskFailed();
}
break;
}
case IPCPacket06RenameWorldNBT.ID: {
tryStopServer();
IPCPacket06RenameWorldNBT pkt = (IPCPacket06RenameWorldNBT)ipc;
boolean b = false;
if(pkt.duplicate) {
b = saveFormat.duplicateWorld(pkt.worldName, pkt.displayName);
}else {
b = saveFormat.renameWorld(pkt.worldName, pkt.displayName);
}
if(!b) {
sendTaskFailed();
break;
}
sendIPCPacket(new IPCPacketFFProcessKeepAlive(IPCPacket06RenameWorldNBT.ID));
break;
}
case IPCPacket07ImportWorld.ID: {
tryStopServer();
IPCPacket07ImportWorld pkt = (IPCPacket07ImportWorld)ipc;
try {
if(pkt.worldFormat == IPCPacket07ImportWorld.WORLD_FORMAT_EAG) {
WorldConverterEPK.importWorld(pkt.worldData, pkt.worldName);
}else if(pkt.worldFormat == IPCPacket07ImportWorld.WORLD_FORMAT_MCA) {
WorldConverterMCA.importWorld(pkt.worldData, pkt.worldName, pkt.gameRules);
}else {
throw new IOException("Client requested an unsupported export format!");
}
sendIPCPacket(new IPCPacketFFProcessKeepAlive(IPCPacket07ImportWorld.ID));
}catch(IOException ex) {
sendIPCPacket(new IPCPacket15Crashed("COULD NOT IMPORT WORLD \"" + pkt.worldName + "\"!!!\n\n" + EagRuntime.getStackTrace(ex) + "\n\nFile is probably corrupt, try a different world"));
sendTaskFailed();
}
break;
}
case IPCPacket0ASetWorldDifficulty.ID: {
IPCPacket0ASetWorldDifficulty pkt = (IPCPacket0ASetWorldDifficulty)ipc;
if(!isServerStopped()) {
currentProcess.setDifficultyForAllWorlds(EnumDifficulty.getDifficultyEnum(pkt.difficulty));
}else {
logger.warn("Client tried to set difficulty while server was stopped");
}
break;
}
case IPCPacket0BPause.ID: {
IPCPacket0BPause pkt = (IPCPacket0BPause)ipc;
if(!isServerStopped()) {
currentProcess.setPaused(pkt.pause);
sendIPCPacket(new IPCPacketFFProcessKeepAlive(IPCPacket0BPause.ID));
}else {
logger.error("Client tried to {} while server was stopped", pkt.pause ? "pause" : "unpause");
sendTaskFailed();
}
break;
}
case IPCPacket0CPlayerChannel.ID: {
IPCPacket0CPlayerChannel pkt = (IPCPacket0CPlayerChannel)ipc;
if(!isServerStopped()) {
if(pkt.open) {
startPlayerConnnection(pkt.channel);
}else {
closeChannel(pkt.channel);
}
}else {
logger.error("Client tried to {} channel server was stopped", pkt.open ? "open" : "close");
}
break;
}
case IPCPacket0EListWorlds.ID: {
IPCPacket0EListWorlds pkt = (IPCPacket0EListWorlds)ipc;
if(!isServerStopped()) {
logger.error("Client tried to list worlds while server was running");
sendTaskFailed();
}else {
String[] worlds = EaglerSaveFormat.worldsList.getAllLines();
if(worlds == null) {
sendIPCPacket(new IPCPacket16NBTList(IPCPacket16NBTList.WORLD_LIST, new LinkedList<NBTTagCompound>()));
break;
}
LinkedHashSet<String> updatedList = new LinkedHashSet();
LinkedList<NBTTagCompound> sendListNBT = new LinkedList();
boolean rewrite = false;
for(int i = 0; i < worlds.length; ++i) {
String w = worlds[i].trim();
if(w.length() > 0) {
VFile2 vf = new VFile2(EaglerSaveFormat.worldsFolder, w, "level.dat");
if(!vf.exists()) {
vf = new VFile2(EaglerSaveFormat.worldsFolder, w, "level.dat_old");
}
if(vf.exists()) {
try(InputStream dat = vf.getInputStream()) {
if(updatedList.add(w)) {
NBTTagCompound worldDatNBT = CompressedStreamTools.readCompressed(dat);
worldDatNBT.setString("folderNameEagler", w);
sendListNBT.add(worldDatNBT);
}else {
rewrite = true;
}
continue;
}catch(IOException e) {
// shit fuck
}
}
rewrite = true;
logger.error("World level.dat for '{}' was not found, attempting to delete", w);
if(!saveFormat.deleteWorldDirectory(w)) {
logger.error("Failed to delete '{}'! It will be removed from the worlds list anyway", w);
}
}else {
rewrite = true;
}
}
if(rewrite) {
EaglerSaveFormat.worldsList.setAllChars(String.join("\n", updatedList));
}
sendIPCPacket(new IPCPacket16NBTList(IPCPacket16NBTList.WORLD_LIST, sendListNBT));
}
break;
}
case IPCPacket14StringList.ID: {
IPCPacket14StringList pkt = (IPCPacket14StringList)ipc;
switch(pkt.opCode) {
case IPCPacket14StringList.LOCALE:
StringTranslate.init(pkt.stringList);
break;
//case IPCPacket14StringList.STAT_GUID:
// AchievementMap.init(pkt.stringList);
// AchievementList.init();
// break;
default:
logger.error("Strange string list 0x{} with length{} recieved", Integer.toHexString(pkt.opCode), pkt.stringList.size());
break;
}
break;
}
case IPCPacket17ConfigureLAN.ID: {
IPCPacket17ConfigureLAN pkt = (IPCPacket17ConfigureLAN)ipc;
currentProcess.getConfigurationManager().configureLAN(pkt.gamemode, pkt.cheats); // don't use iceServers
break;
}
case IPCPacket18ClearPlayers.ID: {
if(!isServerStopped()) {
logger.error("Client tried to clear players while server was running");
sendTaskFailed();
}else {
saveFormat.clearPlayers(((IPCPacket18ClearPlayers)ipc).worldName);
sendIPCPacket(new IPCPacketFFProcessKeepAlive(IPCPacket18ClearPlayers.ID));
}
break;
}
case IPCPacket19Autosave.ID: {
if(!isServerStopped()) {
currentProcess.getConfigurationManager().saveAllPlayerData();
currentProcess.saveAllWorlds(false);
sendIPCPacket(new IPCPacketFFProcessKeepAlive(IPCPacket19Autosave.ID));
}else {
logger.error("Client tried to autosave while server was stopped");
sendTaskFailed();
}
break;
}
case IPCPacket21EnableLogging.ID: {
enableLoggingRedirector(((IPCPacket21EnableLogging)ipc).enable);
break;
}
default:
logger.error("IPC packet type 0x{} class \"{}\" was not handled", Integer.toHexString(id), ipc.getClass().getSimpleName());
sendTaskFailed();
break;
}
}catch(Throwable t) {
logger.error("IPC packet type 0x{} class \"{}\" was not processed correctly", Integer.toHexString(id), ipc.getClass().getSimpleName());
logger.error(t);
sendIPCPacket(new IPCPacket15Crashed("IPC packet type 0x" + Integer.toHexString(id) + " class \"" + ipc.getClass().getSimpleName() + "\" was not processed correctly!\n\n" + EagRuntime.getStackTrace(t)));
sendTaskFailed();
}
}
public static void enableLoggingRedirector(boolean en) {
LogManager.logRedirector = en ? new ILogRedirector() {
@Override
public void log(String txt, boolean err) {
sendLogMessagePacket(txt, err);
}
} : null;
}
public static void sendLogMessagePacket(String txt, boolean err) {
sendIPCPacket(new IPCPacket20LoggerMessage(txt, err));
}
public static void sendIPCPacket(IPCPacketBase ipc) {
byte[] pkt;
try {
pkt = IPCPacketManager.IPCSerialize(ipc);
}catch (IOException ex) {
throw new RuntimeException("Failed to serialize IPC packet", ex);
}
ServerPlatformSingleplayer.sendPacket(new IPCPacketData(SingleplayerServerController.IPC_CHANNEL, pkt));
}
public static void reportTPS(List<String> texts) {
sendIPCPacket(new IPCPacket14StringList(IPCPacket14StringList.SERVER_TPS, texts));
}
public static void sendTaskFailed() {
sendIPCPacket(new IPCPacketFFProcessKeepAlive(IPCPacketFFProcessKeepAlive.FAILURE));
}
public static void sendProgress(String updateMessage, float updateProgress) {
sendIPCPacket(new IPCPacket0DProgressUpdate(updateMessage, updateProgress));
}
private static boolean isServerStopped() {
return currentProcess == null || !currentProcess.isServerRunning();
}
private static void tryStopServer() {
if(!isServerStopped()) {
currentProcess.stopServer();
}
currentProcess = null;
}
private static void mainLoop() {
processAsyncMessageQueue();
if(currentProcess != null) {
if(currentProcess.isServerRunning()) {
currentProcess.mainLoop();
}
if(!currentProcess.isServerRunning()) {
currentProcess.stopServer();
currentProcess = null;
sendIPCPacket(new IPCPacketFFProcessKeepAlive(IPCPacket01StopServer.ID));
}
}else {
EagUtils.sleep(50l);
}
}
public static void serverMain() {
try {
currentProcess = null;
logger.info("Starting EaglercraftX integrated server worker...");
// signal thread startup successful
sendIPCPacket(new IPCPacketFFProcessKeepAlive(0xFF));
while(true) {
mainLoop();
EagUtils.sleep(1l);
}
}catch(Throwable tt) {
if(tt instanceof ReportedException) {
String fullReport = ((ReportedException)tt).getCrashReport().getCompleteReport();
logger.error(fullReport);
sendIPCPacket(new IPCPacket15Crashed(fullReport));
}else {
logger.error("Server process encountered a fatal error!");
logger.error(tt);
sendIPCPacket(new IPCPacket15Crashed("SERVER PROCESS EXITED!\n\n" + EagRuntime.getStackTrace(tt)));
}
}finally {
if(!isServerStopped()) {
try {
currentProcess.stopServer();
}catch(Throwable t) {
logger.error("Encountered exception while stopping server!");
logger.error(t);
}
}
logger.error("Server process exited!");
sendIPCPacket(new IPCPacketFFProcessKeepAlive(IPCPacketFFProcessKeepAlive.EXITED));
}
}
}

View File

@ -0,0 +1,291 @@
package net.lax1dude.eaglercraft.v1_8.sp.server;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import net.lax1dude.eaglercraft.v1_8.internal.vfs2.VFile2;
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.entity.player.EntityPlayer;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.entity.player.EntityPlayerMP;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.init.Bootstrap;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.server.MinecraftServer;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.world.EnumDifficulty;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.world.WorldServer;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.world.WorldSettings;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.world.WorldSettings.GameType;
import net.lax1dude.eaglercraft.v1_8.sp.server.skins.IntegratedSkinService;
/**
* Copyright (c) 2023-2024 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
* 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.
*
*/
public class EaglerMinecraftServer extends MinecraftServer {
public static final Logger logger = EaglerIntegratedServerWorker.logger;
public static final VFile2 savesDir = new VFile2("worlds");
protected EnumDifficulty difficulty;
protected GameType gamemode;
protected WorldSettings newWorldSettings;
protected boolean paused;
protected EaglerSaveHandler saveHandler;
protected IntegratedSkinService skinService;
private long lastTPSUpdate = 0l;
public static int counterTicksPerSecond = 0;
public static int counterChunkRead = 0;
public static int counterChunkGenerate = 0;
public static int counterChunkWrite = 0;
public static int counterTileUpdate = 0;
public static int counterLightUpdate = 0;
private final List<Runnable> scheduledTasks = new LinkedList();
public EaglerMinecraftServer(String world, String owner, int viewDistance, WorldSettings currentWorldSettings, boolean demo) {
super(world);
Bootstrap.register();
this.saveHandler = new EaglerSaveHandler(savesDir, world);
this.skinService = new IntegratedSkinService(new VFile2(saveHandler.getWorldDirectory(), "eagler/skulls"));
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.newWorldSettings = currentWorldSettings;
this.paused = false;
}
public IntegratedSkinService getSkinService() {
return skinService;
}
public void setBaseServerProperties(EnumDifficulty difficulty, GameType gamemode) {
this.difficulty = difficulty;
this.gamemode = gamemode;
this.setCanSpawnAnimals(true);
this.setCanSpawnNPCs(true);
this.setAllowPvp(true);
this.setAllowFlight(true);
}
@Override
public void addScheduledTask(Runnable var1) {
scheduledTasks.add(var1);
}
@Override
protected boolean startServer() throws IOException {
logger.info("Starting integrated eaglercraft server version 1.8.8");
this.loadAllWorlds(saveHandler, this.getWorldName(), newWorldSettings);
serverRunning = true;
return true;
}
public void deleteWorldAndStopServer() {
super.deleteWorldAndStopServer();
logger.info("Deleting world...");
EaglerIntegratedServerWorker.saveFormat.deleteWorldDirectory(getFolderName());
}
public void mainLoop() {
long k = getCurrentTimeMillis();
this.sendTPSToClient(k);
if(paused && this.playersOnline.size() <= 1) {
currentTime = k;
return;
}
long j = k - this.currentTime;
if (j > 2000L && this.currentTime - this.timeOfLastWarning >= 15000L) {
logger.warn(
"Can\'t keep up! Did the system time change, or is the server overloaded? Running {}ms behind, skipping {} tick(s)",
new Object[] { Long.valueOf(j), Long.valueOf(j / 50L) });
j = 100L;
this.currentTime = k - 100l;
this.timeOfLastWarning = this.currentTime;
}
if (j < 0L) {
logger.warn("Time ran backwards! Did the system time change?");
j = 0L;
this.currentTime = k;
}
if (this.worldServers[0].areAllPlayersAsleep()) {
this.currentTime = k;
this.tick();
++counterTicksPerSecond;
} else {
if (j > 50L) {
this.currentTime += 50l;
this.tick();
++counterTicksPerSecond;
}
}
}
public void updateTimeLightAndEntities() {
this.skinService.flushCache();
super.updateTimeLightAndEntities();
}
protected void sendTPSToClient(long millis) {
if(millis - lastTPSUpdate > 1000l) {
lastTPSUpdate = millis;
if(serverRunning && this.worldServers != null) {
List<String> lst = new ArrayList<>(Arrays.asList(
"TPS: " + counterTicksPerSecond + "/20",
"Chunks: " + countChunksLoaded(this.worldServers) + "/" + countChunksTotal(this.worldServers),
"Entities: " + countEntities(this.worldServers) + "+" + countTileEntities(this.worldServers),
"R: " + counterChunkRead + ", G: " + counterChunkGenerate + ", W: " + counterChunkWrite,
"TU: " + counterTileUpdate + ", LU: " + counterLightUpdate
));
int players = countPlayerEntities(this.worldServers);
if(players > 1) {
lst.add("Players: " + players);
}
counterTicksPerSecond = counterChunkRead = counterChunkGenerate = 0;
counterChunkWrite = counterTileUpdate = counterLightUpdate = 0;
EaglerIntegratedServerWorker.reportTPS(lst);
}
}
}
private static int countChunksLoaded(WorldServer[] worlds) {
int i = 0;
for(int j = 0; j < worlds.length; ++j) {
if(worlds[j] != null) {
i += worlds[j].theChunkProviderServer.getLoadedChunkCount();
}
}
return i;
}
private static int countChunksTotal(WorldServer[] worlds) {
int i = 0;
for(int j = 0; j < worlds.length; ++j) {
if(worlds[j] != null) {
List<EntityPlayer> players = worlds[j].playerEntities;
for(int l = 0, n = players.size(); l < n; ++l) {
i += ((EntityPlayerMP)players.get(l)).loadedChunks.size();
}
i += worlds[j].theChunkProviderServer.getLoadedChunkCount();
}
}
return i;
}
private static int countEntities(WorldServer[] worlds) {
int i = 0;
for(int j = 0; j < worlds.length; ++j) {
if(worlds[j] != null) {
i += worlds[j].loadedEntityList.size();
}
}
return i;
}
private static int countTileEntities(WorldServer[] worlds) {
int i = 0;
for(int j = 0; j < worlds.length; ++j) {
if(worlds[j] != null) {
i += worlds[j].loadedTileEntityList.size();
}
}
return i;
}
private static int countPlayerEntities(WorldServer[] worlds) {
int i = 0;
for(int j = 0; j < worlds.length; ++j) {
if(worlds[j] != null) {
i += worlds[j].playerEntities.size();
}
}
return i;
}
public void setPaused(boolean p) {
paused = p;
if(!p) {
currentTime = System.currentTimeMillis();
}
}
public boolean getPaused() {
return paused;
}
@Override
public boolean canStructuresSpawn() {
return worldServers != null ? worldServers[0].getWorldInfo().isMapFeaturesEnabled() : newWorldSettings.isMapFeaturesEnabled();
}
@Override
public GameType getGameType() {
return worldServers != null ? worldServers[0].getWorldInfo().getGameType() : newWorldSettings.getGameType();
}
@Override
public EnumDifficulty getDifficulty() {
return difficulty;
}
@Override
public boolean isHardcore() {
return worldServers != null ? worldServers[0].getWorldInfo().isHardcoreModeEnabled() : newWorldSettings.getHardcoreEnabled();
}
@Override
public int getOpPermissionLevel() {
return 4;
}
@Override
public boolean func_181034_q() {
return true;
}
@Override
public boolean func_183002_r() {
return true;
}
@Override
public boolean isDedicatedServer() {
return false;
}
@Override
public boolean func_181035_ah() {
return false;
}
@Override
public boolean isCommandBlockEnabled() {
return true;
}
@Override
public String shareToLAN(GameType var1, boolean var2) {
return null;
}
}

View File

@ -0,0 +1,48 @@
package net.lax1dude.eaglercraft.v1_8.sp.server;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.entity.player.EntityPlayerMP;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.server.MinecraftServer;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.server.management.ServerConfigurationManager;
import net.minecraft.nbt.NBTTagCompound;
/**
* Copyright (c) 2023-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.
*
*/
public class EaglerPlayerList extends ServerConfigurationManager {
private NBTTagCompound hostPlayerNBT = null;
public EaglerPlayerList(MinecraftServer par1MinecraftServer, int viewDistance) {
super(par1MinecraftServer);
this.viewDistance = viewDistance;
}
protected void writePlayerData(EntityPlayerMP par1EntityPlayerMP) {
if (par1EntityPlayerMP.getName().equals(this.getServerInstance().getServerOwner())) {
this.hostPlayerNBT = new NBTTagCompound();
par1EntityPlayerMP.writeToNBT(hostPlayerNBT);
}
super.writePlayerData(par1EntityPlayerMP);
}
public NBTTagCompound getHostPlayerData() {
return this.hostPlayerNBT;
}
public void playerLoggedOut(EntityPlayerMP playerIn) {
super.playerLoggedOut(playerIn);
((EaglerMinecraftServer)getServerInstance()).skinService.unregisterPlayer(playerIn.getUniqueID());
}
}

View File

@ -0,0 +1,113 @@
package net.lax1dude.eaglercraft.v1_8.sp.server;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import com.google.common.collect.Lists;
import net.lax1dude.eaglercraft.v1_8.internal.vfs2.VFile2;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.world.storage.ISaveHandler;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.world.storage.SaveFormatComparator;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.world.storage.SaveFormatOld;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.world.storage.WorldInfo;
/**
* Copyright (c) 2023-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.
*
*/
public class EaglerSaveFormat extends SaveFormatOld {
public static final VFile2 worldsList = new VFile2("worlds_list.txt");
public static final VFile2 worldsFolder = new VFile2("worlds");
public EaglerSaveFormat(VFile2 parFile) {
super(parFile);
}
public String getName() {
return "eagler";
}
public ISaveHandler getSaveLoader(String s, boolean flag) {
return new EaglerSaveHandler(this.savesDirectory, s);
}
public List<SaveFormatComparator> getSaveList() {
ArrayList arraylist = Lists.newArrayList();
if(worldsList.exists()) {
String[] lines = worldsList.getAllLines();
for (int i = 0; i < lines.length; ++i) {
String s = lines[i];
WorldInfo worldinfo = this.getWorldInfo(s);
if (worldinfo != null
&& (worldinfo.getSaveVersion() == 19132 || worldinfo.getSaveVersion() == 19133)) {
boolean flag = worldinfo.getSaveVersion() != this.getSaveVersion();
String s1 = worldinfo.getWorldName();
if (StringUtils.isEmpty(s1)) {
s1 = s;
}
arraylist.add(new SaveFormatComparator(s, s1, worldinfo.getLastTimePlayed(), 0l,
worldinfo.getGameType(), flag, worldinfo.isHardcoreModeEnabled(),
worldinfo.areCommandsAllowed()));
}
}
}
return arraylist;
}
public void clearPlayers(String worldFolder) {
VFile2 file1 = new VFile2(this.savesDirectory, worldFolder, "player");
deleteFiles(file1.listFiles(true), null);
}
protected int getSaveVersion() {
return 19133; // why notch?
}
public boolean duplicateWorld(String worldFolder, String displayName) {
String newFolderName = displayName.replaceAll("[\\./\"]", "_");
VFile2 newFolder = new VFile2(savesDirectory, newFolderName);
while((new VFile2(newFolder, "level.dat")).exists() || (new VFile2(newFolder, "level.dat_old")).exists()) {
newFolderName += "_";
newFolder = new VFile2(savesDirectory, newFolderName);
}
VFile2 oldFolder = new VFile2(this.savesDirectory, worldFolder);
String oldPath = oldFolder.getPath();
int totalSize = 0;
int lastUpdate = 0;
final VFile2 finalNewFolder = newFolder;
for(VFile2 vf : oldFolder.listFiles(true)) {
String fileNameRelative = vf.getPath().substring(oldPath.length() + 1);
totalSize += VFile2.copyFile(vf, new VFile2(finalNewFolder, fileNameRelative));
if (totalSize - lastUpdate > 10000) {
lastUpdate = totalSize;
EaglerIntegratedServerWorker.sendProgress("singleplayer.busy.duplicating", totalSize);
}
}
String[] worldsTxt = worldsList.getAllLines();
if(worldsTxt == null || worldsTxt.length <= 0) {
worldsTxt = new String[] { newFolderName };
}else {
String[] tmp = worldsTxt;
worldsTxt = new String[worldsTxt.length + 1];
System.arraycopy(tmp, 0, worldsTxt, 0, tmp.length);
worldsTxt[worldsTxt.length - 1] = newFolderName;
}
worldsList.setAllChars(String.join("\n", worldsTxt));
return renameWorld(newFolderName, displayName);
}
}

View File

@ -0,0 +1,39 @@
package net.lax1dude.eaglercraft.v1_8.sp.server;
import net.lax1dude.eaglercraft.v1_8.internal.vfs2.VFile2;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.world.WorldProvider;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.world.chunk.storage.IChunkLoader;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.world.storage.SaveHandler;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.world.storage.WorldInfo;
import net.minecraft.nbt.NBTTagCompound;
/**
* Copyright (c) 2023-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.
*
*/
public class EaglerSaveHandler extends SaveHandler {
public EaglerSaveHandler(VFile2 savesDirectory, String directoryName) {
super(savesDirectory, directoryName);
}
public IChunkLoader getChunkLoader(WorldProvider provider) {
return new EaglerChunkLoader(new VFile2(this.getWorldDirectory(), "level" + provider.getDimensionId()));
}
public void saveWorldInfoWithPlayer(WorldInfo worldInformation, NBTTagCompound tagCompound) {
worldInformation.setSaveVersion(19133);
super.saveWorldInfoWithPlayer(worldInformation, tagCompound);
}
}

View File

@ -0,0 +1,47 @@
package net.lax1dude.eaglercraft.v1_8.sp.server.classes;
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
/**
* Copyright (c) 2022-2024 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
* 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.
*
*/
public class ContextUtil {
public static final Logger LOGGER = LogManager.getLogger("ContextUtil");
private static boolean GUARD_CONTEXT = false; // disable guard, for stability
public static void enterContext() {
if(!GUARD_CONTEXT) {
GUARD_CONTEXT = true;
LOGGER.info("Entered context");
}
}
public static void exitContext() {
if(GUARD_CONTEXT) {
GUARD_CONTEXT = false;
LOGGER.info("Exited context");
}
}
public static void __checkIntegratedContextValid(String id) {
if(GUARD_CONTEXT) {
throw new IllegalContextAccessException("Illegal integrated server class access: " + id);
}
}
}

View File

@ -0,0 +1,41 @@
package net.lax1dude.eaglercraft.v1_8.sp.server.classes;
import net.lax1dude.eaglercraft.v1_8.json.JSONTypeProvider;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.util.ChatStyle;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.util.IChatComponent;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.world.gen.ChunkProviderSettings;
/**
* Copyright (c) 2022-2024 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
* 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.
*
*/
public class EaglerServerBootstrap {
private static boolean isCLInit = false;
public static void staticInit() {
if(isCLInit) {
return;
}
registerJSONTypes();
isCLInit = true;
}
public static void registerJSONTypes() {
JSONTypeProvider.registerType(IChatComponent.class, new IChatComponent.Serializer());
JSONTypeProvider.registerType(ChatStyle.class, new ChatStyle.Serializer());
JSONTypeProvider.registerType(ChunkProviderSettings.Factory.class, new ChunkProviderSettings.Serializer());
}
}

View File

@ -0,0 +1,27 @@
package net.lax1dude.eaglercraft.v1_8.sp.server.classes;
/**
* Copyright (c) 2022-2024 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
* 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.
*
*/
public class IllegalContextAccessException extends RuntimeException {
public IllegalContextAccessException() {
}
public IllegalContextAccessException(String s) {
super(s);
}
}

View File

@ -0,0 +1,24 @@
package net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.entity;
import net.lax1dude.eaglercraft.v1_8.sp.server.classes.net.minecraft.world.World;
/**
* 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.
*
*/
public interface EntityConstructor<T> {
T createEntity(World world);
}

View File

@ -0,0 +1,167 @@
package net.lax1dude.eaglercraft.v1_8.sp.server.export;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.zip.CRC32;
import net.lax1dude.eaglercraft.v1_8.EagRuntime;
/**
* 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.
*
*/
public class EPKCompiler {
private final ByteArrayOutputStream os;
private final CRC32 checkSum = new CRC32();
private int lengthIntegerOffset = 0;
private int totalFileCount = 0;
public EPKCompiler(String name, String owner, String type) {
os = new ByteArrayOutputStream(0x200000);
try {
os.write(new byte[]{(byte)69,(byte)65,(byte)71,(byte)80,(byte)75,(byte)71,(byte)36,(byte)36}); // EAGPKG$$
os.write(new byte[]{(byte)6,(byte)118,(byte)101,(byte)114,(byte)50,(byte)46,(byte)48}); // 6 + ver2.0
Date d = new Date();
byte[] filename = (name + ".epk").getBytes(StandardCharsets.UTF_8);
os.write(filename.length);
os.write(filename);
byte[] comment = ("\n\n # Eagler EPK v2.0 (c) " + EagRuntime.fixDateFormat(new SimpleDateFormat("yyyy")).format(d) + " " +
owner + "\n # export: on " + EagRuntime.fixDateFormat(new SimpleDateFormat("MM/dd/yyyy")).format(d) + " at " +
EagRuntime.fixDateFormat(new SimpleDateFormat("hh:mm:ss aa")).format(d) + "\n\n # world name: " + name + "\n\n")
.getBytes(StandardCharsets.UTF_8);
os.write((comment.length >> 8) & 255);
os.write(comment.length & 255);
os.write(comment);
writeLong(d.getTime(), os);
lengthIntegerOffset = os.size();
os.write(new byte[]{(byte)255,(byte)255,(byte)255,(byte)255}); // this will be replaced with the file count
os.write('0'); // compression type: none
os.write(new byte[]{(byte)72,(byte)69,(byte)65,(byte)68}); // HEAD
os.write(new byte[]{(byte)9,(byte)102,(byte)105,(byte)108,(byte)101,(byte)45,(byte)116,(byte)121,
(byte)112,(byte)101}); // 9 + file-type
byte[] typeBytes = type.getBytes(StandardCharsets.UTF_8);
writeInt(typeBytes.length, os);
os.write(typeBytes); // write type
os.write('>');
++totalFileCount;
os.write(new byte[]{(byte)72,(byte)69,(byte)65,(byte)68}); // HEAD
os.write(new byte[]{(byte)10,(byte)119,(byte)111,(byte)114,(byte)108,(byte)100,(byte)45,(byte)110,
(byte)97,(byte)109,(byte)101}); // 10 + world-name
byte[] nameBytes = name.getBytes(StandardCharsets.UTF_8);
writeInt(nameBytes.length, os);
os.write(nameBytes); // write name
os.write('>');
++totalFileCount;
os.write(new byte[]{(byte)72,(byte)69,(byte)65,(byte)68}); // HEAD
os.write(new byte[]{(byte)11,(byte)119,(byte)111,(byte)114,(byte)108,(byte)100,(byte)45,(byte)111,
(byte)119,(byte)110,(byte)101,(byte)114}); // 11 + world-owner
byte[] ownerBytes = owner.getBytes(StandardCharsets.UTF_8);
writeInt(ownerBytes.length, os);
os.write(ownerBytes); // write owner
os.write('>');
++totalFileCount;
}catch(IOException ex) {
throw new RuntimeException("This happened somehow", ex);
}
}
public void append(String name, byte[] dat) {
try {
checkSum.reset();
checkSum.update(dat, 0, dat.length);
long sum = checkSum.getValue();
os.write(new byte[]{(byte)70,(byte)73,(byte)76,(byte)69}); // FILE
byte[] nameBytes = name.getBytes(StandardCharsets.UTF_8);
os.write(nameBytes.length);
os.write(nameBytes);
writeInt(dat.length + 5, os);
writeInt((int)sum, os);
os.write(dat);
os.write(':');
os.write('>');
++totalFileCount;
}catch(IOException ex) {
throw new RuntimeException("This happened somehow", ex);
}
}
public byte[] complete() {
try {
os.write(new byte[]{(byte)69,(byte)78,(byte)68,(byte)36}); // END$
os.write(new byte[]{(byte)58,(byte)58,(byte)58,(byte)89,(byte)69,(byte)69,(byte)58,(byte)62}); // :::YEE:>
byte[] ret = os.toByteArray();
ret[lengthIntegerOffset] = (byte)((totalFileCount >> 24) & 0xFF);
ret[lengthIntegerOffset + 1] = (byte)((totalFileCount >> 16) & 0xFF);
ret[lengthIntegerOffset + 2] = (byte)((totalFileCount >> 8) & 0xFF);
ret[lengthIntegerOffset + 3] = (byte)(totalFileCount & 0xFF);
return ret;
}catch(IOException ex) {
throw new RuntimeException("This happened somehow", ex);
}
}
public static void writeInt(int i, OutputStream os) throws IOException {
os.write((i >> 24) & 0xFF);
os.write((i >> 16) & 0xFF);
os.write((i >> 8) & 0xFF);
os.write(i & 0xFF);
}
public static void writeLong(long i, OutputStream os) throws IOException {
os.write((int)((i >> 56) & 0xFF));
os.write((int)((i >> 48) & 0xFF));
os.write((int)((i >> 40) & 0xFF));
os.write((int)((i >> 32) & 0xFF));
os.write((int)((i >> 24) & 0xFF));
os.write((int)((i >> 16) & 0xFF));
os.write((int)((i >> 8) & 0xFF));
os.write((int)(i & 0xFF));
}
}

Some files were not shown because too many files have changed in this diff Show More