From a3625a43d5762087dd46d7479cb5cd24f9ff8874 Mon Sep 17 00:00:00 2001 From: Satxm Date: Sun, 18 Aug 2024 18:08:19 +0800 Subject: [PATCH] Add UUID Fixer Module --- README.md | 14 +- fabric/build.gradle | 44 +- .../io/github/satxm/mcwifipnp/MCWiFiPnP.java | 78 ++- .../src/main/resources/mcwifipnp.mixins.json | 12 - forge/build.gradle | 117 ++-- .../io/github/satxm/mcwifipnp/MCWiFiPnP.java | 78 ++- .../resources/META-INF/accesstransformer.cfg | 1 - forge/src/main/resources/META-INF/mods.toml | 20 +- forge/src/main/resources/pack.mcmeta | 7 - gradle.properties | 4 +- settings.gradle | 20 +- src/main/java/com/dosse/upnp/Gateway.java | 298 +++++------ .../java/com/dosse/upnp/GatewayFinder.java | 164 +++--- src/main/java/com/dosse/upnp/UPnP.java | 258 ++++----- .../satxm/mcwifipnp/ForceOfflineCommand.java | 128 +++++ .../github/satxm/mcwifipnp/MCWiFiPnPUnit.java | 501 +++++++++--------- .../io/github/satxm/mcwifipnp/OnlineMode.java | 45 ++ .../satxm/mcwifipnp/ShareToLanScreenNew.java | 300 ++++++----- .../io/github/satxm/mcwifipnp/UUIDFixer.java | 63 +++ .../satxm/mcwifipnp/mixin/MixinPlayer.java | 23 + .../mcwifipnp/mixin/PlayerListAccessor.java | 6 +- .../assets/mcwifipnp/lang/en_us.json | 70 ++- .../assets/mcwifipnp/lang/es_es.json | 70 ++- .../assets/mcwifipnp/lang/ru_ru.json | 70 ++- .../assets/mcwifipnp/lang/zh_cn.json | 70 ++- .../assets/mcwifipnp/lang/zh_hk.json | 62 ++- .../assets/mcwifipnp/lang/zh_tw.json | 70 ++- src/main/resources/mcwifipnp.mixins.json | 13 + src/main/resources/pack.mcmeta | 7 + 29 files changed, 1479 insertions(+), 1134 deletions(-) delete mode 100644 fabric/src/main/resources/mcwifipnp.mixins.json delete mode 100644 forge/src/main/resources/META-INF/accesstransformer.cfg delete mode 100644 forge/src/main/resources/pack.mcmeta create mode 100644 src/main/java/io/github/satxm/mcwifipnp/ForceOfflineCommand.java create mode 100644 src/main/java/io/github/satxm/mcwifipnp/OnlineMode.java create mode 100644 src/main/java/io/github/satxm/mcwifipnp/UUIDFixer.java create mode 100644 src/main/java/io/github/satxm/mcwifipnp/mixin/MixinPlayer.java rename {fabric/src => src}/main/java/io/github/satxm/mcwifipnp/mixin/PlayerListAccessor.java (79%) create mode 100644 src/main/resources/mcwifipnp.mixins.json create mode 100644 src/main/resources/pack.mcmeta diff --git a/README.md b/README.md index 57fb667d..fe3060f4 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ [3]: https://img.shields.io/curseforge/dt/450250?label=CurseForge%0aDownloads&logo=curseforge&style=flat&color=E36639&labelcolor=2D2D2D [4]: https://www.curseforge.com/minecraft/mc-mods/mcwifipnp -[5]: https://img.shields.io/badge/Available%20for-%201.15%20to%201.20-47376F?logo=files&color=377BCB&labelcolor=2D2D2D +[5]: https://img.shields.io/badge/Available%20for-%201.15%20to%201.21-47376F?logo=files&color=377BCB&labelcolor=2D2D2D [6]: https://modrinth.com/mod/mcwifipnp/versions [7]: https://img.shields.io/github/license/Satxm/mcwifipnp?label=License&logo=github&style=flat&color=E51050&labelcolor=2D2D2D @@ -58,6 +58,18 @@ Modified from [TheGlitch76/mcpnp](https://github.com/TheGlitch76/mcpnp) project ## What Can It Do - 它的作用 +Added UUID Fixer module, which allows offline players to obtain a unique UUID from the Mojang server, keeping the UUID fixed and not changing due to client changes. + +添加了 UUID 修复模块,对于离线玩家,可以使离线玩家从 Mojang 服务器获取唯一的 UUID,使 UUID 固定,不会因为客户端变化而变化。 + +Added a new command `/forceoffline` to control whether players are forced into offline mode without obtaining UUIDs from Mojang servers. `/forceoffline list` command can list players who in the force offline list, `/forceoffline add` command can add players to the force offline list, `/forceoffline remove` command can remove players from the force offline list. + +添加了一个新指令 `/forceoffline` 以便于控制玩家是否强制玩家为离线模式,不从 Mojang 服务器获取 UUID。`/forceoffline list` 指令可以查看列表中玩家,`/forceoffline add` 指令可以添加玩家到列表,`/forceoffline remove` 指令可以从列表中移除玩家。 + +For the `Oline Mode` button, there are now three options: 'Enable': enable genuine verification, which will verify login information against the Mojang server database, only allowing players who login with a Microsoft account to join, `Disable`: not verify login information, allows offline players to join, `Disable + UUID Fixer`: Attempt to match the Mojang server user name with the player name for offline mode players to obtain a unique UUID, Meanwhile, UUIDs are retained for users logging in with Microsoft accounts, It can also prevent the loss of backpack and inventory items. + +对于`正版验证`按钮,现在有三个选项:`启用`:启用正版验证,将会比对Mojang服务器数据库验证登录信息,即只允许使用微软帐户登录的玩家加入;`禁用`:即不验证登录信息,允许使用离线模式登录的玩家加入;`禁用 + 修复UUID`:尝试使用离线模式登录的玩家名匹配Mojang服务器用户名称以获取唯一UUID,同时为使用微软帐户登录的用户保留UUID,它也可以防止背包和物品栏内容丢失。 + Allows you to change the port number of the LAN world and choose whether to map this port to the public network using UPnP (if your router supports UPnP). 允许你修改局域网世界的端口号,并选择是否映射这个端口使用UPnP映射到公网(如果你的路由器支持UPnP)。 diff --git a/fabric/build.gradle b/fabric/build.gradle index 63e63377..328424c1 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'fabric-loom' version '0.12-SNAPSHOT' + id 'fabric-loom' version '0.12-SNAPSHOT' } sourceCompatibility = targetCompatibility = JavaVersion.VERSION_16 @@ -9,43 +9,43 @@ version = project.mod_version + "-" + project.minecraft_version + "-fabric" group = project.maven_group dependencies { - minecraft "com.mojang:minecraft:${project.minecraft_version}" - mappings loom.officialMojangMappings() - modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" - - modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" + minecraft "com.mojang:minecraft:${project.minecraft_version}" + mappings loom.officialMojangMappings() + modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" + modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" + modImplementation "com.google.code.findbugs:jsr305:3.0.2" } sourceSets { - main { - java { - srcDir "../src/main/java" - } - resources { - srcDir "../src/main/resources" - } + main { + java { + srcDir "../src/main/java" + } + resources { + srcDir "../src/main/resources" } + } } jar { - from("../LICENSE") { - } + from("../LICENSE") { + } } java { - withSourcesJar() + withSourcesJar() } processResources { - inputs.property "version", project.version + inputs.property "version", project.version - filesMatching("fabric.mod.json") { - expand "version": project.mod_version,'mc_version': project.fabric_minecraft_version_range, 'fabric_version': project.fabric_version_range, "loader_version": project.fabric_loader_version_range - } + filesMatching("fabric.mod.json") { + expand "version": project.mod_version,'mc_version': project.fabric_minecraft_version_range, 'fabric_version': project.fabric_version_range, "loader_version": project.fabric_loader_version_range + } } tasks.withType(JavaCompile).configureEach { - it.options.encoding = "UTF-8" - it.options.release = 16 + it.options.encoding = "UTF-8" + it.options.release = 16 } diff --git a/fabric/src/main/java/io/github/satxm/mcwifipnp/MCWiFiPnP.java b/fabric/src/main/java/io/github/satxm/mcwifipnp/MCWiFiPnP.java index eb8b58ac..37aa2619 100644 --- a/fabric/src/main/java/io/github/satxm/mcwifipnp/MCWiFiPnP.java +++ b/fabric/src/main/java/io/github/satxm/mcwifipnp/MCWiFiPnP.java @@ -1,7 +1,6 @@ package io.github.satxm.mcwifipnp; import java.util.List; -import io.github.satxm.mcwifipnp.mixin.PlayerListAccessor; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents; import net.fabricmc.fabric.api.client.screen.v1.Screens; @@ -12,7 +11,6 @@ import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.screens.PauseScreen; import net.minecraft.client.gui.screens.Screen; -import net.minecraft.client.server.IntegratedServer; import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.server.MinecraftServer; import net.minecraft.server.commands.BanIpCommands; @@ -21,55 +19,49 @@ import net.minecraft.server.commands.DeOpCommands; import net.minecraft.server.commands.OpCommand; import net.minecraft.server.commands.WhitelistCommand; -import net.minecraft.server.players.PlayerList; public class MCWiFiPnP implements ModInitializer { - public static final String MODID = "mcwifipnp"; + public static final String MODID = "mcwifipnp"; - @Override - public void onInitialize() { - ServerLifecycleEvents.SERVER_STARTING.register(this::onServerLoad); - ServerLifecycleEvents.SERVER_STOPPING.register(this::onServerStop); - ScreenEvents.AFTER_INIT.register(MCWiFiPnP::afterScreenInit); + @Override + public void onInitialize() { + ServerLifecycleEvents.SERVER_STARTING.register(this::onServerLoad); + ServerLifecycleEvents.SERVER_STOPPING.register(this::onServerStop); + ScreenEvents.AFTER_INIT.register(MCWiFiPnP::afterScreenInit); - CommandRegistrationCallback.EVENT.register((dispatcher, dedicated) -> { - DeOpCommands.register(dispatcher); - OpCommand.register(dispatcher); - WhitelistCommand.register(dispatcher); - BanIpCommands.register(dispatcher); - BanListCommands.register(dispatcher); - BanPlayerCommands.register(dispatcher); - }); - } + CommandRegistrationCallback.EVENT.register((dispatcher, dedicated) -> { + DeOpCommands.register(dispatcher); + OpCommand.register(dispatcher); + WhitelistCommand.register(dispatcher); + BanIpCommands.register(dispatcher); + BanListCommands.register(dispatcher); + BanPlayerCommands.register(dispatcher); + ForceOfflineCommand.register(dispatcher); + }); + } - public static void afterScreenInit(Minecraft client, Screen screen, int i, int j) { - if (screen instanceof PauseScreen) { - final List buttons = Screens.getButtons(screen); - for (int k = 0; k < buttons.size(); k++) { - AbstractWidget ShareToLanOld = buttons.get(k); - if (buttons.size() != 0 && ShareToLanOld.getMessage().getString() - .equals(new TranslatableComponent("menu.shareToLan").getString())) { - AbstractWidget ShareToLanNew = new Button(ShareToLanOld.x, ShareToLanOld.y, ShareToLanOld.getWidth(), ShareToLanOld.getHeight(),new TranslatableComponent("menu.shareToLan"), - (button) -> client.setScreen(new ShareToLanScreenNew(screen))); - ShareToLanNew.active = ShareToLanOld.active; - buttons.remove(ShareToLanOld); - buttons.add(ShareToLanNew); - } - } + public static void afterScreenInit(Minecraft client, Screen screen, int i, int j) { + if (screen instanceof PauseScreen) { + final List buttons = Screens.getButtons(screen); + for (int k = 0; k < buttons.size(); k++) { + AbstractWidget ShareToLanOld = buttons.get(k); + if (buttons.size() != 0 && ShareToLanOld.getMessage().getString().equals(new TranslatableComponent("menu.shareToLan").getString())) { + AbstractWidget ShareToLanNew = new Button(ShareToLanOld.x, ShareToLanOld.y, ShareToLanOld.getWidth(), ShareToLanOld.getHeight(),new TranslatableComponent("menu.shareToLan"), + (button) -> client.setScreen(new ShareToLanScreenNew(screen))); + ShareToLanNew.active = ShareToLanOld.active; + buttons.remove(ShareToLanOld); + buttons.add(ShareToLanNew); } + } } + } - private void onServerLoad(MinecraftServer server) { - MCWiFiPnPUnit.ReadingConfig(server); - } + private void onServerLoad(MinecraftServer server) { + MCWiFiPnPUnit.ReadingConfig(server); + } - private void onServerStop(MinecraftServer server) { - MCWiFiPnPUnit.CloseUPnPPort(server); - } - - public static void setMaxPlayers(IntegratedServer server, int num) { - PlayerList playerList = server.getPlayerList(); - ((PlayerListAccessor)playerList).setMaxPlayers(num); - } + private void onServerStop(MinecraftServer server) { + MCWiFiPnPUnit.CloseUPnPPort(server); + } } diff --git a/fabric/src/main/resources/mcwifipnp.mixins.json b/fabric/src/main/resources/mcwifipnp.mixins.json deleted file mode 100644 index ea4fcdee..00000000 --- a/fabric/src/main/resources/mcwifipnp.mixins.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "required": true, - "minVersion": "0.8", - "package": "io.github.satxm.mcwifipnp.mixin", - "compatibilityLevel": "JAVA_16", - "client": [ - "PlayerListAccessor" - ], - "injectors": { - "defaultRequire": 1 - } -} \ No newline at end of file diff --git a/forge/build.gradle b/forge/build.gradle index 81a56325..3e77731b 100644 --- a/forge/build.gradle +++ b/forge/build.gradle @@ -1,7 +1,8 @@ plugins { - id 'eclipse' - id 'idea' - id 'net.minecraftforge.gradle' version '5.1+' + id 'eclipse' + id 'idea' + id 'net.minecraftforge.gradle' version '5.1+' + id 'org.spongepowered.mixin' version '0.7.+' } archivesBaseName = project.archives_base_name @@ -13,86 +14,98 @@ java.toolchain.languageVersion = JavaLanguageVersion.of(16) println('Java: ' + System.getProperty('java.version') + ' JVM: ' + System.getProperty('java.vm.version') + '(' + System.getProperty('java.vendor') + ') Arch: ' + System.getProperty('os.arch')) minecraft { - mappings channel: 'official', version: project.minecraft_version + mappings channel: 'official', version: project.minecraft_version - accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') + accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') - runs { - client { - workingDirectory project.file('run') - property 'forge.logging.markers', 'REGISTRIES' - property 'forge.logging.console.level', 'debug' + runs { + client { + workingDirectory project.file('run') + property 'forge.logging.markers', 'REGISTRIES' + property 'forge.logging.console.level', 'debug' - mods { - mcwifipnp { - source sourceSets.main - } - } + mods { + mcwifipnp { + source sourceSets.main } + } } + } } dependencies { - minecraft "net.minecraftforge:forge:${project.minecraft_version}-${project.forge_version}" + minecraft "net.minecraftforge:forge:${project.minecraft_version}-${project.forge_version}" + annotationProcessor 'org.spongepowered:mixin:0.8.5:processor' } afterEvaluate { - tasks.withType(JavaCompile) { - options.compilerArgs << "-Xmaxerrs" << "2000" - } + tasks.withType(JavaCompile) { + options.compilerArgs << "-Xmaxerrs" << "2000" + } } sourceSets { - main { - java { - srcDir "../src/main/java" - } - resources { - srcDir "../src/main/resources" - } + main { + java { + srcDir "../src/main/java" } + resources { + srcDir "../src/main/resources" + } + } +} + + +mixin { + // MixinGradle Settings + add sourceSets.main, 'mcwifipnp.refmap.json' + config 'mcwifipnp.mixins.json' + + debug.verbose = true + debug.export = true } jar { - manifest { - attributes([ - "Specification-Title": "LAN World Plug-n-Play", - "Specification-Vendor": "Satxm", - "Specification-Version": "1", - "Implementation-Title": project.name, - "Implementation-Version": "${version}", - "Implementation-Vendor": "Satxm", - "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"), - ]) - } - from("../LICENSE") { - } + manifest { + attributes([ + "Specification-Title": "LAN World Plug-n-Play", + "Specification-Vendor": "Satxm", + "Specification-Version": "1", + "Implementation-Title": project.name, + "Implementation-Version": "${version}", + "Implementation-Vendor": "Satxm", + "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"), + "MixinConfigs": "mcwifipnp.mixins.json" + ]) + } + from("../LICENSE") { + } } java { - withSourcesJar() + withSourcesJar() } def replaceResources = tasks.register("replaceResources", Copy) { - it.outputs.upToDateWhen { false } - it.from(sourceSets.main.resources) { - include "META-INF/mods.toml" - expand 'version': project.mod_version, 'mc_version': project.forge_minecraft_version_range, 'forge_version': project.forge_version_range, "loader_version": project.forge_version_range - } - it.into "$buildDir/resources/main/" + it.outputs.upToDateWhen { false } + it.from(sourceSets.main.resources) { + include "META-INF/mods.toml" + expand 'version': project.mod_version, 'mc_version': project.forge_minecraft_version_range, 'forge_version': project.forge_version_range, "loader_version": project.forge_version_range + } + it.into "$buildDir/resources/main/" } processResources { - duplicatesStrategy(DuplicatesStrategy.FAIL) - exclude('META-INF/mods.toml') - configure { finalizedBy(replaceResources) } + duplicatesStrategy(DuplicatesStrategy.FAIL) + exclude('META-INF/mods.toml') + configure { finalizedBy(replaceResources) } } classes.configure { - dependsOn(replaceResources) + dependsOn(replaceResources) } tasks.withType(JavaCompile).configureEach { - it.options.encoding = "UTF-8" - it.options.release = 16 + it.options.encoding = "UTF-8" + it.options.release = 16 } diff --git a/forge/src/main/java/io/github/satxm/mcwifipnp/MCWiFiPnP.java b/forge/src/main/java/io/github/satxm/mcwifipnp/MCWiFiPnP.java index 09cbc88c..84ca17cd 100644 --- a/forge/src/main/java/io/github/satxm/mcwifipnp/MCWiFiPnP.java +++ b/forge/src/main/java/io/github/satxm/mcwifipnp/MCWiFiPnP.java @@ -4,7 +4,6 @@ import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.screens.PauseScreen; import net.minecraft.client.gui.screens.Screen; -import net.minecraft.client.server.IntegratedServer; import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.server.commands.BanIpCommands; import net.minecraft.server.commands.BanListCommands; @@ -12,7 +11,6 @@ import net.minecraft.server.commands.DeOpCommands; import net.minecraft.server.commands.OpCommand; import net.minecraft.server.commands.WhitelistCommand; -import net.minecraft.server.players.PlayerList; import net.minecraftforge.client.event.GuiScreenEvent; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.SubscribeEvent; @@ -22,51 +20,47 @@ @Mod(MCWiFiPnP.MODID) public class MCWiFiPnP { - public static final String MODID = "mcwifipnp"; + public static final String MODID = "mcwifipnp"; - public MCWiFiPnP() { - MinecraftForge.EVENT_BUS.register(this); - MinecraftForge.EVENT_BUS.addListener(this::ChangeButton); - } + public MCWiFiPnP() { + MinecraftForge.EVENT_BUS.register(this); + MinecraftForge.EVENT_BUS.addListener(this::ChangeButton); + } - @SubscribeEvent - public void ChangeButton(GuiScreenEvent.InitGuiEvent.Post event) { - Minecraft client = Minecraft.getInstance(); - Screen screen = event.getGui(); - if (screen instanceof PauseScreen && event.getWidgetList().size() != 0) { - for (int k = 0; k < event.getWidgetList().size(); k++) { - Button ShareToLanOld = (Button) event.getWidgetList().get(k); - if (ShareToLanOld.getMessage().getString() - .equals(new TranslatableComponent("menu.shareToLan").getString())) { - Button ShareToLanNew = new Button(ShareToLanOld.x, ShareToLanOld.y, ShareToLanOld.getWidth(), ShareToLanOld.getHeight(), new TranslatableComponent("menu.shareToLan"), - (button) -> client.setScreen(new ShareToLanScreenNew(screen))); - ShareToLanNew.active = ShareToLanOld.active; - event.removeWidget(ShareToLanOld); - event.addWidget(ShareToLanNew); - } - } + @SubscribeEvent + public void ChangeButton(GuiScreenEvent.InitGuiEvent.Post event) { + Minecraft client = Minecraft.getInstance(); + Screen screen = event.getGui(); + if (screen instanceof PauseScreen && event.getWidgetList().size() != 0) { + for (int k = 0; k < event.getWidgetList().size(); k++) { + Button ShareToLanOld = (Button) event.getWidgetList().get(k); + if (ShareToLanOld.getMessage().getString() + .equals(new TranslatableComponent("menu.shareToLan").getString())) { + Button ShareToLanNew = new Button(ShareToLanOld.x, ShareToLanOld.y, ShareToLanOld.getWidth(), ShareToLanOld.getHeight(), new TranslatableComponent("menu.shareToLan"), + (button) -> client.setScreen(new ShareToLanScreenNew(screen))); + ShareToLanNew.active = ShareToLanOld.active; + event.removeWidget(ShareToLanOld); + event.addWidget(ShareToLanNew); } + } } + } - @SubscribeEvent - public void onServerStarting(FMLServerStartingEvent event) { - MCWiFiPnPUnit.ReadingConfig(event.getServer()); - DeOpCommands.register(event.getServer().getCommands().getDispatcher()); - OpCommand.register(event.getServer().getCommands().getDispatcher()); - WhitelistCommand.register(event.getServer().getCommands().getDispatcher()); - BanIpCommands.register(event.getServer().getCommands().getDispatcher()); - BanListCommands.register(event.getServer().getCommands().getDispatcher()); - BanPlayerCommands.register(event.getServer().getCommands().getDispatcher()); - } + @SubscribeEvent + public void onServerStarting(FMLServerStartingEvent event) { + MCWiFiPnPUnit.ReadingConfig(event.getServer()); + DeOpCommands.register(event.getServer().getCommands().getDispatcher()); + OpCommand.register(event.getServer().getCommands().getDispatcher()); + WhitelistCommand.register(event.getServer().getCommands().getDispatcher()); + BanIpCommands.register(event.getServer().getCommands().getDispatcher()); + BanListCommands.register(event.getServer().getCommands().getDispatcher()); + BanPlayerCommands.register(event.getServer().getCommands().getDispatcher()); + ForceOfflineCommand.register(event.getServer().getCommands().getDispatcher()); + } - @SubscribeEvent - public void onServerStopping(FMLServerStoppingEvent event) { - MCWiFiPnPUnit.CloseUPnPPort(event.getServer()); - } - - public static void setMaxPlayers(IntegratedServer server, int num) { - PlayerList playerList = server.getPlayerList(); - playerList.maxPlayers = num; - } + @SubscribeEvent + public void onServerStopping(FMLServerStoppingEvent event) { + MCWiFiPnPUnit.CloseUPnPPort(event.getServer()); + } } diff --git a/forge/src/main/resources/META-INF/accesstransformer.cfg b/forge/src/main/resources/META-INF/accesstransformer.cfg deleted file mode 100644 index 94ee3f3d..00000000 --- a/forge/src/main/resources/META-INF/accesstransformer.cfg +++ /dev/null @@ -1 +0,0 @@ -public-f net.minecraft.server.players.PlayerList f_11193_ # int maxPlayers \ No newline at end of file diff --git a/forge/src/main/resources/META-INF/mods.toml b/forge/src/main/resources/META-INF/mods.toml index a4df99d2..b3bd5afb 100644 --- a/forge/src/main/resources/META-INF/mods.toml +++ b/forge/src/main/resources/META-INF/mods.toml @@ -13,15 +13,15 @@ authors="Satxm" description="A Minecraft LAN World Tool With WLAN UPnP." [[dependencies.mcwifipnp]] - modId="forge" - mandatory=true - versionRange="${forge_version}" - ordering="NONE" - side="CLIENT" + modId="forge" + mandatory=true + versionRange="${forge_version}" + ordering="NONE" + side="CLIENT" [[dependencies.mcwifipnp]] - modId="minecraft" - mandatory=true - versionRange="${mc_version}" - ordering="NONE" - side="CLIENT" + modId="minecraft" + mandatory=true + versionRange="${mc_version}" + ordering="NONE" + side="CLIENT" diff --git a/forge/src/main/resources/pack.mcmeta b/forge/src/main/resources/pack.mcmeta deleted file mode 100644 index b43921e4..00000000 --- a/forge/src/main/resources/pack.mcmeta +++ /dev/null @@ -1,7 +0,0 @@ -{ - "pack": { - "description": "LAN World Plug-n-Play", - "pack_format": 7, - "_comment": "A Minecraft LAN World Tool With WLAN UPnP." - } -} diff --git a/gradle.properties b/gradle.properties index 8b731a4c..a7c9a9f2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,14 +2,12 @@ org.gradle.jvmargs = -Xmx4G org.gradle.daemon = false # Mod Properties -mod_version = 1.7.1 +mod_version = 1.7.2 maven_group = io.github.satxm.mcwifipnp archives_base_name = mcwifipnp minecraft_version = 1.17.1 -minecraft_version = 1.17.1 - # Forge Properties on https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json forge_version = 37.1.1 diff --git a/settings.gradle b/settings.gradle index c8fcdda5..02e4a4e3 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,15 +1,15 @@ pluginManagement { - repositories { - maven { - name = 'Fabric' - url = 'https://maven.fabricmc.net/' - } - maven { - name = 'Forge' - url = 'https://maven.minecraftforge.net' - } - gradlePluginPortal() + repositories { + maven { + name = 'Fabric' + url = 'https://maven.fabricmc.net/' } + maven { + name = 'Forge' + url = 'https://maven.minecraftforge.net' + } + gradlePluginPortal() + } } include("fabric") diff --git a/src/main/java/com/dosse/upnp/Gateway.java b/src/main/java/com/dosse/upnp/Gateway.java index 56f40a92..e8189206 100644 --- a/src/main/java/com/dosse/upnp/Gateway.java +++ b/src/main/java/com/dosse/upnp/Gateway.java @@ -39,171 +39,171 @@ */ class Gateway { - private Inet4Address iface; - private InetAddress routerip; + private Inet4Address iface; + private InetAddress routerip; - private String serviceType = null, controlURL = null; + private String serviceType = null, controlURL = null; - public Gateway(byte[] data, Inet4Address ip, InetAddress gatewayip) throws Exception { - iface = ip; - routerip = gatewayip; - String location = null; - StringTokenizer st = new StringTokenizer(new String(data), "\n"); - while (st.hasMoreTokens()) { - String s = st.nextToken().trim(); - if (s.isEmpty() || s.startsWith("HTTP/1.") || s.startsWith("NOTIFY *")) { - continue; - } - String name = s.substring(0, s.indexOf(':')), val = s.length() >= name.length() ? s.substring(name.length() + 1).trim() : null; - if (name.equalsIgnoreCase("location")) { - location = val; - } - } - if (location == null) { - throw new Exception("Unsupported Gateway"); - } - Document d; - d = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(location); - NodeList services = d.getElementsByTagName("service"); - for (int i = 0; i < services.getLength(); i++) { - Node service = services.item(i); - NodeList n = service.getChildNodes(); - String serviceType = null, controlURL = null; - for (int j = 0; j < n.getLength(); j++) { - Node x = n.item(j); - if (x.getNodeName().trim().equalsIgnoreCase("serviceType")) { - serviceType = x.getFirstChild().getNodeValue(); - } else if (x.getNodeName().trim().equalsIgnoreCase("controlURL")) { - controlURL = x.getFirstChild().getNodeValue(); - } - } - if (serviceType == null || controlURL == null) { - continue; - } - if (serviceType.trim().toLowerCase().contains(":wanipconnection:") || serviceType.trim().toLowerCase().contains(":wanpppconnection:")) { - this.serviceType = serviceType.trim(); - this.controlURL = controlURL.trim(); - } - } - if (controlURL == null) { - throw new Exception("Unsupported Gateway"); - } - int slash = location.indexOf("/", 7); //finds first slash after http:// - if (slash == -1) { - throw new Exception("Unsupported Gateway"); - } - location = location.substring(0, slash); - if (!controlURL.startsWith("/")) { - controlURL = "/" + controlURL; + public Gateway(byte[] data, Inet4Address ip, InetAddress gatewayip) throws Exception { + iface = ip; + routerip = gatewayip; + String location = null; + StringTokenizer st = new StringTokenizer(new String(data), "\n"); + while (st.hasMoreTokens()) { + String s = st.nextToken().trim(); + if (s.isEmpty() || s.startsWith("HTTP/1.") || s.startsWith("NOTIFY *")) { + continue; + } + String name = s.substring(0, s.indexOf(':')), val = s.length() >= name.length() ? s.substring(name.length() + 1).trim() : null; + if (name.equalsIgnoreCase("location")) { + location = val; + } + } + if (location == null) { + throw new Exception("Unsupported Gateway"); + } + Document d; + d = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(location); + NodeList services = d.getElementsByTagName("service"); + for (int i = 0; i < services.getLength(); i++) { + Node service = services.item(i); + NodeList n = service.getChildNodes(); + String serviceType = null, controlURL = null; + for (int j = 0; j < n.getLength(); j++) { + Node x = n.item(j); + if (x.getNodeName().trim().equalsIgnoreCase("serviceType")) { + serviceType = x.getFirstChild().getNodeValue(); + } else if (x.getNodeName().trim().equalsIgnoreCase("controlURL")) { + controlURL = x.getFirstChild().getNodeValue(); } - controlURL = location + controlURL; + } + if (serviceType == null || controlURL == null) { + continue; + } + if (serviceType.trim().toLowerCase().contains(":wanipconnection:") || serviceType.trim().toLowerCase().contains(":wanpppconnection:")) { + this.serviceType = serviceType.trim(); + this.controlURL = controlURL.trim(); + } } + if (controlURL == null) { + throw new Exception("Unsupported Gateway"); + } + int slash = location.indexOf("/", 7); //finds first slash after http:// + if (slash == -1) { + throw new Exception("Unsupported Gateway"); + } + location = location.substring(0, slash); + if (!controlURL.startsWith("/")) { + controlURL = "/" + controlURL; + } + controlURL = location + controlURL; + } - private Map command(String action, Map params) throws Exception { - Map ret = new HashMap(); - String soap = "\r\n" + "" - + "" - + ""; - if (params != null) { - for (Map.Entry entry : params.entrySet()) { - soap += "<" + entry.getKey() + ">" + entry.getValue() + ""; - } - } - soap += ""; - byte[] req = soap.getBytes(); - HttpURLConnection conn = (HttpURLConnection) new URL(controlURL).openConnection(); - conn.setRequestMethod("POST"); - conn.setDoOutput(true); - conn.setRequestProperty("Content-Type", "text/xml"); - conn.setRequestProperty("SOAPAction", "\"" + serviceType + "#" + action + "\""); - conn.setRequestProperty("Connection", "Close"); - conn.setRequestProperty("Content-Length", "" + req.length); - conn.getOutputStream().write(req); - Document d = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(conn.getInputStream()); - NodeIterator iter = ((DocumentTraversal) d).createNodeIterator(d.getDocumentElement(), NodeFilter.SHOW_ELEMENT, null, true); - Node n; - while ((n = iter.nextNode()) != null) { - try { - if (n.getFirstChild().getNodeType() == Node.TEXT_NODE) { - ret.put(n.getNodeName(), n.getTextContent()); - } - } catch (Throwable t) { - } + private Map command(String action, Map params) throws Exception { + Map ret = new HashMap(); + String soap = "\r\n" + "" + + "" + + ""; + if (params != null) { + for (Map.Entry entry : params.entrySet()) { + soap += "<" + entry.getKey() + ">" + entry.getValue() + ""; + } + } + soap += ""; + byte[] req = soap.getBytes(); + HttpURLConnection conn = (HttpURLConnection) new URL(controlURL).openConnection(); + conn.setRequestMethod("POST"); + conn.setDoOutput(true); + conn.setRequestProperty("Content-Type", "text/xml"); + conn.setRequestProperty("SOAPAction", "\"" + serviceType + "#" + action + "\""); + conn.setRequestProperty("Connection", "Close"); + conn.setRequestProperty("Content-Length", "" + req.length); + conn.getOutputStream().write(req); + Document d = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(conn.getInputStream()); + NodeIterator iter = ((DocumentTraversal) d).createNodeIterator(d.getDocumentElement(), NodeFilter.SHOW_ELEMENT, null, true); + Node n; + while ((n = iter.nextNode()) != null) { + try { + if (n.getFirstChild().getNodeType() == Node.TEXT_NODE) { + ret.put(n.getNodeName(), n.getTextContent()); } - conn.disconnect(); - return ret; + } catch (Throwable t) { + } } + conn.disconnect(); + return ret; + } - public String getGatewayIP(){ return routerip.getHostAddress(); } + public String getGatewayIP(){ return routerip.getHostAddress(); } - public String getLocalIP() { - return iface.getHostAddress(); - } + public String getLocalIP() { + return iface.getHostAddress(); + } - public String getExternalIP() { - try { - Map r = command("GetExternalIPAddress", null); - return r.get("NewExternalIPAddress"); - } catch (Throwable t) { - return null; - } + public String getExternalIP() { + try { + Map r = command("GetExternalIPAddress", null); + return r.get("NewExternalIPAddress"); + } catch (Throwable t) { + return null; } + } - public boolean openPort(int port, boolean udp, String display) { - if (port < 0 || port > 65535) { - throw new IllegalArgumentException("Invalid port"); - } - Map params = new HashMap(); - params.put("NewRemoteHost", ""); - params.put("NewProtocol", udp ? "UDP" : "TCP"); - params.put("NewInternalClient", iface.getHostAddress()); - params.put("NewExternalPort", "" + port); - params.put("NewInternalPort", "" + port); - params.put("NewEnabled", "1"); - params.put("NewPortMappingDescription", display); - params.put("NewLeaseDuration", "0"); - try { - Map r = command("AddPortMapping", params); - return r.get("errorCode") == null; - } catch (Exception ex) { - return false; - } + public boolean openPort(int port, boolean udp, String display) { + if (port < 0 || port > 65535) { + throw new IllegalArgumentException("Invalid port"); } - - public boolean closePort(int port, boolean udp) { - if (port < 0 || port > 65535) { - throw new IllegalArgumentException("Invalid port"); - } - Map params = new HashMap(); - params.put("NewRemoteHost", ""); - params.put("NewProtocol", udp ? "UDP" : "TCP"); - params.put("NewExternalPort", "" + port); - try { - command("DeletePortMapping", params); - return true; - } catch (Exception ex) { - return false; - } + Map params = new HashMap(); + params.put("NewRemoteHost", ""); + params.put("NewProtocol", udp ? "UDP" : "TCP"); + params.put("NewInternalClient", iface.getHostAddress()); + params.put("NewExternalPort", "" + port); + params.put("NewInternalPort", "" + port); + params.put("NewEnabled", "1"); + params.put("NewPortMappingDescription", display); + params.put("NewLeaseDuration", "0"); + try { + Map r = command("AddPortMapping", params); + return r.get("errorCode") == null; + } catch (Exception ex) { + return false; } + } - public boolean isMapped(int port, boolean udp) { - if (port < 0 || port > 65535) { - throw new IllegalArgumentException("Invalid port"); - } - Map params = new HashMap(); - params.put("NewRemoteHost", ""); - params.put("NewProtocol", udp ? "UDP" : "TCP"); - params.put("NewExternalPort", "" + port); - try { - Map r = command("GetSpecificPortMappingEntry", params); - if (r.get("errorCode") != null) { - throw new Exception(); - } - return r.get("NewInternalPort") != null; - } catch (Exception ex) { - return false; - } + public boolean closePort(int port, boolean udp) { + if (port < 0 || port > 65535) { + throw new IllegalArgumentException("Invalid port"); + } + Map params = new HashMap(); + params.put("NewRemoteHost", ""); + params.put("NewProtocol", udp ? "UDP" : "TCP"); + params.put("NewExternalPort", "" + port); + try { + command("DeletePortMapping", params); + return true; + } catch (Exception ex) { + return false; + } + } + public boolean isMapped(int port, boolean udp) { + if (port < 0 || port > 65535) { + throw new IllegalArgumentException("Invalid port"); + } + Map params = new HashMap(); + params.put("NewRemoteHost", ""); + params.put("NewProtocol", udp ? "UDP" : "TCP"); + params.put("NewExternalPort", "" + port); + try { + Map r = command("GetSpecificPortMappingEntry", params); + if (r.get("errorCode") != null) { + throw new Exception(); + } + return r.get("NewInternalPort") != null; + } catch (Exception ex) { + return false; } + } + } diff --git a/src/main/java/com/dosse/upnp/GatewayFinder.java b/src/main/java/com/dosse/upnp/GatewayFinder.java index f1a775b6..5fda66a1 100644 --- a/src/main/java/com/dosse/upnp/GatewayFinder.java +++ b/src/main/java/com/dosse/upnp/GatewayFinder.java @@ -34,108 +34,108 @@ */ abstract class GatewayFinder { - private static final String[] SEARCH_MESSAGES; + private static final String[] SEARCH_MESSAGES; - static { - LinkedList m = new LinkedList(); - for (String type : new String[]{"urn:schemas-upnp-org:device:InternetGatewayDevice:1", "urn:schemas-upnp-org:service:WANIPConnection:1", "urn:schemas-upnp-org:service:WANPPPConnection:1"}) { - m.add("M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nST: " + type + "\r\nMAN: \"ssdp:discover\"\r\nMX: 2\r\n\r\n"); - } - SEARCH_MESSAGES = m.toArray(new String[]{}); + static { + LinkedList m = new LinkedList(); + for (String type : new String[]{"urn:schemas-upnp-org:device:InternetGatewayDevice:1", "urn:schemas-upnp-org:service:WANIPConnection:1", "urn:schemas-upnp-org:service:WANPPPConnection:1"}) { + m.add("M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nST: " + type + "\r\nMAN: \"ssdp:discover\"\r\nMX: 2\r\n\r\n"); } + SEARCH_MESSAGES = m.toArray(new String[]{}); + } - private class GatewayListener extends Thread { + private class GatewayListener extends Thread { - private Inet4Address ip; - private String req; + private Inet4Address ip; + private String req; - public GatewayListener(Inet4Address ip, String req) { - setName("WaifUPnP - Gateway Listener"); - this.ip = ip; - this.req = req; - } + public GatewayListener(Inet4Address ip, String req) { + setName("WaifUPnP - Gateway Listener"); + this.ip = ip; + this.req = req; + } - @Override - public void run() { - boolean foundgw = false; - Gateway gw = null; - try { - byte[] req = this.req.getBytes(); - DatagramSocket s = new DatagramSocket(new InetSocketAddress(ip, 0)); - s.send(new DatagramPacket(req, req.length, new InetSocketAddress("239.255.255.250", 1900))); - s.setSoTimeout(3000); - for (;;) { - try { - DatagramPacket recv = new DatagramPacket(new byte[1536], 1536); - s.receive(recv); - gw = new Gateway(recv.getData(), ip, recv.getAddress()); - String extIp = gw.getExternalIP(); - if( (extIp!=null) && (!extIp.equalsIgnoreCase("0.0.0.0")) ){ //Exclude gateways without an external IP - gatewayFound(gw); - foundgw = true; - } - } catch (SocketTimeoutException t) { - break; - } catch (Throwable t) { - } - } - } catch (Throwable t) { - } - if( (!foundgw) && (gw!=null)){ //Pick the last GW if none have an external IP - internet not up yet?? - gatewayFound(gw); + @Override + public void run() { + boolean foundgw = false; + Gateway gw = null; + try { + byte[] req = this.req.getBytes(); + DatagramSocket s = new DatagramSocket(new InetSocketAddress(ip, 0)); + s.send(new DatagramPacket(req, req.length, new InetSocketAddress("239.255.255.250", 1900))); + s.setSoTimeout(3000); + for (;;) { + try { + DatagramPacket recv = new DatagramPacket(new byte[1536], 1536); + s.receive(recv); + gw = new Gateway(recv.getData(), ip, recv.getAddress()); + String extIp = gw.getExternalIP(); + if( (extIp!=null) && (!extIp.equalsIgnoreCase("0.0.0.0")) ){ //Exclude gateways without an external IP + gatewayFound(gw); + foundgw = true; } + } catch (SocketTimeoutException t) { + break; + } catch (Throwable t) { + } } + } catch (Throwable t) { + } + if( (!foundgw) && (gw!=null)){ //Pick the last GW if none have an external IP - internet not up yet?? + gatewayFound(gw); + } } + } - private LinkedList listeners = new LinkedList(); + private LinkedList listeners = new LinkedList(); - public GatewayFinder() { - for (Inet4Address ip : getLocalIPs()) { - for (String req : SEARCH_MESSAGES) { - GatewayListener l = new GatewayListener(ip, req); - l.start(); - listeners.add(l); - } - } + public GatewayFinder() { + for (Inet4Address ip : getLocalIPs()) { + for (String req : SEARCH_MESSAGES) { + GatewayListener l = new GatewayListener(ip, req); + l.start(); + listeners.add(l); + } } + } - public boolean isSearching() { - for (GatewayListener l : listeners) { - if (l.isAlive()) { - return true; - } - } - return false; + public boolean isSearching() { + for (GatewayListener l : listeners) { + if (l.isAlive()) { + return true; + } } + return false; + } - public abstract void gatewayFound(Gateway g); + public abstract void gatewayFound(Gateway g); - private static Inet4Address[] getLocalIPs() { - LinkedList ret = new LinkedList(); + private static Inet4Address[] getLocalIPs() { + LinkedList ret = new LinkedList(); + try { + Enumeration ifaces = NetworkInterface.getNetworkInterfaces(); + while (ifaces.hasMoreElements()) { try { - Enumeration ifaces = NetworkInterface.getNetworkInterfaces(); - while (ifaces.hasMoreElements()) { - try { - NetworkInterface iface = ifaces.nextElement(); - if (!iface.isUp() || iface.isLoopback() || iface.isVirtual() || iface.isPointToPoint()) { - continue; - } - Enumeration addrs = iface.getInetAddresses(); - if (addrs == null) { - continue; - } - while (addrs.hasMoreElements()) { - InetAddress addr = addrs.nextElement(); - if (addr instanceof Inet4Address) { - ret.add((Inet4Address) addr); - } - } - } catch (Throwable t) { - } + NetworkInterface iface = ifaces.nextElement(); + if (!iface.isUp() || iface.isLoopback() || iface.isVirtual() || iface.isPointToPoint()) { + continue; + } + Enumeration addrs = iface.getInetAddresses(); + if (addrs == null) { + continue; + } + while (addrs.hasMoreElements()) { + InetAddress addr = addrs.nextElement(); + if (addr instanceof Inet4Address) { + ret.add((Inet4Address) addr); } + } } catch (Throwable t) { } - return ret.toArray(new Inet4Address[]{}); + } + } catch (Throwable t) { } + return ret.toArray(new Inet4Address[]{}); + } } diff --git a/src/main/java/com/dosse/upnp/UPnP.java b/src/main/java/com/dosse/upnp/UPnP.java index a268ccb7..bbc12d3a 100644 --- a/src/main/java/com/dosse/upnp/UPnP.java +++ b/src/main/java/com/dosse/upnp/UPnP.java @@ -26,139 +26,139 @@ */ public class UPnP { - private static Gateway defaultGW = null; - private static final GatewayFinder finder = new GatewayFinder() { - @Override - public void gatewayFound(Gateway g) { - synchronized (finder) { - if (defaultGW == null) { - defaultGW = g; - } - } + private static Gateway defaultGW = null; + private static final GatewayFinder finder = new GatewayFinder() { + @Override + public void gatewayFound(Gateway g) { + synchronized (finder) { + if (defaultGW == null) { + defaultGW = g; } - }; - - /** - * Waits for UPnP to be initialized (takes ~3 seconds).
- * It is not necessary to call this method manually before using UPnP functions - */ - public static void waitInit() { - while (finder.isSearching()) { - try { - Thread.sleep(1); - } catch (InterruptedException ex) { - } - } - } - - /** - * Is there an UPnP gateway?
- * This method is blocking if UPnP is still initializing
- * All UPnP commands will fail if UPnP is not available - * - * @return true if available, false if not - */ - public static boolean isUPnPAvailable(){ - waitInit(); - return defaultGW!=null; + } } + }; - /** - * Opens a TCP port on the gateway - * - * @param port TCP port (0-65535) - * @return true if the operation was successful, false otherwise - */ - public static boolean openPortTCP(int port, String display) { - if(!isUPnPAvailable()) return false; - return defaultGW.openPort(port, false, display); - } - - /** - * Opens a UDP port on the gateway - * - * @param port UDP port (0-65535) - * @return true if the operation was successful, false otherwise - */ - public static boolean openPortUDP(int port, String display) { - if(!isUPnPAvailable()) return false; - return defaultGW.openPort(port, true, display); - } - - /** - * Closes a TCP port on the gateway
- * Most gateways seem to refuse to do this - * - * @param port TCP port (0-65535) - * @return true if the operation was successful, false otherwise - */ - public static boolean closePortTCP(int port) { - if(!isUPnPAvailable()) return false; - return defaultGW.closePort(port, false); - } - - /** - * Closes a UDP port on the gateway
- * Most gateways seem to refuse to do this - * - * @param port UDP port (0-65535) - * @return true if the operation was successful, false otherwise - */ - public static boolean closePortUDP(int port) { - if(!isUPnPAvailable()) return false; - return defaultGW.closePort(port, true); - } - - /** - * Checks if a TCP port is mapped
- * - * @param port TCP port (0-65535) - * @return true if the port is mapped, false otherwise - */ - public static boolean isMappedTCP(int port) { - if(!isUPnPAvailable()) return false; - return defaultGW.isMapped(port, false); - } - - /** - * Checks if a UDP port is mapped
- * - * @param port UDP port (0-65535) - * @return true if the port is mapped, false otherwise - */ - public static boolean isMappedUDP(int port) { - if(!isUPnPAvailable()) return false; - return defaultGW.isMapped(port, true); - } - - /** - * Gets the external IP address of the default gateway - * - * @return external IP address as string, or null if not available - */ - public static String getExternalIP(){ - if(!isUPnPAvailable()) return null; - return defaultGW.getExternalIP(); - } - - /** - * Gets the internal IP address of this machine - * - * @return internal IP address as string, or null if not available - */ - public static String getLocalIP(){ - if(!isUPnPAvailable()) return null; - return defaultGW.getLocalIP(); + /** + * Waits for UPnP to be initialized (takes ~3 seconds).
+ * It is not necessary to call this method manually before using UPnP functions + */ + public static void waitInit() { + while (finder.isSearching()) { + try { + Thread.sleep(1); + } catch (InterruptedException ex) { + } } + } + + /** + * Is there an UPnP gateway?
+ * This method is blocking if UPnP is still initializing
+ * All UPnP commands will fail if UPnP is not available + * + * @return true if available, false if not + */ + public static boolean isUPnPAvailable(){ + waitInit(); + return defaultGW!=null; + } - /** - * Gets the IP address of the router - * - * @return internal IP address as string, or null if not available - */ - public static String getDefaultGatewayIP(){ - if(!isUPnPAvailable()) return null; - return defaultGW.getGatewayIP(); - } + /** + * Opens a TCP port on the gateway + * + * @param port TCP port (0-65535) + * @return true if the operation was successful, false otherwise + */ + public static boolean openPortTCP(int port, String display) { + if(!isUPnPAvailable()) return false; + return defaultGW.openPort(port, false, display); + } + + /** + * Opens a UDP port on the gateway + * + * @param port UDP port (0-65535) + * @return true if the operation was successful, false otherwise + */ + public static boolean openPortUDP(int port, String display) { + if(!isUPnPAvailable()) return false; + return defaultGW.openPort(port, true, display); + } + + /** + * Closes a TCP port on the gateway
+ * Most gateways seem to refuse to do this + * + * @param port TCP port (0-65535) + * @return true if the operation was successful, false otherwise + */ + public static boolean closePortTCP(int port) { + if(!isUPnPAvailable()) return false; + return defaultGW.closePort(port, false); + } + + /** + * Closes a UDP port on the gateway
+ * Most gateways seem to refuse to do this + * + * @param port UDP port (0-65535) + * @return true if the operation was successful, false otherwise + */ + public static boolean closePortUDP(int port) { + if(!isUPnPAvailable()) return false; + return defaultGW.closePort(port, true); + } + + /** + * Checks if a TCP port is mapped
+ * + * @param port TCP port (0-65535) + * @return true if the port is mapped, false otherwise + */ + public static boolean isMappedTCP(int port) { + if(!isUPnPAvailable()) return false; + return defaultGW.isMapped(port, false); + } + + /** + * Checks if a UDP port is mapped
+ * + * @param port UDP port (0-65535) + * @return true if the port is mapped, false otherwise + */ + public static boolean isMappedUDP(int port) { + if(!isUPnPAvailable()) return false; + return defaultGW.isMapped(port, true); + } + + /** + * Gets the external IP address of the default gateway + * + * @return external IP address as string, or null if not available + */ + public static String getExternalIP(){ + if(!isUPnPAvailable()) return null; + return defaultGW.getExternalIP(); + } + + /** + * Gets the internal IP address of this machine + * + * @return internal IP address as string, or null if not available + */ + public static String getLocalIP(){ + if(!isUPnPAvailable()) return null; + return defaultGW.getLocalIP(); + } + + /** + * Gets the IP address of the router + * + * @return internal IP address as string, or null if not available + */ + public static String getDefaultGatewayIP(){ + if(!isUPnPAvailable()) return null; + return defaultGW.getGatewayIP(); + } } diff --git a/src/main/java/io/github/satxm/mcwifipnp/ForceOfflineCommand.java b/src/main/java/io/github/satxm/mcwifipnp/ForceOfflineCommand.java new file mode 100644 index 00000000..a8cc45ce --- /dev/null +++ b/src/main/java/io/github/satxm/mcwifipnp/ForceOfflineCommand.java @@ -0,0 +1,128 @@ +package io.github.satxm.mcwifipnp; + +import com.mojang.authlib.GameProfile; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.commands.arguments.GameProfileArgument; +import net.minecraft.network.chat.ComponentUtils; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.players.PlayerList; +import org.apache.commons.lang3.StringUtils; + +public class ForceOfflineCommand { + private static final SimpleCommandExceptionType ERROR_ALREADY_IN = new SimpleCommandExceptionType(new TranslatableComponent("mcwifipnp.commands.forceoffline.add.failed")); + private static final SimpleCommandExceptionType ERROR_NOT_IN = new SimpleCommandExceptionType(new TranslatableComponent("mcwifipnp.commands.forceoffline.remove.failed")); + + public ForceOfflineCommand() { + } + + public static void register(CommandDispatcher commandDispatcher) { + commandDispatcher.register((LiteralArgumentBuilder)((LiteralArgumentBuilder)((LiteralArgumentBuilder)((LiteralArgumentBuilder) Commands.literal("forceoffline").requires((commandSourceStack) -> { + return commandSourceStack.hasPermission(3); + })).then(Commands.literal("list").executes((commandContext) -> { + return showList((CommandSourceStack)commandContext.getSource()); + }))).then(Commands.literal("add").then(Commands.argument("targets", GameProfileArgument.gameProfile()).suggests((commandContext, suggestionsBuilder) -> { + MinecraftServer server = ((CommandSourceStack)commandContext.getSource()).getServer(); + PlayerList playerList = server.getPlayerList(); + MCWiFiPnPUnit.ReadingConfig(server); + MCWiFiPnPUnit.Config cfg = MCWiFiPnPUnit.getConfig(server); + List ForceOfflinePlayers = cfg.ForceOfflinePlayers; + return SharedSuggestionProvider.suggest(playerList.getPlayers().stream().filter((serverPlayer) -> { + return !ForceOfflinePlayers.contains(serverPlayer.getGameProfile().getName()); + }).map((serverPlayer) -> { + return serverPlayer.getGameProfile().getName(); + }), suggestionsBuilder); + }).executes((commandContext) -> { + return addPlayers((CommandSourceStack)commandContext.getSource(), GameProfileArgument.getGameProfiles(commandContext, "targets")); + })))).then(Commands.literal("remove").then(Commands.argument("targets", GameProfileArgument.gameProfile()).suggests((commandContext, suggestionsBuilder) -> { + MinecraftServer server = ((CommandSourceStack)commandContext.getSource()).getServer(); + MCWiFiPnPUnit.ReadingConfig(server); + MCWiFiPnPUnit.Config cfg = MCWiFiPnPUnit.getConfig(server); + List ForceOfflinePlayers = cfg.ForceOfflinePlayers; + return SharedSuggestionProvider.suggest(ForceOfflinePlayers.stream(), suggestionsBuilder); + }).executes((commandContext) -> { + return removePlayers((CommandSourceStack)commandContext.getSource(), GameProfileArgument.getGameProfiles(commandContext, "targets")); + })))); + } + + private static int addPlayers(CommandSourceStack commandSourceStack, Collection collection) throws CommandSyntaxException { + + MinecraftServer server = commandSourceStack.getServer(); + MCWiFiPnPUnit.ReadingConfig(server); + MCWiFiPnPUnit.Config cfg = MCWiFiPnPUnit.getConfig(server); + List ForceOfflinePlayers = cfg.ForceOfflinePlayers; + int i = 0; + Iterator var4 = collection.iterator(); + + while(var4.hasNext()) { + GameProfile gameProfile = (GameProfile)var4.next(); + if (!ForceOfflinePlayers.contains(gameProfile.getName())) { + ForceOfflinePlayers.add(gameProfile.getName()); + MCWiFiPnPUnit.saveConfig(cfg); + commandSourceStack.sendSuccess(new TranslatableComponent("mcwifipnp.commands.forceoffline.add.success", + new Object[] { ComponentUtils.getDisplayName(gameProfile) }), true); + ++i; + } + } + + if (i == 0) { + throw ERROR_ALREADY_IN.create(); + } else { + return i; + } + } + + private static int removePlayers(CommandSourceStack commandSourceStack, Collection collection) throws CommandSyntaxException { + MinecraftServer server = commandSourceStack.getServer(); + MCWiFiPnPUnit.ReadingConfig(server); + MCWiFiPnPUnit.Config cfg = MCWiFiPnPUnit.getConfig(server); + List ForceOfflinePlayers = cfg.ForceOfflinePlayers; + + int i = 0; + Iterator var4 = collection.iterator(); + + while(var4.hasNext()) { + GameProfile gameProfile = (GameProfile)var4.next(); + if (ForceOfflinePlayers.contains(gameProfile.getName())) { + ForceOfflinePlayers.remove(gameProfile.getName()); + MCWiFiPnPUnit.saveConfig(cfg); + commandSourceStack.sendSuccess(new TranslatableComponent("mcwifipnp.commands.forceoffline.remove.success", + new Object[] { ComponentUtils.getDisplayName(gameProfile) }), true); + ++i; + } + } + + if (i == 0) { + throw ERROR_NOT_IN.create(); + } else { + commandSourceStack.getServer().kickUnlistedPlayers(commandSourceStack); + return i; + } + } + + private static int showList(CommandSourceStack commandSourceStack) { + MinecraftServer server = commandSourceStack.getServer(); + MCWiFiPnPUnit.ReadingConfig(server); + MCWiFiPnPUnit.Config cfg = MCWiFiPnPUnit.getConfig(server); + List ForceOfflinePlayers = cfg.ForceOfflinePlayers; + + if (ForceOfflinePlayers.size() == 0) { + commandSourceStack.sendSuccess(new TranslatableComponent("mcwifipnp.commands.forceoffline.none"), false); + } else { + commandSourceStack.sendSuccess(new TranslatableComponent("mcwifipnp.commands.forceoffline.list", + new Object[]{ForceOfflinePlayers.size(), StringUtils.join(ForceOfflinePlayers,", ")}), false); + } + + return ForceOfflinePlayers.size(); + } +} diff --git a/src/main/java/io/github/satxm/mcwifipnp/MCWiFiPnPUnit.java b/src/main/java/io/github/satxm/mcwifipnp/MCWiFiPnPUnit.java index 5597a8ea..9fb53565 100644 --- a/src/main/java/io/github/satxm/mcwifipnp/MCWiFiPnPUnit.java +++ b/src/main/java/io/github/satxm/mcwifipnp/MCWiFiPnPUnit.java @@ -12,14 +12,9 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.WeakHashMap; +import java.util.*; +import io.github.satxm.mcwifipnp.mixin.PlayerListAccessor; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -47,279 +42,283 @@ import net.minecraft.world.level.storage.LevelResource; public class MCWiFiPnPUnit { - private static final Map configMap = Collections.synchronizedMap(new WeakHashMap<>()); - private static final Gson gson = new GsonBuilder().create(); - private static final Logger LOGGER = LogManager.getLogger(MCWiFiPnP.class); + private static final Map configMap = Collections.synchronizedMap(new WeakHashMap<>()); + private static final Gson gson = new GsonBuilder().create(); + private static final Logger LOGGER = LogManager.getLogger(MCWiFiPnP.class); - public static Config getConfig(MinecraftServer server) { - return Objects.requireNonNull(configMap.get(server), "no config for server???"); - } + public static Config getConfig(MinecraftServer server) { + return Objects.requireNonNull(configMap.get(server), "no config for server???"); + } - public static void OpenToLan() { - Minecraft client = Minecraft.getInstance(); - IntegratedServer server = client.getSingleplayerServer(); - PlayerList playerList = server.getPlayerList(); - MCWiFiPnPUnit.Config cfg = MCWiFiPnPUnit.getConfig(server); + public static void OpenToLan() { + Minecraft client = Minecraft.getInstance(); + IntegratedServer server = client.getSingleplayerServer(); + PlayerList playerList = server.getPlayerList(); + MCWiFiPnPUnit.Config cfg = MCWiFiPnPUnit.getConfig(server); - server.setMotd(cfg.motd); - server.getStatus().setDescription(new TextComponent(cfg.motd)); - TranslatableComponent component = server.publishServer(GameType.byName(cfg.GameMode), cfg.AllowCommands, cfg.port) - ? new TranslatableComponent("commands.publish.started", cfg.port) - : new TranslatableComponent("commands.publish.failed"); - client.gui.getChat().addMessage(component); + server.setMotd(cfg.motd); + server.getStatus().setDescription(new TextComponent(cfg.motd)); + TranslatableComponent component = server.publishServer(GameType.byName(cfg.GameMode), cfg.AllowCommands, cfg.port) + ? new TranslatableComponent("commands.publish.started", cfg.port) + : new TranslatableComponent("commands.publish.failed"); + client.gui.getChat().addMessage(component); - MCWiFiPnP.setMaxPlayers(server, cfg.maxPlayers); - server.setUsesAuthentication(cfg.OnlineMode); - server.setPvpAllowed(cfg.PvP); - server.setEnforceWhitelist(cfg.Whitelist); - playerList.setUsingWhiteList(cfg.Whitelist); - playerList.getOps().add(new ServerOpListEntry(client.player.getGameProfile(), 4, playerList.canBypassPlayerLimit(client.player.getGameProfile()))); - playerList.setAllowCheatsForAllPlayers(cfg.AllPlayersCheats); + ((PlayerListAccessor) playerList).setMaxPlayers(cfg.maxPlayers); + server.setUsesAuthentication(cfg.OnlineMode); + server.setPvpAllowed(cfg.PvP); + server.setEnforceWhitelist(cfg.Whitelist); + playerList.setUsingWhiteList(cfg.Whitelist); + playerList.getOps().add(new ServerOpListEntry(client.player.getGameProfile(), 4, playerList.canBypassPlayerLimit(client.player.getGameProfile()))); + playerList.setAllowCheatsForAllPlayers(cfg.AllPlayersCheats); + UUIDFixer.EnableUUIDFixer = cfg.EnableUUIDFixer; + UUIDFixer.ForceOfflinePlayers = cfg.ForceOfflinePlayers; - new Thread(() -> { - MCWiFiPnPUnit.UseUPnP(cfg, client); - MCWiFiPnPUnit.CopyToClipboard(cfg, client); - }, "MCWiFiPnP").start(); - } + new Thread(() -> { + MCWiFiPnPUnit.UseUPnP(cfg, client); + MCWiFiPnPUnit.CopyToClipboard(cfg, client); + }, "MCWiFiPnP").start(); + } - public static void UseUPnP(Config cfg, Minecraft client) { - if (cfg.UseUPnP) { - if (UPnP.isUPnPAvailable()) { - if (UPnP.isMappedTCP(cfg.port)) { - client.gui.getChat() - .addMessage(new TranslatableComponent("mcwifipnp.upnp.failed.mapped", cfg.port)); - } else if (UPnP.openPortTCP(cfg.port, cfg.motd)) { - client.gui.getChat().addMessage(new TranslatableComponent("mcwifipnp.upnp.success", cfg.port)); - LOGGER.info("Started forwarded port " + cfg.port + "."); - } else { - client.gui.getChat().addMessage(new TranslatableComponent("mcwifipnp.upnp.failed", cfg.port)); - } - } else { - client.gui.getChat().addMessage(new TranslatableComponent("mcwifipnp.upnp.failed.disabled", cfg.port)); - } + public static void UseUPnP(Config cfg, Minecraft client) { + if (cfg.UseUPnP) { + if (UPnP.isUPnPAvailable()) { + if (UPnP.isMappedTCP(cfg.port)) { + client.gui.getChat() + .addMessage(new TranslatableComponent("mcwifipnp.upnp.failed.mapped", cfg.port)); + } else if (UPnP.openPortTCP(cfg.port, cfg.motd)) { + client.gui.getChat().addMessage(new TranslatableComponent("mcwifipnp.upnp.success", cfg.port)); + LOGGER.info("Started forwarded port " + cfg.port + "."); + } else { + client.gui.getChat().addMessage(new TranslatableComponent("mcwifipnp.upnp.failed", cfg.port)); } + } else { + client.gui.getChat().addMessage(new TranslatableComponent("mcwifipnp.upnp.failed.disabled", cfg.port)); + } } + } - public static void CopyToClipboard(Config cfg, Minecraft client) { - if (cfg.CopyToClipboard) { - ArrayList IPComponentList = new ArrayList(); - ArrayList IPList = new ArrayList(); - for (int i = 0; i < IPAddressList().size(); i++) { - Map NewMap = IPAddressList().get(i); - if (NewMap.get("Type") == "IPv4") { - IPComponentList.add(IPComponent( - new TranslatableComponent(NewMap.get("Local")).getString() + " " + NewMap.get("Type"), - NewMap.get("IP") + ":" + cfg.port)); - } else { - IPComponentList.add(IPComponent( - new TranslatableComponent(NewMap.get("Local")).getString() + " " + NewMap.get("Type"), - "[" + NewMap.get("IP") + "]:" + cfg.port)); - } - IPList.add(NewMap.get("IP")); - } - if (!GetGlobalIPv4().isEmpty() && !IPList.contains(GetGlobalIPv4().get("IP"))) { - IPComponentList.add(IPComponent( - new TranslatableComponent(GetGlobalIPv4().get("Local")).getString() + " " - + GetGlobalIPv4().get("Type"), - GetGlobalIPv4().get("IP") + ":" + cfg.port)); - IPList.add(GetGlobalIPv4().get("IP")); - } - if (!GetGlobalIPv6().isEmpty() && !IPList.contains(GetGlobalIPv6().get("IP"))) { - IPComponentList.add(IPComponent( - new TranslatableComponent(GetGlobalIPv6().get("Local")).getString() + " " - + GetGlobalIPv6().get("Type"), - "[" + GetGlobalIPv6().get("IP") + "]:" + cfg.port)); - IPList.add(GetGlobalIPv4().get("IP")); - } - if (cfg.UseUPnP && UPnP.getExternalIP() != null && !IPList.contains(GetGlobalIPv6().get("IP"))) { - IPComponentList.add(IPComponent("UPnP IPv4", UPnP.getExternalIP() + ":" + cfg.port)); - IPList.add(UPnP.getExternalIP()); - } - if (IPList.isEmpty()) { - client.gui.getChat().addMessage(new TranslatableComponent("mcwifipnp.upnp.cantgetip")); - } else { - MutableComponent component = null; - for (int i = 0; i < IPComponentList.size(); i++) { - if (component == null) { - component = IPComponentList.get(i).copy(); - } else { - component.append(IPComponentList.get(i)); - } - } - client.gui.getChat().addMessage( - new TranslatableComponent("mcwifipnp.upnp.clipboard", new Object[] { component })); - } + public static void CopyToClipboard(Config cfg, Minecraft client) { + if (cfg.CopyToClipboard) { + ArrayList IPComponentList = new ArrayList(); + ArrayList IPList = new ArrayList(); + for (int i = 0; i < IPAddressList().size(); i++) { + Map NewMap = IPAddressList().get(i); + if (NewMap.get("Type") == "IPv4") { + IPComponentList.add(IPComponent( + new TranslatableComponent(NewMap.get("Local")).getString() + " " + NewMap.get("Type"), + NewMap.get("IP") + ":" + cfg.port)); + } else { + IPComponentList.add(IPComponent( + new TranslatableComponent(NewMap.get("Local")).getString() + " " + NewMap.get("Type"), + "[" + NewMap.get("IP") + "]:" + cfg.port)); } - } - - public static void ReadingConfig(MinecraftServer server) { - Path location = server.getWorldPath(LevelResource.ROOT).resolve("mcwifipnp.json"); - MCWiFiPnPUnit.Config cfg; - try { - cfg = gson.fromJson(new String(Files.readAllBytes(location),"utf-8"), MCWiFiPnPUnit.Config.class); - cfg.location = location; - } catch (IOException | JsonParseException e) { - try { - Files.deleteIfExists(location); - } catch (IOException ie) { - LOGGER.warn("Unable to read config file!", ie); - } - cfg = new MCWiFiPnPUnit.Config(); - cfg.location = location; - cfg.needsDefaults = true; + IPList.add(NewMap.get("IP")); + } + if (!GetGlobalIPv4().isEmpty() && !IPList.contains(GetGlobalIPv4().get("IP"))) { + IPComponentList.add(IPComponent( + new TranslatableComponent(GetGlobalIPv4().get("Local")).getString() + " " + + GetGlobalIPv4().get("Type"), + GetGlobalIPv4().get("IP") + ":" + cfg.port)); + IPList.add(GetGlobalIPv4().get("IP")); + } + if (!GetGlobalIPv6().isEmpty() && !IPList.contains(GetGlobalIPv6().get("IP"))) { + IPComponentList.add(IPComponent( + new TranslatableComponent(GetGlobalIPv6().get("Local")).getString() + " " + + GetGlobalIPv6().get("Type"), + "[" + GetGlobalIPv6().get("IP") + "]:" + cfg.port)); + IPList.add(GetGlobalIPv4().get("IP")); + } + if (cfg.UseUPnP && UPnP.getExternalIP() != null && !IPList.contains(GetGlobalIPv6().get("IP"))) { + IPComponentList.add(IPComponent("UPnP IPv4", UPnP.getExternalIP() + ":" + cfg.port)); + IPList.add(UPnP.getExternalIP()); + } + if (IPList.isEmpty()) { + client.gui.getChat().addMessage(new TranslatableComponent("mcwifipnp.upnp.cantgetip")); + } else { + MutableComponent component = null; + for (int i = 0; i < IPComponentList.size(); i++) { + if (component == null) { + component = IPComponentList.get(i).copy(); + } else { + component.append(IPComponentList.get(i)); + } } - configMap.put(server, cfg); + client.gui.getChat().addMessage( + new TranslatableComponent("mcwifipnp.upnp.clipboard", new Object[] { component })); + } } + } - public static void CloseUPnPPort(MinecraftServer server) { - MCWiFiPnPUnit.Config cfg = configMap.get(server); - if (server.isPublished() && cfg.UseUPnP) { - UPnP.closePortTCP(cfg.port); - LOGGER.info("Stopped forwarded port " + cfg.port + "."); - } + public static void ReadingConfig(MinecraftServer server) { + Path location = server.getWorldPath(LevelResource.ROOT).resolve("mcwifipnp.json"); + MCWiFiPnPUnit.Config cfg; + try { + cfg = gson.fromJson(new String(Files.readAllBytes(location),"utf-8"), MCWiFiPnPUnit.Config.class); + cfg.location = location; + } catch (IOException | JsonParseException e) { + try { + Files.deleteIfExists(location); + } catch (IOException ie) { + LOGGER.warn("Unable to read config file!", ie); + } + cfg = new MCWiFiPnPUnit.Config(); + cfg.location = location; + cfg.needsDefaults = true; } + configMap.put(server, cfg); + } - static void saveConfig(Config cfg) { - if (!cfg.needsDefaults) { - try { - Files.write(cfg.location, toPrettyFormat(cfg).getBytes("utf-8"), StandardOpenOption.TRUNCATE_EXISTING, - StandardOpenOption.CREATE); - } catch (IOException e) { - LOGGER.warn("Unable to write config file!", e); - } - } + public static void CloseUPnPPort(MinecraftServer server) { + MCWiFiPnPUnit.Config cfg = configMap.get(server); + if (server.isPublished() && cfg.UseUPnP) { + UPnP.closePortTCP(cfg.port); + LOGGER.info("Stopped forwarded port " + cfg.port + "."); } + } - public static class Config { - public int port = 25565; - public int maxPlayers = 8; - public String GameMode = "survival"; - public String motd = new TranslatableComponent("lanServer.title").getString(); - public boolean AllPlayersCheats = false; - public boolean Whitelist = false; - public boolean UseUPnP = true; - public boolean AllowCommands = false; - public boolean OnlineMode = true; - public boolean PvP = true; - public boolean CopyToClipboard = true; - public transient Path location; - public transient boolean needsDefaults = false; + static void saveConfig(Config cfg) { + if (!cfg.needsDefaults) { + try { + Files.write(cfg.location, toPrettyFormat(cfg).getBytes("utf-8"), StandardOpenOption.TRUNCATE_EXISTING, + StandardOpenOption.CREATE); + } catch (IOException e) { + LOGGER.warn("Unable to write config file!", e); + } } + } - private static String toPrettyFormat(Object src) { - String json = gson.toJson(src); - JsonParser jsonParser = new JsonParser(); - JsonObject jsonObject = jsonParser.parse(json).getAsJsonObject(); - Gson gson = new GsonBuilder().setPrettyPrinting().create(); - return gson.toJson(jsonObject); - } + public static class Config { + public int port = 25565; + public int maxPlayers = 8; + public String GameMode = "survival"; + public String motd = new TranslatableComponent("lanServer.title").getString(); + public boolean AllPlayersCheats = false; + public boolean Whitelist = false; + public boolean UseUPnP = true; + public boolean AllowCommands = false; + public boolean OnlineMode = true; + public boolean EnableUUIDFixer = false; + public List ForceOfflinePlayers = Collections.emptyList(); + public boolean PvP = true; + public boolean CopyToClipboard = true; + public transient Path location; + public transient boolean needsDefaults = false; + } - private static Component IPComponent(String Type, String IP) { - return ComponentUtils.wrapInSquareBrackets((new TextComponent(Type)).withStyle((style) -> { - return style.withColor(ChatFormatting.GREEN) - .withClickEvent(new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, IP)) - .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, - new TranslatableComponent("chat.copy.click").append("\n").append(IP))) - .withInsertion(IP); - })); - } + private static String toPrettyFormat(Object src) { + String json = gson.toJson(src); + JsonParser jsonParser = new JsonParser(); + JsonObject jsonObject = jsonParser.parse(json).getAsJsonObject(); + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + return gson.toJson(jsonObject); + } - public static Map GetGlobalIPv4() { - String ipv4 = null; - try { - URL url = new URL("https://api-ipv4.ip.sb/ip"); - URLConnection URLconnection = url.openConnection(); - InputStreamReader isr = new InputStreamReader(URLconnection.getInputStream()); - BufferedReader bufr = new BufferedReader(isr); - String str; - while ((str = bufr.readLine()) != null) { - ipv4 = str; - } - bufr.close(); - } catch (Exception e) { - } - Map Gl4Map = new HashMap(); - if (ipv4 != null) { - // Gl4Map.put("Iface", "Global IPv4"); - Gl4Map.put("Type", "IPv4"); - Gl4Map.put("Local", "mcwifipnp.gui.Global"); - Gl4Map.put("IP", ipv4); - } - return Gl4Map; + private static Component IPComponent(String Type, String IP) { + return ComponentUtils.wrapInSquareBrackets((new TextComponent(Type)).withStyle((style) -> { + return style.withColor(ChatFormatting.GREEN) + .withClickEvent(new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, IP)) + .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, + new TranslatableComponent("chat.copy.click").append("\n").append(IP))) + .withInsertion(IP); + })); + } + + public static Map GetGlobalIPv4() { + String ipv4 = null; + try { + URL url = new URL("https://api-ipv4.ip.sb/ip"); + URLConnection URLconnection = url.openConnection(); + InputStreamReader isr = new InputStreamReader(URLconnection.getInputStream()); + BufferedReader bufr = new BufferedReader(isr); + String str; + while ((str = bufr.readLine()) != null) { + ipv4 = str; + } + bufr.close(); + } catch (Exception e) { } + Map Gl4Map = new HashMap(); + if (ipv4 != null) { + // Gl4Map.put("Iface", "Global IPv4"); + Gl4Map.put("Type", "IPv4"); + Gl4Map.put("Local", "mcwifipnp.gui.Global"); + Gl4Map.put("IP", ipv4); + } + return Gl4Map; + } - public static Map GetGlobalIPv6() { - String ipv6 = null; - try { - URL url = new URL("https://api-ipv6.ip.sb/ip"); - URLConnection URLconnection = url.openConnection(); - InputStreamReader isr = new InputStreamReader(URLconnection.getInputStream()); - BufferedReader bufr = new BufferedReader(isr); - String str; - while ((str = bufr.readLine()) != null) { - ipv6 = str; - } - bufr.close(); - } catch (Exception e) { - } - Map Gl6Map = new HashMap(); - if (ipv6 != null) { - // Gl6Map.put("Iface", "Global IPv6"); - Gl6Map.put("Type", "IPv6"); - Gl6Map.put("Local", "mcwifipnp.gui.Global"); - Gl6Map.put("IP", ipv6); - } - return Gl6Map; + public static Map GetGlobalIPv6() { + String ipv6 = null; + try { + URL url = new URL("https://api-ipv6.ip.sb/ip"); + URLConnection URLconnection = url.openConnection(); + InputStreamReader isr = new InputStreamReader(URLconnection.getInputStream()); + BufferedReader bufr = new BufferedReader(isr); + String str; + while ((str = bufr.readLine()) != null) { + ipv6 = str; + } + bufr.close(); + } catch (Exception e) { + } + Map Gl6Map = new HashMap(); + if (ipv6 != null) { + // Gl6Map.put("Iface", "Global IPv6"); + Gl6Map.put("Type", "IPv6"); + Gl6Map.put("Local", "mcwifipnp.gui.Global"); + Gl6Map.put("IP", ipv6); } + return Gl6Map; + } - public static ArrayList> IPAddressList() { - ArrayList> out = new ArrayList>(); + public static ArrayList> IPAddressList() { + ArrayList> out = new ArrayList>(); + try { + Enumeration ifaces = NetworkInterface.getNetworkInterfaces(); + while (ifaces.hasMoreElements()) { try { - Enumeration ifaces = NetworkInterface.getNetworkInterfaces(); - while (ifaces.hasMoreElements()) { - try { - NetworkInterface iface = ifaces.nextElement(); - if (!iface.isUp() || iface.isLoopback() || iface.isVirtual() || iface.isPointToPoint()) { - continue; - } - if (iface.getDisplayName().contains("Virtual") - || iface.getDisplayName().contains("VMware") - || iface.getDisplayName().contains("VirtualBox") - || iface.getDisplayName().contains("Bluetooth") - || iface.getDisplayName().contains("Hyper-V")) { - continue; - } - Enumeration addrs = iface.getInetAddresses(); - if (addrs == null) { - continue; - } - while (addrs.hasMoreElements()) { - Map NetMap = new HashMap(); - // NetMap.put("Iface", iface.getDisplayName()); - InetAddress addr = addrs.nextElement(); - if (addr instanceof Inet4Address) { - NetMap.put("Type", "IPv4"); - } - if (addr instanceof Inet6Address) { - NetMap.put("Type", "IPv6"); - } - if (addr.isLinkLocalAddress()) { - continue; - } - if (addr.isSiteLocalAddress()) { - NetMap.put("Local", "mcwifipnp.gui.Local"); - } else { - NetMap.put("Local", "mcwifipnp.gui.Global"); - } - NetMap.put("IP", addr.getHostAddress()); - out.add(NetMap); - } - } catch (Throwable t) { - } + NetworkInterface iface = ifaces.nextElement(); + if (!iface.isUp() || iface.isLoopback() || iface.isVirtual() || iface.isPointToPoint()) { + continue; + } + if (iface.getDisplayName().contains("Virtual") + || iface.getDisplayName().contains("VMware") + || iface.getDisplayName().contains("VirtualBox") + || iface.getDisplayName().contains("Bluetooth") + || iface.getDisplayName().contains("Hyper-V")) { + continue; + } + Enumeration addrs = iface.getInetAddresses(); + if (addrs == null) { + continue; + } + while (addrs.hasMoreElements()) { + Map NetMap = new HashMap(); + // NetMap.put("Iface", iface.getDisplayName()); + InetAddress addr = addrs.nextElement(); + if (addr instanceof Inet4Address) { + NetMap.put("Type", "IPv4"); + } + if (addr instanceof Inet6Address) { + NetMap.put("Type", "IPv6"); + } + if (addr.isLinkLocalAddress()) { + continue; + } + if (addr.isSiteLocalAddress()) { + NetMap.put("Local", "mcwifipnp.gui.Local"); + } else { + NetMap.put("Local", "mcwifipnp.gui.Global"); } + NetMap.put("IP", addr.getHostAddress()); + out.add(NetMap); + } } catch (Throwable t) { } - return out; + } + } catch (Throwable t) { } + return out; + } } \ No newline at end of file diff --git a/src/main/java/io/github/satxm/mcwifipnp/OnlineMode.java b/src/main/java/io/github/satxm/mcwifipnp/OnlineMode.java new file mode 100644 index 00000000..a12c4b7e --- /dev/null +++ b/src/main/java/io/github/satxm/mcwifipnp/OnlineMode.java @@ -0,0 +1,45 @@ +package io.github.satxm.mcwifipnp; + +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TranslatableComponent; + +public enum OnlineMode { + ONLINE(true, false,"online"), + OFFLINE(false, false,"offline"), + FIXUUID(false, true,"fixuuid"); + + private final boolean onlinemode, fixuuid; + private final Component displayName, toolTip; + + OnlineMode(boolean onlinemode, boolean fixuuid, final String string) { + this.onlinemode = onlinemode; + this.fixuuid = fixuuid; + this.displayName = new TranslatableComponent("mcwifipnp.gui.OnlineMode." + string); + this.toolTip = new TranslatableComponent("mcwifipnp.gui.OnlineMode." + string +".info"); + } + + public Component getDisplayName() { + return this.displayName; + } + + public Component gettoolTip() { + return this.toolTip; + } + + public static OnlineMode of(boolean onlinemode, boolean fixuuid) { + if (onlinemode) { + return ONLINE; + } else { + return fixuuid ? FIXUUID : OFFLINE; + } + } + + public boolean getOnlieMode() { + return this.onlinemode; + } + + public boolean getFixUUID() { + return this.fixuuid; + } + +} diff --git a/src/main/java/io/github/satxm/mcwifipnp/ShareToLanScreenNew.java b/src/main/java/io/github/satxm/mcwifipnp/ShareToLanScreenNew.java index 38a55abc..79a0d47e 100644 --- a/src/main/java/io/github/satxm/mcwifipnp/ShareToLanScreenNew.java +++ b/src/main/java/io/github/satxm/mcwifipnp/ShareToLanScreenNew.java @@ -14,153 +14,159 @@ import net.minecraft.util.HttpUtil; import net.minecraft.world.level.GameType; -public class ShareToLanScreenNew extends Screen { - private final MCWiFiPnPUnit.Config cfg; - private EditBox EditPort; - private EditBox EditMotd; - private EditBox EditPlayers; - private Button StartLanServer; - private Screen lastScreen; - - public ShareToLanScreenNew(Screen screen) { - super(new TranslatableComponent("lanServer.title")); - this.lastScreen = screen; - - Minecraft client = Minecraft.getInstance(); - MinecraftServer server = Minecraft.getInstance().getSingleplayerServer(); - MCWiFiPnPUnit.ReadingConfig(server); - this.cfg = MCWiFiPnPUnit.getConfig(server); - - if (cfg.needsDefaults) { - cfg.port = HttpUtil.getAvailablePort(); - cfg.AllowCommands = client.getSingleplayerServer().getWorldData().getAllowCommands(); - cfg.GameMode = client.getSingleplayerServer().getWorldData().getGameType().getName(); - cfg.OnlineMode = client.getSingleplayerServer().usesAuthentication(); - cfg.needsDefaults = false; - } - } - - protected void init() { - this.StartLanServer = this.addRenderableWidget(new Button(this.width / 2 - 155, this.height - 32, 150, 20, - new TranslatableComponent("lanServer.start"), (button) -> { - cfg.port = Integer.parseInt(EditPort.getValue()); - cfg.motd = EditMotd.getValue(); - cfg.maxPlayers = Integer.parseInt(EditPlayers.getValue()); - MCWiFiPnPUnit.saveConfig(cfg); - MCWiFiPnPUnit.OpenToLan(); - this.minecraft.updateTitle(); - this.minecraft.setScreen((Screen) null); - })); - - this.addRenderableWidget( - new Button(this.width / 2 + 5, this.height - 32, 150, 20, CommonComponents.GUI_CANCEL, (button) -> { - this.minecraft.setScreen(this.lastScreen); - })); - - this.addRenderableWidget(CycleButton.builder(GameType::getShortDisplayName) - .withValues(GameType.SURVIVAL, GameType.SPECTATOR, GameType.CREATIVE, GameType.ADVENTURE) - .withInitialValue(GameType.byName(cfg.GameMode)).create(this.width / 2 - 155, 36, 150, 20, - new TranslatableComponent("selectWorld.gameMode"), (button, gameMode) -> { - cfg.GameMode = gameMode.getName(); - })); - - this.addRenderableWidget(CycleButton.onOffBuilder(cfg.AllowCommands).create(this.width / 2 + 5, 36, 150, 20, - new TranslatableComponent("selectWorld.allowCommands"), (button, AllowCommands) -> { - cfg.AllowCommands = AllowCommands; - })); - - this.EditPort = new EditBox(this.font, this.width / 2 - 154, 70, 96, 20, - new TextComponent(Integer.toString(cfg.port))); - this.EditPort.setValue(Integer.toString(cfg.port)); - this.EditPort.setMaxLength(5); - this.addRenderableWidget(EditPort); - - this.EditPort.setResponder((sPort) -> { - this.StartLanServer.active = !this.EditPort.getValue().isEmpty(); - try { - int port = Integer.parseInt(EditPort.getValue()); - if (port < 1024) { - this.StartLanServer.active = false; - } else if (port > 65535) { - this.StartLanServer.active = false; - } else { - } - } catch (NumberFormatException ex) { - this.StartLanServer.active = false; - } - }); - - this.EditPlayers = new EditBox(this.font, this.width / 2 - 48, 70, 96, 20, - new TextComponent(Integer.toString(cfg.maxPlayers))); - this.EditPlayers.setValue(Integer.toString(cfg.maxPlayers)); - this.addRenderableWidget(EditPlayers); - - this.EditPlayers.setResponder((sPlayers) -> { - this.StartLanServer.active = !this.EditPlayers.getValue().isEmpty(); - try { - int players = Integer.parseInt(EditPlayers.getValue()); - if (players <= 0) { - this.StartLanServer.active = false; - } - } catch (NumberFormatException ex) { - this.StartLanServer.active = false; - } - }); - - this.EditMotd = new EditBox(this.font, this.width / 2 + 58, 70, 96, 20, new TextComponent(cfg.motd)); - this.EditMotd.setValue(cfg.motd); - this.EditMotd.setMaxLength(32); - this.addRenderableWidget(EditMotd); - - this.EditMotd.setResponder((sMotd) -> { - this.StartLanServer.active = !this.EditMotd.getValue().isEmpty(); - }); - - this.addRenderableWidget(CycleButton.onOffBuilder(cfg.AllPlayersCheats).create(this.width / 2 - 155, 124, 150, 20, - new TranslatableComponent("mcwifipnp.gui.AllPlayersCheats"), (button, AllPlayersCheats) -> { - cfg.AllPlayersCheats = AllPlayersCheats; - })); - - this.addRenderableWidget(CycleButton.onOffBuilder(cfg.Whitelist).create(this.width / 2 + 5, 124, 150, 20, - new TranslatableComponent("mcwifipnp.gui.Whitelist"), (button, Whitelist) -> { - cfg.Whitelist = Whitelist; - })); - - this.addRenderableWidget(CycleButton.onOffBuilder(cfg.OnlineMode).create(this.width / 2 - 155, 148, 150, 20, - new TranslatableComponent("mcwifipnp.gui.OnlineMode"), (button, OnlineMode) -> { - cfg.OnlineMode = OnlineMode; - })); - - this.addRenderableWidget(CycleButton.onOffBuilder(cfg.PvP).create(this.width / 2 + 5, 148, 150, 20, - new TranslatableComponent("mcwifipnp.gui.PvP"), (button, PvP) -> { - cfg.PvP = PvP; - })); - - this.addRenderableWidget(CycleButton.onOffBuilder(cfg.UseUPnP).create(this.width / 2 - 155, 172, 150, 20, - new TranslatableComponent("mcwifipnp.gui.UseUPnP"), (button, UseUPnP) -> { - cfg.UseUPnP = UseUPnP; - })); - - this.addRenderableWidget(CycleButton.onOffBuilder(cfg.CopyToClipboard).create(this.width / 2 + 5, 172, 150, 20, - new TranslatableComponent("mcwifipnp.gui.CopyIP"), (button, CopyToClipboard) -> { - cfg.CopyToClipboard = CopyToClipboard; - })); - } +import java.util.Collections; - public void render(PoseStack poseStack, int i, int j, float f) { - this.renderBackground(poseStack); - drawCenteredString(poseStack, this.font, this.title, this.width / 2, 16, 16777215); - drawString(poseStack, this.font, new TranslatableComponent("mcwifipnp.gui.port"), this.width / 2 - 149, 58, - 16777215); - drawString(poseStack, this.font, new TranslatableComponent("mcwifipnp.gui.players"), this.width / 2 - 43, 58, - 16777215); - drawString(poseStack, this.font, new TranslatableComponent("mcwifipnp.gui.motd"), this.width / 2 + 63, 58, - 16777215); - drawCenteredString(poseStack, this.font, new TranslatableComponent("lanServer.otherPlayers"), this.width / 2, - 104, 16777215); - EditPort.render(poseStack, i, j, f); - EditPlayers.render(poseStack, i, j, f); - EditMotd.render(poseStack, i, j, f); - super.render(poseStack, i, j, f); +public class ShareToLanScreenNew extends Screen { + private final MCWiFiPnPUnit.Config cfg; + private EditBox EditPort; + private EditBox EditMotd; + private EditBox EditPlayers; + private Button StartLanServer; + private Screen lastScreen; + + public ShareToLanScreenNew(Screen screen) { + super(new TranslatableComponent("lanServer.title")); + this.lastScreen = screen; + + Minecraft client = Minecraft.getInstance(); + MinecraftServer server = Minecraft.getInstance().getSingleplayerServer(); + MCWiFiPnPUnit.ReadingConfig(server); + this.cfg = MCWiFiPnPUnit.getConfig(server); + + if (cfg.needsDefaults) { + cfg.port = HttpUtil.getAvailablePort(); + cfg.AllowCommands = client.getSingleplayerServer().getWorldData().getAllowCommands(); + cfg.GameMode = client.getSingleplayerServer().getWorldData().getGameType().getName(); + cfg.OnlineMode = client.getSingleplayerServer().usesAuthentication(); + cfg.ForceOfflinePlayers = Collections.emptyList(); + cfg.needsDefaults = false; } + } + + protected void init() { + this.StartLanServer = this.addRenderableWidget(new Button(this.width / 2 - 155, this.height - 32, 150, 20, + new TranslatableComponent("lanServer.start"), (button) -> { + cfg.port = Integer.parseInt(EditPort.getValue()); + cfg.motd = EditMotd.getValue(); + cfg.maxPlayers = Integer.parseInt(EditPlayers.getValue()); + MCWiFiPnPUnit.saveConfig(cfg); + MCWiFiPnPUnit.OpenToLan(); + this.minecraft.updateTitle(); + this.minecraft.setScreen((Screen) null); + })); + + this.addRenderableWidget( + new Button(this.width / 2 + 5, this.height - 32, 150, 20, CommonComponents.GUI_CANCEL, (button) -> { + this.minecraft.setScreen(this.lastScreen); + })); + + this.addRenderableWidget(CycleButton.builder(GameType::getShortDisplayName) + .withValues(GameType.SURVIVAL, GameType.SPECTATOR, GameType.CREATIVE, GameType.ADVENTURE) + .withInitialValue(GameType.byName(cfg.GameMode)).create(this.width / 2 - 155, 36, 150, 20, + new TranslatableComponent("selectWorld.gameMode"), (button, gameMode) -> { + cfg.GameMode = gameMode.getName(); + })); + + this.addRenderableWidget(CycleButton.onOffBuilder(cfg.AllowCommands).create(this.width / 2 + 5, 36, 150, 20, + new TranslatableComponent("selectWorld.allowCommands"), (button, AllowCommands) -> { + cfg.AllowCommands = AllowCommands; + })); + + this.EditPort = new EditBox(this.font, this.width / 2 - 154, 70, 96, 20, + new TextComponent(Integer.toString(cfg.port))); + this.EditPort.setValue(Integer.toString(cfg.port)); + this.EditPort.setMaxLength(5); + this.addRenderableWidget(EditPort); + + this.EditPort.setResponder((sPort) -> { + this.StartLanServer.active = !this.EditPort.getValue().isEmpty(); + try { + int port = Integer.parseInt(EditPort.getValue()); + if (port < 1024) { + this.StartLanServer.active = false; + } else if (port > 65535) { + this.StartLanServer.active = false; + } else { + } + } catch (NumberFormatException ex) { + this.StartLanServer.active = false; + } + }); + + this.EditPlayers = new EditBox(this.font, this.width / 2 - 48, 70, 96, 20, + new TextComponent(Integer.toString(cfg.maxPlayers))); + this.EditPlayers.setValue(Integer.toString(cfg.maxPlayers)); + this.addRenderableWidget(EditPlayers); + + this.EditPlayers.setResponder((sPlayers) -> { + this.StartLanServer.active = !this.EditPlayers.getValue().isEmpty(); + try { + int players = Integer.parseInt(EditPlayers.getValue()); + if (players <= 0) { + this.StartLanServer.active = false; + } + } catch (NumberFormatException ex) { + this.StartLanServer.active = false; + } + }); + + this.EditMotd = new EditBox(this.font, this.width / 2 + 58, 70, 96, 20, new TextComponent(cfg.motd)); + this.EditMotd.setValue(cfg.motd); + this.EditMotd.setMaxLength(32); + this.addRenderableWidget(EditMotd); + + this.EditMotd.setResponder((sMotd) -> { + this.StartLanServer.active = !this.EditMotd.getValue().isEmpty(); + }); + + this.addRenderableWidget(CycleButton.onOffBuilder(cfg.AllPlayersCheats).create(this.width / 2 - 155, 124, 150, 20, + new TranslatableComponent("mcwifipnp.gui.AllPlayersCheats"), (button, AllPlayersCheats) -> { + cfg.AllPlayersCheats = AllPlayersCheats; + })); + + this.addRenderableWidget(CycleButton.onOffBuilder(cfg.Whitelist).create(this.width / 2 + 5, 124, 150, 20, + new TranslatableComponent("mcwifipnp.gui.Whitelist"), (button, Whitelist) -> { + cfg.Whitelist = Whitelist; + })); + + this.addRenderableWidget(CycleButton.builder(OnlineMode::getDisplayName) + .withValues(OnlineMode.values()) + .withInitialValue(OnlineMode.of(cfg.OnlineMode, cfg.EnableUUIDFixer)).create(this.width / 2 - 155, 148, 150, 20, + new TranslatableComponent("mcwifipnp.gui.OnlineMode"), (button, OnlineMode) -> { + cfg.OnlineMode = OnlineMode.getOnlieMode(); + cfg.EnableUUIDFixer = OnlineMode.getFixUUID(); + })); + + this.addRenderableWidget(CycleButton.onOffBuilder(cfg.PvP).create(this.width / 2 + 5, 148, 150, 20, + new TranslatableComponent("mcwifipnp.gui.PvP"), (button, PvP) -> { + cfg.PvP = PvP; + })); + + this.addRenderableWidget(CycleButton.onOffBuilder(cfg.UseUPnP).create(this.width / 2 - 155, 172, 150, 20, + new TranslatableComponent("mcwifipnp.gui.UseUPnP"), (button, UseUPnP) -> { + cfg.UseUPnP = UseUPnP; + })); + + this.addRenderableWidget(CycleButton.onOffBuilder(cfg.CopyToClipboard).create(this.width / 2 + 5, 172, 150, 20, + new TranslatableComponent("mcwifipnp.gui.CopyIP"), (button, CopyToClipboard) -> { + cfg.CopyToClipboard = CopyToClipboard; + })); + } + + public void render(PoseStack poseStack, int i, int j, float f) { + this.renderBackground(poseStack); + drawCenteredString(poseStack, this.font, this.title, this.width / 2, 16, 16777215); + drawString(poseStack, this.font, new TranslatableComponent("mcwifipnp.gui.port"), this.width / 2 - 149, 58, + 16777215); + drawString(poseStack, this.font, new TranslatableComponent("mcwifipnp.gui.players"), this.width / 2 - 43, 58, + 16777215); + drawString(poseStack, this.font, new TranslatableComponent("mcwifipnp.gui.motd"), this.width / 2 + 63, 58, + 16777215); + drawCenteredString(poseStack, this.font, new TranslatableComponent("lanServer.otherPlayers"), this.width / 2, + 104, 16777215); + EditPort.render(poseStack, i, j, f); + EditPlayers.render(poseStack, i, j, f); + EditMotd.render(poseStack, i, j, f); + super.render(poseStack, i, j, f); + } } diff --git a/src/main/java/io/github/satxm/mcwifipnp/UUIDFixer.java b/src/main/java/io/github/satxm/mcwifipnp/UUIDFixer.java new file mode 100644 index 00000000..2432ef28 --- /dev/null +++ b/src/main/java/io/github/satxm/mcwifipnp/UUIDFixer.java @@ -0,0 +1,63 @@ +package io.github.satxm.mcwifipnp; + +import java.io.IOException; +import java.net.URL; +import java.nio.charset.Charset; +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +import javax.annotation.Nullable; + +import org.apache.commons.io.IOUtils; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.JsonSyntaxException; + +public class UUIDFixer { + public static boolean EnableUUIDFixer = false; + public static List ForceOfflinePlayers = Collections.emptyList(); + + /** + * Mixin/ Coremod callback + */ + public static UUID hookEntry(String playerName) { + + if (ForceOfflinePlayers.contains(playerName)) + return null; + if (EnableUUIDFixer) + return getOfficialUUID(playerName); + + return null; + } + + @Nullable + public static UUID getOfficialUUID(String playerName) { + String url = "https://api.mojang.com/users/profiles/minecraft/" + playerName; + try { + String UUIDJson = IOUtils.toString(new URL(url), Charset.defaultCharset()); + if (!UUIDJson.isEmpty()) { + JsonParser jsonParser = new JsonParser(); + JsonObject root = jsonParser.parse(UUIDJson).getAsJsonObject(); + String playerName2 = root.getAsJsonPrimitive("name").getAsString(); + String uuidString = root.getAsJsonPrimitive("id").getAsString(); + // com.mojang.util.UUIDTypeAdapter.fromString(String) + long uuidMSB = Long.parseLong(uuidString.substring(0, 8), 16); + uuidMSB <<= 32; + uuidMSB |= Long.parseLong(uuidString.substring(8, 16), 16); + long uuidLSB = Long.parseLong(uuidString.substring(16, 24), 16); + uuidLSB <<= 32; + uuidLSB |= Long.parseLong(uuidString.substring(24, 32), 16); + UUID uuid = new UUID(uuidMSB, uuidLSB); + + if (playerName2.equalsIgnoreCase(playerName)) + return uuid; + } + } catch (IOException | JsonSyntaxException e) { + e.printStackTrace(); + } + + return null; + } +} \ No newline at end of file diff --git a/src/main/java/io/github/satxm/mcwifipnp/mixin/MixinPlayer.java b/src/main/java/io/github/satxm/mcwifipnp/mixin/MixinPlayer.java new file mode 100644 index 00000000..60334ef3 --- /dev/null +++ b/src/main/java/io/github/satxm/mcwifipnp/mixin/MixinPlayer.java @@ -0,0 +1,23 @@ +package io.github.satxm.mcwifipnp.mixin; + +import java.util.UUID; + +import com.mojang.authlib.GameProfile; +import io.github.satxm.mcwifipnp.UUIDFixer; +import net.minecraft.world.entity.player.Player; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(Player.class) +public abstract class MixinPlayer { + @Inject(method = "createPlayerUUID(Lcom/mojang/authlib/GameProfile;)Ljava/util/UUID;", at = @At("HEAD"), cancellable = true) + private static void detour_createOfflinePlayerUUID(GameProfile gameProfile, CallbackInfoReturnable ci) { + UUID uuid = UUIDFixer.hookEntry(gameProfile.getName()); + if (uuid != null) { + ci.setReturnValue(uuid); + ci.cancel(); + } + } +} \ No newline at end of file diff --git a/fabric/src/main/java/io/github/satxm/mcwifipnp/mixin/PlayerListAccessor.java b/src/main/java/io/github/satxm/mcwifipnp/mixin/PlayerListAccessor.java similarity index 79% rename from fabric/src/main/java/io/github/satxm/mcwifipnp/mixin/PlayerListAccessor.java rename to src/main/java/io/github/satxm/mcwifipnp/mixin/PlayerListAccessor.java index ac6bd420..cb0bbe13 100644 --- a/fabric/src/main/java/io/github/satxm/mcwifipnp/mixin/PlayerListAccessor.java +++ b/src/main/java/io/github/satxm/mcwifipnp/mixin/PlayerListAccessor.java @@ -8,7 +8,7 @@ @Mixin(PlayerList.class) public interface PlayerListAccessor { - @Accessor - @Mutable - public void setMaxPlayers(int maxPlayers); + @Accessor + @Mutable + public void setMaxPlayers(int maxPlayers); } \ No newline at end of file diff --git a/src/main/resources/assets/mcwifipnp/lang/en_us.json b/src/main/resources/assets/mcwifipnp/lang/en_us.json index 9c1b3345..90d915a7 100644 --- a/src/main/resources/assets/mcwifipnp/lang/en_us.json +++ b/src/main/resources/assets/mcwifipnp/lang/en_us.json @@ -1,31 +1,43 @@ { - "mcwifipnp.gui.port":"Port Number", - "mcwifipnp.gui.port.info":"Port number for LAN World.\nLeave the edit box empty or enter a different number between 1024 and 65535.", - "mcwifipnp.gui.port.invalid": "Not a valid port.\nLeave the edit box empty or enter a number between 1024 and 65535.", - "mcwifipnp.gui.port.unavailable": "Port not available.\nLeave the edit box empty or enter a different number between 1024 and 65535.", - "mcwifipnp.gui.players":"Max Players", - "mcwifipnp.gui.players.info":"The maximum number of players that are able to join the server.", - "mcwifipnp.gui.motd":"The MOTD", - "mcwifipnp.gui.motd.info":"The server information displayed below the name in the multiplayer server list.", - "mcwifipnp.gui.AllPlayersCheats":"Other Players Cheats", - "mcwifipnp.gui.AllPlayersCheats.info":"Enable to automatically make other players operators when they join the server. You also can use /op to make someone an operator.", - "mcwifipnp.gui.Whitelist":"Whitelist", - "mcwifipnp.gui.Whitelist.info":"Enforce whitelist. When enabled, only whitelisted players can connect to the server. Use /whitelist to add players to the list.", - "mcwifipnp.gui.OnlineMode": "Online Mode", - "mcwifipnp.gui.OnlineMode.info": "Connects to the Minecraft account database to verify logins. Disable to allow offline accounts to join.", - "mcwifipnp.gui.PvP":"PvP", - "mcwifipnp.gui.PvP.info":"Toggles PvP. Disabling PvP will also prevent you from taking damage from your own projectiles.", - "mcwifipnp.gui.UseUPnP": "Forward Port", - "mcwifipnp.gui.UseUPnP.info": "Whether to use the UPnP function to map the LAN game port number.", - "mcwifipnp.gui.Local": "Local", - "mcwifipnp.gui.Global": "Global", - "mcwifipnp.gui.CopyIP": "Get IP", - "mcwifipnp.gui.CopyIP.info": "Get IP to copying to clipboard", - "mcwifipnp.upnp.success": "Successfully forwarded port %s", - "mcwifipnp.upnp.clipboard": "Successfully got %s, Due to factors such as NAT, these IPs may still not be able to connect directly.", - "mcwifipnp.upnp.cantgetip": "Couldn't get public IP! Please check your network settings. Your IPv4 may contain multiple NATs or you do not have IPv6.", - "mcwifipnp.upnp.failed.mapped": "Unable to forward port %s: Port was already mapped by another UPnP service, Please change the port number.", - "mcwifipnp.upnp.failed.disabled": "Unable to forward port %s: UPnP is not enabled on your router, You may need to use port mapping software.", - "mcwifipnp.upnp.failed.unknownerror": "Unable to forward port %s: Unknown error while adding port mapping, Please use a port mapping software.", - "mcwifipnp.upnp.failed": "Unable to forward port %s!" + "mcwifipnp.gui.port":"Port Number", + "mcwifipnp.gui.port.info":"Port number for LAN World.\nLeave the edit box empty or enter a different number between 1024 and 65535.", + "mcwifipnp.gui.port.invalid": "Not a valid port.\nLeave the edit box empty or enter a number between 1024 and 65535.", + "mcwifipnp.gui.port.unavailable": "Port not available.\nLeave the edit box empty or enter a different number between 1024 and 65535.", + "mcwifipnp.gui.players":"Max Players", + "mcwifipnp.gui.players.info":"The maximum number of players that are able to join the server.", + "mcwifipnp.gui.motd":"The MOTD", + "mcwifipnp.gui.motd.info":"The server information displayed below the name in the multiplayer server list.", + "mcwifipnp.gui.AllPlayersCheats":"Other Players Cheats", + "mcwifipnp.gui.AllPlayersCheats.info":"Enable to automatically make other players operators when they join the server. You also can use /op to make someone an operator.", + "mcwifipnp.gui.Whitelist":"Whitelist", + "mcwifipnp.gui.Whitelist.info":"Enforce whitelist. When enabled, only whitelisted players can connect to the server. Use /whitelist to add players to the list.", + "mcwifipnp.gui.OnlineMode": "Online Mode", + "mcwifipnp.gui.OnlineMode.info": "Whether to let the server compare and verify the login information against the Mojang server database.", + "mcwifipnp.gui.OnlineMode.online": "Enable", + "mcwifipnp.gui.OnlineMode.online.info": "Enabe Online Mode will only allow players who login with a Microsoft account to join this server.", + "mcwifipnp.gui.OnlineMode.offline": "Disable", + "mcwifipnp.gui.OnlineMode.offline.info": "Disabe Online Mode will allow players who login in offline mode to join this server.", + "mcwifipnp.gui.OnlineMode.fixuuid": "Disable + UUID Fixer", + "mcwifipnp.gui.OnlineMode.fixuuid.info": "Attempt to match the Mojang server user name with the player name for offline mode players to obtain a unique UUID. \nMeanwhile, UUIDs are retained for users logging in with Microsoft accounts.\nIt can also prevent the loss of backpack and inventory items.", + "mcwifipnp.gui.PvP": "PvP", + "mcwifipnp.gui.PvP.info":"Toggles PvP. Disabling PvP will also prevent you from taking damage from your own projectiles.", + "mcwifipnp.gui.UseUPnP": "Forward Port", + "mcwifipnp.gui.UseUPnP.info": "Whether to use the UPnP function to map the LAN game port number.", + "mcwifipnp.gui.Local": "Local", + "mcwifipnp.gui.Global": "Global", + "mcwifipnp.gui.CopyIP": "Get IP", + "mcwifipnp.gui.CopyIP.info": "Get IP to copying to clipboard", + "mcwifipnp.upnp.success": "Successfully forwarded port %s", + "mcwifipnp.upnp.clipboard": "Successfully got %s, Due to factors such as NAT, these IPs may still not be able to connect directly.", + "mcwifipnp.upnp.cantgetip": "Couldn't get public IP! Please check your network settings. Your IPv4 may contain multiple NATs or you do not have IPv6.", + "mcwifipnp.upnp.failed.mapped": "Unable to forward port %s: Port was already mapped by another UPnP service, Please change the port number.", + "mcwifipnp.upnp.failed.disabled": "Unable to forward port %s: UPnP is not enabled on your router, You may need to use port mapping software.", + "mcwifipnp.upnp.failed.unknownerror": "Unable to forward port %s: Unknown error while adding port mapping, Please use a port mapping software.", + "mcwifipnp.upnp.failed": "Unable to forward port %s!", + "mcwifipnp.commands.forceoffline.add.failed": "Player is already in force offline list", + "mcwifipnp.commands.forceoffline.add.success": "Added %s to the force offline list", + "mcwifipnp.commands.forceoffline.list": "There are %s players in force offline list: %s", + "mcwifipnp.commands.forceoffline.none": "There are no players in force offline list", + "mcwifipnp.commands.forceoffline.remove.failed": "Player is not in force offline list", + "mcwifipnp.commands.forceoffline.remove.success": "Removed %s from the force offline list" } diff --git a/src/main/resources/assets/mcwifipnp/lang/es_es.json b/src/main/resources/assets/mcwifipnp/lang/es_es.json index 0f56c0d9..02b4bd28 100644 --- a/src/main/resources/assets/mcwifipnp/lang/es_es.json +++ b/src/main/resources/assets/mcwifipnp/lang/es_es.json @@ -1,31 +1,43 @@ { - "mcwifipnp.gui.port": "Número de Puerto", - "mcwifipnp.gui.port.info": "Número de puerto para el Mundo LAN.\nDeja el cuadro de edición vacío o ingresa un número diferente entre 1024 y 65535.", - "mcwifipnp.gui.port.invalid": "Puerto no válido.\nDeja el cuadro de edición vacío o ingresa un número entre 1024 y 65535.", - "mcwifipnp.gui.port.unavailable": "Puerto no disponible.\nDeja el cuadro de edición vacío o ingresa un número diferente entre 1024 y 65535.", - "mcwifipnp.gui.players": "Jugadores Máximos", - "mcwifipnp.gui.players.info": "El número máximo de jugadores que pueden unirse al servidor.", - "mcwifipnp.gui.motd": "MOTD", - "mcwifipnp.gui.motd.info": "La información del servidor que se muestra debajo del nombre en la lista de servidores multijugador.", - "mcwifipnp.gui.AllPlayersCheats": "Trucos de Otros Jugadores", - "mcwifipnp.gui.AllPlayersCheats.info": "Habilita para hacer automáticamente operadores a otros jugadores cuando se unan al servidor. También puedes usar /op para hacer que alguien sea operador.", - "mcwifipnp.gui.Whitelist": "Lista Blanca", - "mcwifipnp.gui.Whitelist.info": "Habilita la lista blanca. Cuando está activada, solo los jugadores en la lista blanca pueden conectarse al servidor. Usa /whitelist para agregar jugadores a la lista.", - "mcwifipnp.gui.OnlineMode": "Modo en Línea", - "mcwifipnp.gui.OnlineMode.info": "Conecta a la base de datos de cuentas de Minecraft para verificar los inicios de sesión. Desactívalo para permitir que las cuentas sin conexión se unan.", - "mcwifipnp.gui.PvP": "PvP", - "mcwifipnp.gui.PvP.info": "Activa o desactiva el PvP. Deshabilitar el PvP también evitará que recibas daño de tus propios proyectiles.", - "mcwifipnp.gui.UseUPnP": "Reenviar Puerto", - "mcwifipnp.gui.UseUPnP.info": "Si se debe usar la función UPnP para asignar el número de puerto del juego LAN.", - "mcwifipnp.gui.Local": "Local", - "mcwifipnp.gui.Global": "Global", - "mcwifipnp.gui.CopyIP": "Obtener IP", - "mcwifipnp.gui.CopyIP.info": "Obtener IP y copiar al portapapeles", - "mcwifipnp.upnp.success": "Puerto %s reenviado con éxito", - "mcwifipnp.upnp.clipboard": "Obtención exitosa de %s. Debido a factores como NAT, es posible que estas IP no puedan conectarse directamente.", - "mcwifipnp.upnp.cantgetip": "¡No se pudo obtener la IP pública! Verifica la configuración de tu red. Tu IPv4 puede contener múltiples NAT o no tener IPv6.", - "mcwifipnp.upnp.failed.mapped": "No se pudo reenviar el puerto %s: El puerto ya estaba asignado por otro servicio UPnP. Cambia el número de puerto.", - "mcwifipnp.upnp.failed.disabled": "No se pudo reenviar el puerto %s: UPnP no está habilitado en tu enrutador. Puede que necesites usar software de asignación de puertos.", - "mcwifipnp.upnp.failed.unknownerror": "No se pudo reenviar el puerto %s: Error desconocido al agregar la asignación de puertos. Usa un software de asignación de puertos.", - "mcwifipnp.upnp.failed": "No se pudo reenviar el puerto %s." + "mcwifipnp.gui.port": "Número de puerto", + "mcwifipnp.gui.port.info": "Número de puerto para el Mundo LAN.\nDeja el cuadro de edición vacío o ingresa un número diferente entre 1024 y 65535.", + "mcwifipnp.gui.port.invalid": "Puerto no válido.\nDeja la caja de edición vacía o elige un número entre 1024 y 65535.", + "mcwifipnp.gui.port.unavailable": "Puerto no disponible.\nDeja la caja de edición vacía o elige un número diferente entre 1024 y 65535.", + "mcwifipnp.gui.players": "Jugadores Máximos", + "mcwifipnp.gui.players.info": "El número máximo de jugadores que pueden unirse al servidor.", + "mcwifipnp.gui.motd": "Mensaje del servidor", + "mcwifipnp.gui.motd.info": "La información del servidor que se muestra debajo del nombre en la lista de servidores multijugador.", + "mcwifipnp.gui.AllPlayersCheats": "Trucos de Otros Jugadores", + "mcwifipnp.gui.AllPlayersCheats.info": "Habilita para hacer automáticamente operadores a otros jugadores cuando se unan al servidor. También puedes usar /op para hacer que alguien sea operador.", + "mcwifipnp.gui.Whitelist": "Lista Blanca", + "mcwifipnp.gui.Whitelist.info": "Habilita la lista blanca. Cuando estaba activada, solo los jugadores en la lista blanca pueden conectarse al servidor. Usa /whitelist para agregar jugadores a la lista.", + "mcwifipnp.gui.OnlineMode": "Modo en Línea", + "mcwifipnp.gui.OnlineMode.info": "Conecta a la base de datos de cuentas de Minecraft para verificar los inicios de sesión. Desactívalo para permitir que las cuentas sin conexión se unan.", + "mcwifipnp.gui.OnlineMode.online": "Activado", + "mcwifipnp.gui.OnlineMode.online.info": "El modo en línea enabe solo permite que los jugadores que se conecten con una cuenta de Microsoft se unan a este servidor.", + "mcwifipnp.gui.OnlineMode.offline": "Desactivado", + "mcwifipnp.gui.OnlineMode.offline.info": "Desactiva Modo en Línea permitirá a los jugadores que se conecten en modo offline unirse a este servidor.", + "mcwifipnp.gui.OnlineMode.fixuuid": "Desactivar + Reparación uuid", + "mcwifipnp.gui.OnlineMode.fixuuid.info": "Trate de coincidir el nombre de usuario del servidor mojang con el nombre del jugador del jugador en modo offline para obtener un uuid único. N al mismo tiempo, los usuarios que se conecten con una cuenta de Microsoft conservarán uuid. N también evita la pérdida de mochilas y artículos de inventario.", + "mcwifipnp.gui.PvP": "PvP", + "mcwifipnp.gui.PvP.info": "Activa o desactiva el PvP. Deshabilitar el PvP también evitará que recibas daño de tus propios proyectiles.", + "mcwifipnp.gui.UseUPnP": "Reenviar Puerto", + "mcwifipnp.gui.UseUPnP.info": "Si se debe usar la función UPnP para asignar el número de puerto del juego LAN.", + "mcwifipnp.gui.Local": "Local", + "mcwifipnp.gui.Global": "Global", + "mcwifipnp.gui.CopyIP": "Obtener IP", + "mcwifipnp.gui.CopyIP.info": "Obtener IP y copiar al portapapeles", + "mcwifipnp.upnp.success": "Puerto %s reenviado con éxito", + "mcwifipnp.upnp.clipboard": "Obtención exitosa de %s. Debido a factores como NAT, es posible que estas IP no puedan conectarse directamente.", + "mcwifipnp.upnp.cantgetip": "¡No se pudo obtener la IP pública! Verifica la configuración de tu red. Tu IPv4 puede contener múltiples NAT o no tener IPv6.", + "mcwifipnp.upnp.failed.mapped": "No se pudo reenviar el puerto %s: El puerto ya estaba asignado por otro servicio UPnP. Cambia el número de puerto.", + "mcwifipnp.upnp.failed.disabled": "No se pudo reenviar el puerto %s: UPnP no estaba habilitado en tu enrutador. Puede que necesites usar software de asignación de puertos.", + "mcwifipnp.upnp.failed.unknownerror": "No se pudo reenviar el puerto %s: Error desconocido al agregar la asignación de puertos. Usa un software de asignación de puertos.", + "mcwifipnp.upnp.failed": "No se pudo reenviar el puerto %s.", + "mcwifipnp.commands.forceoffline.add.failed": "El jugador ya estaba en la lista fuera de línea", + "mcwifipnp.commands.forceoffline.add.success": "Se ha añadido a %s a la lista fuera de línea", + "mcwifipnp.commands.forceoffline.list": "Hay %s jugador(es) en la lista fuera de línea: %s", + "mcwifipnp.commands.forceoffline.none": "No hay jugadores en la lista fuera de línea", + "mcwifipnp.commands.forceoffline.remove.failed": "El jugador no estaba en la lista fuera de línea", + "mcwifipnp.commands.forceoffline.remove.success": "Se ha eliminado a %s de la lista fuera de línea" } diff --git a/src/main/resources/assets/mcwifipnp/lang/ru_ru.json b/src/main/resources/assets/mcwifipnp/lang/ru_ru.json index e7356113..0241ca58 100644 --- a/src/main/resources/assets/mcwifipnp/lang/ru_ru.json +++ b/src/main/resources/assets/mcwifipnp/lang/ru_ru.json @@ -1,31 +1,43 @@ { - "mcwifipnp.gui.port": "Порт", - "mcwifipnp.gui.port.info": "Порт для локального мира.\nОставьте это поле пустым или введите число от 1024 до 65535.", - "mcwifipnp.gui.port.invalid": "Неверный порт.\nОставьте это поле пустым или введите число от 1024 до 65535.", - "mcwifipnp.gui.port.unavailable": "Порт недоступен.\nОставьте это поле пустым или введите число от 1024 до 65535.", - "mcwifipnp.gui.players": "Лимит игроков", - "mcwifipnp.gui.players.info": "Максимальное количество игроков, которые могут присоединиться к серверу.", - "mcwifipnp.gui.motd": "Описание", - "mcwifipnp.gui.motd.info": "Информация о сервере, отображаемая под названием в списке сетевой игры.", - "mcwifipnp.gui.AllPlayersCheats": "Использование команд", - "mcwifipnp.gui.AllPlayersCheats.info": "Разрешать другим игрокам использовать команды.", - "mcwifipnp.gui.Whitelist": "Белый список", - "mcwifipnp.gui.Whitelist.info": "Принудительное включение белого списка. Если эта функция включена, только игроки, внесённые в этот список, смогут подключаться к серверу. Используйте /whitelist для добавления игроков в список.", - "mcwifipnp.gui.OnlineMode": "Проверка лицензии", - "mcwifipnp.gui.OnlineMode.info": "Подключается к базе данных учётных записей Minecraft для проверки логинов. Отключите, чтобы разрешить подключение учётных записей без лицензии.", - "mcwifipnp.gui.PvP": "PvP", - "mcwifipnp.gui.PvP.info": "Переключает возможность игроков наносить прямой урон друг другу. Отключение режима PvP также не позволит вам получать урон от ваших собственных снарядов.", - "mcwifipnp.gui.UseUPnP": "Переадресация порта", - "mcwifipnp.gui.UseUPnP.info": "Следует ли использовать функцию UPnP для сопоставления номера игрового порта локальной сети.", - "mcwifipnp.gui.Local": "Локальный", - "mcwifipnp.gui.Global": "Глобалный", - "mcwifipnp.gui.CopyIP": "Получить IP", - "mcwifipnp.gui.CopyIP.info": "Получить IP для копирования в буфер обмена", - "mcwifipnp.upnp.success": "Порт %s успешно переадресован", - "mcwifipnp.upnp.clipboard": "Успешно получен %s, из-за таких факторов, как NAT, эти IP-адреса, возможно, по-прежнему не смогут подключиться напрямую.", - "mcwifipnp.upnp.cantgetip": "Не удалось получить публичный IP! Пожалуйста, проверьте настройки вашей сети. Возможно, ваш IPv4 содержит несколько NAT-адресов или у вас нет IPv6.", - "mcwifipnp.upnp.failed.mapped": "Не удаётся переадресовать порт %s: порт уже был сопоставлен другой службой UPnP. Пожалуйста, измените номер порта.", - "mcwifipnp.upnp.failed.disabled": "Не удаётся переадресовать порт %s: UPnP на вашем маршрутизаторе не включен. Возможно, вам потребуется использовать программное обеспечение для сопоставления портов.", - "mcwifipnp.upnp.failed.unknownerror": "Не удаётся переадресовать порт %s: неизвестная ошибка при добавлении сопоставления портов. Пожалуйста, используйте программное обеспечение для сопоставления портов.", - "mcwifipnp.upnp.failed": "Не удаётся переадресовать порт %s!" + "mcwifipnp.gui.port": "Порт", + "mcwifipnp.gui.port.info": "Порт для локального мира.\nОставьте это поле пустым или введите число от 1024 до 65535.", + "mcwifipnp.gui.port.invalid": "Неверный порт.\nОставьте это поле пустым или введите число от 1024 до 65535.", + "mcwifipnp.gui.port.unavailable": "Порт недоступен.\nОставьте это поле пустым или введите число от 1024 до 65535.", + "mcwifipnp.gui.players": "Лимит игроков", + "mcwifipnp.gui.players.info": "Максимальное количество игроков, которые могут присоединиться к серверу.", + "mcwifipnp.gui.motd": "Описание", + "mcwifipnp.gui.motd.info": "Информация о сервере, отображаемая под названием в списке сетевой игры.", + "mcwifipnp.gui.AllPlayersCheats": "Использование команд", + "mcwifipnp.gui.AllPlayersCheats.info": "Разрешать другим игрокам использовать команды.", + "mcwifipnp.gui.Whitelist": "Белый список", + "mcwifipnp.gui.Whitelist.info": "Принудительное включение белого списка. Если эта функция включена, только игроки, внесённые в этот список, смогут подключаться к серверу. Используйте /whitelist для добавления игроков в список.", + "mcwifipnp.gui.OnlineMode": "Проверка лицензии", + "mcwifipnp.gui.OnlineMode.info": "Подключается к базе данных учётных записей Minecraft для проверки логинов. Отключите, чтобы разрешить подключение учётных записей без лицензии.", + "mcwifipnp.gui.OnlineMode.online": "Включить", + "mcwifipnp.gui.OnlineMode.online.info": "Включение проверки лицензии позволит подключиться к этому серверу только игрокам, которые вошли в систему с учётной записью Microsoft.", + "mcwifipnp.gui.OnlineMode.offline": "Отключить", + "mcwifipnp.gui.OnlineMode.offline.info": "Отключение проверки лицензии позволит игрокам, которые войдут в систему в автономном режиме, присоединиться к этому серверу.", + "mcwifipnp.gui.OnlineMode.fixuuid": "Отключить с исправлением UUID", + "mcwifipnp.gui.OnlineMode.fixuuid.info": "Попытается сопоставить имя пользователя сервера Mojang с именем игрока для игроков в автономном режиме, чтобы получить уникальный UUID. \nМежду тем, UUID сохраняются для пользователей, входящих в систему с помощью учетных записей Майкрософт.\nЭто также может предотвратить потерю предметов рюкзака и инвентаря.", + "mcwifipnp.gui.PvP": "PvP", + "mcwifipnp.gui.PvP.info": "Переключает возможность игроков наносить прямой урон друг другу. Отключение режима PvP также не позволит вам получать урон от ваших собственных снарядов.", + "mcwifipnp.gui.UseUPnP": "Переадресация порта", + "mcwifipnp.gui.UseUPnP.info": "Следует ли использовать функцию UPnP для сопоставления номера игрового порта локальной сети.", + "mcwifipnp.gui.Local": "Локальный", + "mcwifipnp.gui.Global": "Глобалный", + "mcwifipnp.gui.CopyIP": "Получить IP", + "mcwifipnp.gui.CopyIP.info": "Получить IP для копирования в буфер обмена", + "mcwifipnp.upnp.success": "Порт %s успешно переадресован", + "mcwifipnp.upnp.clipboard": "Успешно получен %s, из-за таких факторов, как NAT, эти IP-адреса, возможно, по-прежнему не смогут подключиться напрямую.", + "mcwifipnp.upnp.cantgetip": "Не удалось получить публичный IP! Пожалуйста, проверьте настройки вашей сети. Возможно, ваш IPv4 содержит несколько NAT-адресов или у вас нет IPv6.", + "mcwifipnp.upnp.failed.mapped": "Не удаётся переадресовать порт %s: порт уже был сопоставлен другой службой UPnP. Пожалуйста, измените номер порта.", + "mcwifipnp.upnp.failed.disabled": "Не удаётся переадресовать порт %s: UPnP на вашем маршрутизаторе не включен. Возможно, вам потребуется использовать программное обеспечение для сопоставления портов.", + "mcwifipnp.upnp.failed.unknownerror": "Не удаётся переадресовать порт %s: неизвестная ошибка при добавлении сопоставления портов. Пожалуйста, используйте программное обеспечение для сопоставления портов.", + "mcwifipnp.upnp.failed": "Не удаётся переадресовать порт %s!", + "mcwifipnp.commands.forceoffline.add.failed": "Игрок уже находится в принудительном автономном списке", + "mcwifipnp.commands.forceoffline.add.success": "%s добавлен в принудительный автономный список", + "mcwifipnp.commands.forceoffline.list": "В принудительном автономном списке есть %s игроков: %s", + "mcwifipnp.commands.forceoffline.none": "В принудительном автономном списке нет игроков", + "mcwifipnp.commands.forceoffline.remove.failed": "Игрок не находится в принудительном автономном списке", + "mcwifipnp.commands.forceoffline.remove.success": "%s удалён из принудительного автономного списка" } diff --git a/src/main/resources/assets/mcwifipnp/lang/zh_cn.json b/src/main/resources/assets/mcwifipnp/lang/zh_cn.json index 9ac5c9b4..39fda2f1 100644 --- a/src/main/resources/assets/mcwifipnp/lang/zh_cn.json +++ b/src/main/resources/assets/mcwifipnp/lang/zh_cn.json @@ -1,31 +1,43 @@ { - "mcwifipnp.gui.port":"端口号", - "mcwifipnp.gui.port.info":"局域网游戏端口号。\n请将编辑框留空,或输入一个介于1024至65535之间的数字。", - "mcwifipnp.gui.port.invalid": "端口无效。\n请将编辑框留空,或输入一个介于1024至65535之间的数字。", - "mcwifipnp.gui.port.unavailable": "端口不可用。\n请将编辑框留空,或输入一个介于1024至65535之间的新数字。", - "mcwifipnp.gui.players":"允许玩家数", - "mcwifipnp.gui.players.info":"服务器同时能容纳的最大玩家数量。", - "mcwifipnp.gui.motd":"服务器信息", - "mcwifipnp.gui.motd.info":"玩家客户端的多人游戏服务器列表中显示于名称下方的服务器信息。", - "mcwifipnp.gui.AllPlayersCheats":"其他玩家作弊", - "mcwifipnp.gui.AllPlayersCheats.info":"是否允许其他玩家作弊,你可以使用/op命令开放某人的作弊权限。", - "mcwifipnp.gui.Whitelist":"白名单", - "mcwifipnp.gui.Whitelist.info":"是否服务器的白名单。当启用时,只有白名单上的用户才能连接服务器。", - "mcwifipnp.gui.OnlineMode": "正版验证", - "mcwifipnp.gui.OnlineMode.info": "是否让服务器对比Minecraft账户数据库验证登录信息。", - "mcwifipnp.gui.PvP":"PvP", - "mcwifipnp.gui.PvP.info":"是否允许PvP。也只有在允许PvP时玩家自己的箭才会受到伤害。", - "mcwifipnp.gui.UseUPnP": "映射端口", - "mcwifipnp.gui.UseUPnP.info": "是否使用UPnP功能映射局域网游戏端口号。", - "mcwifipnp.gui.Local": "内网", - "mcwifipnp.gui.Global": "公网", - "mcwifipnp.gui.CopyIP": "获取IP", - "mcwifipnp.gui.CopyIP.info": "获取你的IP地址到剪切板。", - "mcwifipnp.upnp.success": "成功转发端口%s", - "mcwifipnp.upnp.clipboard": "成功获取到%s,由于NAT等因素,这些IP可能仍旧无法直接联机。", - "mcwifipnp.upnp.cantgetip": "无法获取IP!请检查你的网络设置。你的IPv4可能包含多级NAT或者你无IPv6。", - "mcwifipnp.upnp.failed.mapped": "无法转发端口%s:端口%s已被另一个UPnP服务映射,请更换端口。", - "mcwifipnp.upnp.failed.disabled": "无法转发端口%s:路由器上未启用UPnP,你可能需要端口映射软件。", - "mcwifipnp.upnp.failed.unknownerror": "无法转发端口%s:添加端口映射时出现未知错误,请使用端口映射软件。", - "mcwifipnp.upnp.failed": "无法转发端口%s!请使用端口映射软件。" + "mcwifipnp.gui.port": "端口号", + "mcwifipnp.gui.port.info": "局域网游戏端口号。\n请将编辑框留空,或输入一个介于1024至65535之间的数字。", + "mcwifipnp.gui.port.invalid": "端口无效。\n请将编辑框留空,或输入一个介于1024至65535之间的数字。", + "mcwifipnp.gui.port.unavailable": "端口不可用。\n请将编辑框留空,或输入一个介于1024至65535之间的新数字。", + "mcwifipnp.gui.players": "允许玩家数", + "mcwifipnp.gui.players.info": "服务器同时能容纳的最大玩家数量。", + "mcwifipnp.gui.motd": "服务器信息", + "mcwifipnp.gui.motd.info": "玩家客户端的多人游戏服务器列表中显示于名称下方的服务器信息。", + "mcwifipnp.gui.AllPlayersCheats": "其他玩家作弊", + "mcwifipnp.gui.AllPlayersCheats.info": "是否允许其他玩家作弊,你可以使用/op命令开放某人的作弊权限。", + "mcwifipnp.gui.Whitelist": "白名单", + "mcwifipnp.gui.Whitelist.info": "是否服务器的白名单。当启用时,只有白名单上的用户才能连接服务器。", + "mcwifipnp.gui.OnlineMode": "正版验证", + "mcwifipnp.gui.OnlineMode.info": "是否让服务器比对Mojang服务器数据库验证登录信息。", + "mcwifipnp.gui.OnlineMode.online": "启用", + "mcwifipnp.gui.OnlineMode.online.info": "启用正版验证将只允许使用微软帐户登录的玩家加入本服务器。", + "mcwifipnp.gui.OnlineMode.offline": "禁用", + "mcwifipnp.gui.OnlineMode.offline.info": "禁用正版验证将允许使用离线模式登录的玩家加入本服务器。", + "mcwifipnp.gui.OnlineMode.fixuuid": "禁用 + 修复UUID", + "mcwifipnp.gui.OnlineMode.fixuuid.info": "尝试使用离线模式登录的玩家名匹配Mojang服务器用户名称以获取唯一UUID。\n同时为使用微软帐户登录的用户保留UUID。\n它也可以防止背包和物品栏内容丢失。", + "mcwifipnp.gui.PvP": "PvP", + "mcwifipnp.gui.PvP.info": "是否允许PvP。也只有在允许PvP时玩家自己的箭才会受到伤害。", + "mcwifipnp.gui.UseUPnP": "映射端口", + "mcwifipnp.gui.UseUPnP.info": "是否使用UPnP功能映射局域网游戏端口号。", + "mcwifipnp.gui.Local": "内网", + "mcwifipnp.gui.Global": "公网", + "mcwifipnp.gui.CopyIP": "获取IP", + "mcwifipnp.gui.CopyIP.info": "是否获取你当前设备的IP地址,以便于你直接复制。", + "mcwifipnp.upnp.success": "成功转发端口%s", + "mcwifipnp.upnp.clipboard": "成功获取到%s,由于NAT等因素,这些IP可能仍旧无法直接联机。", + "mcwifipnp.upnp.cantgetip": "无法获取IP!请检查你的网络设置。你的IPv4可能包含多级NAT或者你无IPv6。", + "mcwifipnp.upnp.failed.mapped": "无法转发端口%s:端口%s已被另一个UPnP服务映射,请更换端口。", + "mcwifipnp.upnp.failed.disabled": "无法转发端口%s:路由器上未启用UPnP,你可能需要端口映射软件。", + "mcwifipnp.upnp.failed.unknownerror": "无法转发端口%s:添加端口映射时出现未知错误,请使用端口映射软件。", + "mcwifipnp.upnp.failed": "无法转发端口%s!请使用端口映射软件。", + "mcwifipnp.commands.forceoffline.add.failed": "玩家已在强制离线模式列表内", + "mcwifipnp.commands.forceoffline.add.success": "已将%s加入强制离线模式列表", + "mcwifipnp.commands.forceoffline.list": "强制离线模式列表中共有%s名玩家:%s", + "mcwifipnp.commands.forceoffline.none": "强制离线模式列表中没有玩家", + "mcwifipnp.commands.forceoffline.remove.failed": "玩家不在强制离线模式列表内", + "mcwifipnp.commands.forceoffline.remove.success": "已将%s移出强制离线模式列表" } diff --git a/src/main/resources/assets/mcwifipnp/lang/zh_hk.json b/src/main/resources/assets/mcwifipnp/lang/zh_hk.json index 4b4a529e..37dc4aed 100644 --- a/src/main/resources/assets/mcwifipnp/lang/zh_hk.json +++ b/src/main/resources/assets/mcwifipnp/lang/zh_hk.json @@ -1,31 +1,43 @@ { - "mcwifipnp.gui.port":"端口號", - "mcwifipnp.gui.port.info":"局域網遊戲端口碼。\n請闕之,抑再入1024至65535間之數。", - "mcwifipnp.gui.port.invalid": "端口碼不可用。\n請闕之,抑再入1024至65535間之數。", - "mcwifipnp.gui.port.unavailable": "端口碼不可用。\n請闕之,抑再入1024至65535間之另數。", - "mcwifipnp.gui.players":"允許玩家數", - "mcwifipnp.gui.players.info":"服務器同時能容納的最大玩家數量。", - "mcwifipnp.gui.motd":"伺服器信息", - "mcwifipnp.gui.motd.info":"玩家客戶端的多人遊戲服務器列錶中顯示於名稱下方的服務器信息。", - "mcwifipnp.gui.AllPlayersCheats":"其他玩家作弊", - "mcwifipnp.gui.AllPlayersCheats.info":"是否允許其他玩家作弊,你可以使用/op命令開放某人的作弊權限。", - "mcwifipnp.gui.Whitelist":"白名单", - "mcwifipnp.gui.Whitelist.info":"是否服務器的白名單。當啓用時,隻有白名單上的用戶才能連接服務器。", + "mcwifipnp.gui.port": "端口號", + "mcwifipnp.gui.port.info": "局域網遊戲端口碼。\n請闕之,抑再入 1024 至 65535 間之數。", + "mcwifipnp.gui.port.invalid": "端口碼不可用。\n請闕之,抑再入 1024 至 65535 間之數。", + "mcwifipnp.gui.port.unavailable": "端口碼不可用。\n請闕之,抑再入 1024 至 65535 間之另數。", + "mcwifipnp.gui.players": "允許玩家數", + "mcwifipnp.gui.players.info": "伺服器同時能容納的最大玩家數量。", + "mcwifipnp.gui.motd": "伺服器信息", + "mcwifipnp.gui.motd.info": "玩家客戶端的多人遊戲服務器列錶中顯示於名稱下方的服務器信息。", + "mcwifipnp.gui.AllPlayersCheats": "其他玩家作弊", + "mcwifipnp.gui.AllPlayersCheats.info": "是否允許其他玩家作弊,你可以使用 /op 命令開放某人的作弊權限。", + "mcwifipnp.gui.Whitelist": "白名单", + "mcwifipnp.gui.Whitelist.info": "是否伺服器的白名單。當啓用時,隻有白名單上的用戶才能連接服務器。", "mcwifipnp.gui.OnlineMode": "正版驗證", - "mcwifipnp.gui.OnlineMode.info": "是否讓服務器對比Minecraft賬戶數據庫驗證登入信息。", - "mcwifipnp.gui.PvP":"PvP", - "mcwifipnp.gui.PvP.info":"是否允許PvP。也隻有在允許PvP時玩家自己的箭才會受到傷害。", + "mcwifipnp.gui.OnlineMode.info": "是否讓服務器對比 Mojang 伺服器賬戶數據庫驗證登入信息。", + "mcwifipnp.gui.OnlineMode.online": "啟用", + "mcwifipnp.gui.OnlineMode.online.info": "啟用正版驗證將只允許使用微軟帳戶登入的玩家加入本服務器。", + "mcwifipnp.gui.OnlineMode.offline": "禁用", + "mcwifipnp.gui.OnlineMode.offline.info": "禁用正版驗證將允許使用離線模式登入的玩家加入本服務器。", + "mcwifipnp.gui.OnlineMode.fixuuid": "禁用+修復UUID", + "mcwifipnp.gui.OnlineMode.fixuuid.info": "嘗試使用離線模式登入的玩家名匹配Mojang服務器用戶名稱以獲取唯一UUID。\n同時為使用微軟帳戶登入的用戶保留UUID。\n它也可以防止背包和物品欄內容遺失。", + "mcwifipnp.gui.PvP": "PvP", + "mcwifipnp.gui.PvP.info": "是否允許 PvP。也隻有在允許 PvP 時玩家自己的箭才會受到傷害。", "mcwifipnp.gui.UseUPnP": "映射端口", - "mcwifipnp.gui.UseUPnP.info": "是否使用UPnP功能映射局域網遊戲端口號。", + "mcwifipnp.gui.UseUPnP.info": "是否使用 UPnP 功能映射局域網遊戲端口號。", "mcwifipnp.gui.Local": "內網", "mcwifipnp.gui.Global": "公網", - "mcwifipnp.gui.CopyIP": "獲取IP", - "mcwifipnp.gui.CopyIP.info": "獲取內網IP地址及公網IP地址", - "mcwifipnp.upnp.success": "成功轉發端口%s", - "mcwifipnp.upnp.clipboard": "成功獲取到%s,由於NAT等因素,這些IP可能仍舊無法直接聯機。", - "mcwifipnp.upnp.cantgetip": "無法獲取IP!請檢查你嘅網路設置。你嘅IPv4可能包含多級NAT或者你無IPv6。", - "mcwifipnp.upnp.failed.mapped": "無法轉發端口%s:端口%s已被另一個UPnP服務映射,請更換端口。", - "mcwifipnp.upnp.failed.disabled": "無法轉發端口%s:路由器上未啟用UPnP,你可能需要端口映射軟件。", - "mcwifipnp.upnp.failed.unknownerror": "無法轉發端口%s:添加端口映射時出現未知錯誤,請使用端口映射軟件。", - "mcwifipnp.upnp.failed": "無法轉發端口%s!請使用端口映射軟件。" + "mcwifipnp.gui.CopyIP": "獲取 IP", + "mcwifipnp.gui.CopyIP.info": "取得內網 IP 地址及公網 IP 地址,以便於你直接複製。", + "mcwifipnp.upnp.success": "成功轉發端口 %s", + "mcwifipnp.upnp.clipboard": "成功獲取到 %s,由於NAT等因素,這些 IP 可能仍舊無法直接聯機。", + "mcwifipnp.upnp.cantgetip": "無法獲取 IP!請檢查你嘅網路設置。你嘅 IPv4 可能包含多級 NAT 或者你無 IPv6。", + "mcwifipnp.upnp.failed.mapped": "無法轉發端口 %s:端口 %s 已被另一個 UPnP 服務映射,請更換端口。", + "mcwifipnp.upnp.failed.disabled": "無法轉發端口 %s:路由器上未啟用 UPnP,你可能需要端口映射軟件。", + "mcwifipnp.upnp.failed.unknownerror": "無法轉發端口 %s:添加端口映射時出現未知錯誤,請使用端口映射軟件。", + "mcwifipnp.upnp.failed": "無法轉發端口 %s!請使用端口映射軟件。", + "mcwifipnp.commands.forceoffline.add.failed": "玩家已在強制離線模式清單內", + "mcwifipnp.commands.forceoffline.add.success": "已將 %s 加入強制離線模式清單", + "mcwifipnp.commands.forceoffline.list": "強制離線模式清單中共有%s名玩家:%s", + "mcwifipnp.commands.forceoffline.none": "強制離線模式清單中沒有玩家", + "mcwifipnp.commands.forceoffline.remove.failed": "玩家不在強制離線模式清單內", + "mcwifipnp.commands.forceoffline.remove.success": "已將 %s 移出強制離線模式清單" } diff --git a/src/main/resources/assets/mcwifipnp/lang/zh_tw.json b/src/main/resources/assets/mcwifipnp/lang/zh_tw.json index 51ae5a74..86d4f507 100644 --- a/src/main/resources/assets/mcwifipnp/lang/zh_tw.json +++ b/src/main/resources/assets/mcwifipnp/lang/zh_tw.json @@ -1,31 +1,43 @@ { - "mcwifipnp.gui.port":"連接埠", - "mcwifipnp.gui.port.info":"區域網路遊戲連接埠。\n將編輯框留空或輸入 1024 到 65535 之間的數字。", - "mcwifipnp.gui.port.invalid": "連接埠不可用。\n將編輯框留空或輸入 1024 到 65535 之間的數字。", - "mcwifipnp.gui.port.unavailable": "連接埠不可用。\n將編輯框留空或輸入 1024 到 65535 之間不同的數字。", - "mcwifipnp.gui.players":"允許玩家數", - "mcwifipnp.gui.players.info":"伺服器同時能容納的最大玩家數量。", - "mcwifipnp.gui.motd":"伺服器資訊", - "mcwifipnp.gui.motd.info":"玩家用戶端的多人遊戲伺服器清單中顯示於名稱下方的伺服器資訊。", - "mcwifipnp.gui.AllPlayersCheats":"其他玩家是否能作弊", - "mcwifipnp.gui.AllPlayersCheats.info":"是否允許其他玩家作弊,你可以使用 /op 指令開放某人的作弊權限。", - "mcwifipnp.gui.Whitelist":"白名單", - "mcwifipnp.gui.Whitelist.info":"是否伺服器的白名單。當啟用時,只有白名單上的使用者才能連線伺服器。", - "mcwifipnp.gui.OnlineMode": "正版驗證", - "mcwifipnp.gui.OnlineMode.info": "是否讓伺服器對比 Minecraft 帳號資料庫驗證登入資訊。", - "mcwifipnp.gui.PvP":"PvP", - "mcwifipnp.gui.PvP.info":"是否允許 PvP。也只有在允許 PvP 時玩家自己的箭才會受到傷害。", - "mcwifipnp.gui.UseUPnP": "連接埠轉送", - "mcwifipnp.gui.UseUPnP.info": "是否使用 UPnP 功能轉送區域網路遊戲連接埠。", - "mcwifipnp.gui.Local": "內網", - "mcwifipnp.gui.Global": "公網", - "mcwifipnp.gui.CopyIP": "取得 IP", - "mcwifipnp.gui.CopyIP.info": "取得內網 IP 地址及公網 IP 地址", - "mcwifipnp.upnp.success": "成功連接埠轉送 %s", - "mcwifipnp.upnp.clipboard": "成功取得到 %s,由於 NAT 等因素,這些 IP 可能仍舊無法直接聯機。", - "mcwifipnp.upnp.cantgetip": "無法取得 IP!請檢查你的網路設定。你的 IPv4 可能包含多級 NAT 或者你無 IPv6。", - "mcwifipnp.upnp.failed.mapped": "無法連接埠轉送 %s:連接埠 %s 已被另一個 UPnP 服務轉送,請變更連接埠。", - "mcwifipnp.upnp.failed.disabled": "無法連接埠轉送 %s:路由器上未啟用 UPnP,你可能需要連接埠轉送軟體。", - "mcwifipnp.upnp.failed.unknownerror": "無法連接埠轉送 %s:增加連接埠轉送時出現未知錯誤,請使用連接埠轉送軟體。", - "mcwifipnp.upnp.failed": "無法連接埠轉送 %s!請使用連接埠轉送軟體。" + "mcwifipnp.gui.port": "連接埠", + "mcwifipnp.gui.port.info": "區域網路遊戲連接埠。\n將編輯框留空或輸入 1024 到 65535 之間的數字。", + "mcwifipnp.gui.port.invalid": "連接埠不可用。\n將編輯框留空或輸入 1024 到 65535 之間的數字。", + "mcwifipnp.gui.port.unavailable": "連接埠不可用。\n將編輯框留空或輸入 1024 到 65535 之間不同的數字。", + "mcwifipnp.gui.players": "允許玩家數", + "mcwifipnp.gui.players.info": "伺服器同時能容納的最大玩家數量。", + "mcwifipnp.gui.motd": "伺服器資訊", + "mcwifipnp.gui.motd.info": "玩家用戶端的多人遊戲伺服器清單中顯示於名稱下方的伺服器資訊。", + "mcwifipnp.gui.AllPlayersCheats": "其他玩家是否能作弊", + "mcwifipnp.gui.AllPlayersCheats.info": "是否允許其他玩家作弊,你可以使用 /op 指令開放某人的作弊權限。", + "mcwifipnp.gui.Whitelist": "白名單", + "mcwifipnp.gui.Whitelist.info": "是否伺服器的白名單。當啟用時,只有白名單上的使用者才能連線伺服器。", + "mcwifipnp.gui.OnlineMode": "正版驗證", + "mcwifipnp.gui.OnlineMode.info": "是否讓伺服器對比 Mojang 伺服器帳號資料庫驗證登入資訊。", + "mcwifipnp.gui.OnlineMode.online": "啟用", + "mcwifipnp.gui.OnlineMode.online.info": "啟用正版驗證將只允許使用微軟帳戶登入的玩家加入本服務器。", + "mcwifipnp.gui.OnlineMode.offline": "禁用", + "mcwifipnp.gui.OnlineMode.offline.info": "禁用正版驗證將允許使用離線模式登入的玩家加入本服務器。", + "mcwifipnp.gui.OnlineMode.fixuuid": "禁用+修復UUID", + "mcwifipnp.gui.OnlineMode.fixuuid.info": "嘗試使用離線模式登入的玩家名匹配Mojang服務器用戶名稱以獲取唯一UUID。\n同時為使用微軟帳戶登入的用戶保留UUID。\n它也可以防止背包和物品欄內容遺失。", + "mcwifipnp.gui.PvP": "PvP", + "mcwifipnp.gui.PvP.info": "是否允許 PvP。也只有在允許 PvP 時玩家自己的箭才會受到傷害。", + "mcwifipnp.gui.UseUPnP": "連接埠轉送", + "mcwifipnp.gui.UseUPnP.info": "是否使用 UPnP 功能轉送區域網路遊戲連接埠。", + "mcwifipnp.gui.Local": "內網", + "mcwifipnp.gui.Global": "公網", + "mcwifipnp.gui.CopyIP": "取得 IP", + "mcwifipnp.gui.CopyIP.info": "取得內網 IP 地址及公網 IP 地址,以便於你直接複製。", + "mcwifipnp.upnp.success": "成功連接埠轉送 %s", + "mcwifipnp.upnp.clipboard": "成功取得到 %s,由於 NAT 等因素,這些 IP 可能仍舊無法直接聯機。", + "mcwifipnp.upnp.cantgetip": "無法取得 IP!請檢查你的網路設定。你的 IPv4 可能包含多級 NAT 或者你無 IPv6。", + "mcwifipnp.upnp.failed.mapped": "無法連接埠轉送 %s:連接埠 %s 已被另一個 UPnP 服務轉送,請變更連接埠。", + "mcwifipnp.upnp.failed.disabled": "無法連接埠轉送 %s:路由器上未啟用 UPnP,你可能需要連接埠轉送軟體。", + "mcwifipnp.upnp.failed.unknownerror": "無法連接埠轉送 %s:增加連接埠轉送時出現未知錯誤,請使用連接埠轉送軟體。", + "mcwifipnp.upnp.failed": "無法連接埠轉送 %s!請使用連接埠轉送軟體。", + "mcwifipnp.commands.forceoffline.add.failed": "玩家已在強制離線模式清單內", + "mcwifipnp.commands.forceoffline.add.success": "已將 %s 加入強制離線模式清單", + "mcwifipnp.commands.forceoffline.list": "強制離線模式清單中共有%s名玩家:%s", + "mcwifipnp.commands.forceoffline.none": "強制離線模式清單中沒有玩家", + "mcwifipnp.commands.forceoffline.remove.failed": "玩家不在強制離線模式清單內", + "mcwifipnp.commands.forceoffline.remove.success": "已將 %s 移出強制離線模式清單" } diff --git a/src/main/resources/mcwifipnp.mixins.json b/src/main/resources/mcwifipnp.mixins.json new file mode 100644 index 00000000..91a71eb2 --- /dev/null +++ b/src/main/resources/mcwifipnp.mixins.json @@ -0,0 +1,13 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "io.github.satxm.mcwifipnp.mixin", + "compatibilityLevel": "JAVA_16", + "client": [ + "PlayerListAccessor", + "MixinPlayer" + ], + "injectors": { + "defaultRequire": 1 + } +} \ No newline at end of file diff --git a/src/main/resources/pack.mcmeta b/src/main/resources/pack.mcmeta new file mode 100644 index 00000000..d948f580 --- /dev/null +++ b/src/main/resources/pack.mcmeta @@ -0,0 +1,7 @@ +{ + "pack": { + "description": "LAN World Plug-n-Play", + "pack_format": 7, + "_comment": "A Minecraft LAN World Tool With WLAN UPnP." + } +}