├── .gitignore ├── LICENSE ├── README.md ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src ├── main ├── java │ ├── cn │ │ └── moonmc │ │ │ ├── ability │ │ │ ├── AbilityServer.java │ │ │ ├── chooseServer │ │ │ │ ├── ChooseServer.java │ │ │ │ └── 描述.md │ │ │ ├── login │ │ │ │ ├── Login.java │ │ │ │ ├── data │ │ │ │ │ ├── User.java │ │ │ │ │ ├── UserManager.java │ │ │ │ │ ├── bookpage │ │ │ │ │ │ └── Paragraph.java │ │ │ │ │ └── password │ │ │ │ │ │ ├── EncryptionMethod.java │ │ │ │ │ │ ├── HashedPassword.java │ │ │ │ │ │ ├── HexSaltedMethod.java │ │ │ │ │ │ └── Sha256.java │ │ │ │ ├── event │ │ │ │ │ └── LoginSuccessfulEvent.java │ │ │ │ ├── lister │ │ │ │ │ ├── LoginState.java │ │ │ │ │ └── PlayerJoin.java │ │ │ │ └── utils │ │ │ │ │ ├── HashUtils.java │ │ │ │ │ ├── RandomStringUtils.java │ │ │ │ │ └── SMSCodeUtils.java │ │ │ ├── notify │ │ │ │ └── ServerEula.java │ │ │ └── 描述.md │ │ │ └── limboAdd │ │ │ ├── AddServer.java │ │ │ ├── config │ │ │ └── ConfigFile.java │ │ │ ├── packets │ │ │ ├── PackReg.java │ │ │ ├── in │ │ │ │ ├── PacketClickButtonContainer.java │ │ │ │ ├── PacketClickContainer.java │ │ │ │ ├── PacketCloseContainer.java │ │ │ │ ├── PacketPlayerChatMessage.java │ │ │ │ ├── PacketPlayerCommand.java │ │ │ │ └── PacketRenameItem.java │ │ │ └── out │ │ │ │ ├── PacketOpenBook.java │ │ │ │ ├── PacketOpenMenu.java │ │ │ │ ├── PacketPluginMessage.java │ │ │ │ ├── PacketSetContainerProperty.java │ │ │ │ ├── PacketSetContainerSlot.java │ │ │ │ ├── PacketSetHeldItem.java │ │ │ │ ├── PlayDisconnect.java │ │ │ │ └── PlayerCloveInventory.java │ │ │ ├── works │ │ │ ├── entity │ │ │ │ ├── Attachments.java │ │ │ │ └── Player.java │ │ │ ├── event │ │ │ │ ├── Cancelable.java │ │ │ │ ├── Event.java │ │ │ │ ├── EventManager.java │ │ │ │ ├── Lister.java │ │ │ │ └── playerEvent │ │ │ │ │ ├── PlayerCancelableEvent.java │ │ │ │ │ ├── PlayerChatEvent.java │ │ │ │ │ ├── PlayerClickButtonContainer.java │ │ │ │ │ ├── PlayerClickContainer.java │ │ │ │ │ ├── PlayerCloseContainer.java │ │ │ │ │ ├── PlayerCommandEvent.java │ │ │ │ │ ├── PlayerConnectEvent.java │ │ │ │ │ ├── PlayerEvent.java │ │ │ │ │ ├── PlayerJoinEvent.java │ │ │ │ │ ├── PlayerQuitEvent.java │ │ │ │ │ └── PlayerRenameItem.java │ │ │ ├── menu │ │ │ │ ├── AnvilInventory.java │ │ │ │ ├── BookItemNBTs.java │ │ │ │ ├── GenericInventory.java │ │ │ │ ├── Inventory.java │ │ │ │ ├── InventoryManager.java │ │ │ │ ├── Item.java │ │ │ │ ├── ItemNBTs.java │ │ │ │ ├── ItemType.java │ │ │ │ ├── LecternInventory.java │ │ │ │ ├── PlayerInventory.java │ │ │ │ ├── ShowInventory.java │ │ │ │ └── Slot.java │ │ │ ├── message │ │ │ │ ├── ClickEvent.java │ │ │ │ ├── ClickEventChangePage.java │ │ │ │ ├── ClickEventRunCommand.java │ │ │ │ ├── ClickEventoOpenUrl.java │ │ │ │ ├── HoverEvent.java │ │ │ │ ├── HoverEventShowItem.java │ │ │ │ ├── HoverEventShowText.java │ │ │ │ ├── JsonText.java │ │ │ │ ├── JsonTextArticle.java │ │ │ │ └── JsonTextParagraph.java │ │ │ └── readme.md │ │ │ └── 描述.md │ └── ru │ │ └── nanit │ │ └── limbo │ │ ├── LimboConstants.java │ │ ├── NanoLimbo.java │ │ ├── configuration │ │ ├── LimboConfig.java │ │ └── SocketAddressSerializer.java │ │ ├── connection │ │ ├── ClientChannelInitializer.java │ │ ├── ClientConnection.java │ │ ├── GameProfile.java │ │ ├── PacketHandler.java │ │ ├── PacketSnapshots.java │ │ └── pipeline │ │ │ ├── PacketDecoder.java │ │ │ ├── PacketEncoder.java │ │ │ ├── VarIntByteDecoder.java │ │ │ ├── VarIntFrameDecoder.java │ │ │ └── VarIntLengthEncoder.java │ │ ├── protocol │ │ ├── ByteMessage.java │ │ ├── Packet.java │ │ ├── PacketIn.java │ │ ├── PacketOut.java │ │ ├── PacketSnapshot.java │ │ ├── packets │ │ │ ├── PacketHandshake.java │ │ │ ├── login │ │ │ │ ├── PacketDisconnect.java │ │ │ │ ├── PacketLoginPluginRequest.java │ │ │ │ ├── PacketLoginPluginResponse.java │ │ │ │ ├── PacketLoginStart.java │ │ │ │ └── PacketLoginSuccess.java │ │ │ ├── play │ │ │ │ ├── PacketBossBar.java │ │ │ │ ├── PacketChatMessage.java │ │ │ │ ├── PacketDeclareCommands.java │ │ │ │ ├── PacketJoinGame.java │ │ │ │ ├── PacketKeepAlive.java │ │ │ │ ├── PacketPlayerAbilities.java │ │ │ │ ├── PacketPlayerInfo.java │ │ │ │ ├── PacketPlayerListHeader.java │ │ │ │ ├── PacketPlayerPositionAndLook.java │ │ │ │ ├── PacketPluginMessage.java │ │ │ │ ├── PacketTitleLegacy.java │ │ │ │ ├── PacketTitleSetSubTitle.java │ │ │ │ ├── PacketTitleSetTitle.java │ │ │ │ └── PacketTitleTimes.java │ │ │ └── status │ │ │ │ ├── PacketStatusPing.java │ │ │ │ ├── PacketStatusRequest.java │ │ │ │ └── PacketStatusResponse.java │ │ └── registry │ │ │ ├── State.java │ │ │ └── Version.java │ │ ├── server │ │ ├── Command.java │ │ ├── CommandManager.java │ │ ├── Connections.java │ │ ├── LimboServer.java │ │ ├── Logger.java │ │ ├── commands │ │ │ ├── CmdConn.java │ │ │ ├── CmdHelp.java │ │ │ ├── CmdMem.java │ │ │ └── CmdStop.java │ │ └── data │ │ │ ├── BossBar.java │ │ │ ├── InfoForwarding.java │ │ │ ├── PingData.java │ │ │ └── Title.java │ │ ├── util │ │ ├── Colors.java │ │ └── UuidUtil.java │ │ └── world │ │ ├── Location.java │ │ └── dimension │ │ ├── Dimension.java │ │ └── DimensionRegistry.java └── resources │ ├── LICENSE-configurate-yaml │ ├── LICENSE-netty │ ├── ServerEula.json │ ├── chooseServerBook.json │ ├── dimension │ ├── codec_1_16.snbt │ ├── codec_1_18_2.snbt │ ├── codec_1_19.snbt │ ├── codec_1_19_1.snbt │ └── codec_old.snbt │ ├── loginDataBase.properties │ └── settings.yml └── test └── java ├── pattern.java └── 生成uuid.java /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .gradle 3 | build 4 | settings.yml -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## moonlimboauthserver 2 | 本项目fork自项目https://github.com/Nan1t/NanoLimbo 3 | 此分支为活跃状态,供学习参考使用 4 | 公开服:x.moonmc.cn 5 | 正版服:play.moonmc.cn 6 | 交流:http://tt.moonmc.cn 7 | 8 | 以下内容为NanoLimbo Readme.md 9 | ## NanoLimbo 10 | 11 | This is lightweight minecraft limbo server, written on Java with Netty. 12 | The main goal of the project is maximum simplicity with a minimum number of sent and processed packets. 13 | This limbo is empty, there are no ability to set schematic building since 14 | this is not necessary. You can send useful information in chat or BossBar. 15 | 16 | No plugins, no logs. The server is fully clear. It only able keep a lot of players while the main server is down. 17 | 18 | The general features: 19 | * High performance. The server not saves and not cached any useless (for limbo) data. 20 | * Doesn't spawn threads per player. Uses fixed threads pool. 21 | * Support for **BungeeCord** and **Velocity** info forwarding. 22 | * Support for [BungeeGuard](https://www.spigotmc.org/resources/79601/) handshake format. 23 | * Multiple versions support. 24 | * Fully configurable. 25 | * Lightweight. App size around **2MB.** 26 | 27 | ![](https://i.imgur.com/sT8p1Gz.png) 28 | 29 | ### Versions support 30 | 31 | Symbol `X` means all minor versions. 32 | 33 | - [x] 1.8.X 34 | - [x] 1.9.X 35 | - [x] 1.10.X 36 | - [x] 1.11.X 37 | - [x] 1.12.X 38 | - [x] 1.13.X 39 | - [x] 1.14.X 40 | - [x] 1.15.X 41 | - [x] 1.16.X 42 | - [x] 1.17.X 43 | - [x] 1.18.X 44 | - [x] 1.19 45 | - [x] 1.19.1 46 | 47 | The server **doesn't** support snapshots. 48 | 49 | ### Commands 50 | 51 | * `help` - Show help message 52 | * `conn` - Display amount of connections 53 | * `mem` - Display memory usage stats 54 | * `stop` - Stop the server 55 | 56 | Note, that it also will be closed correctly if you just press `Ctrl+C`. 57 | 58 | ### Installation 59 | 60 | The installation process is simple. 61 | 62 | 1. Download the latest version of program **[here](https://github.com/Nan1t/NanoLimbo/releases)** 63 | 2. Put jar file in the folder you want. 64 | 3. Create a start script as you did it for Bukkit or BungeeCord with command like this: 65 | `java -jar NanoLimbo-.jar` 66 | 4. The server will create `settings.yml` file. It's a server configuration. 67 | 5. Configure it as you want and restart server. 68 | 69 | ### About player info forwarding 70 | 71 | The server supports player info forwarding from the proxy. There are several types of info forwarding: 72 | 73 | * `LEGACY` - The **BungeeCord** IP forwarding. 74 | * `MODERN` - **Velocity** native info forwarding type. 75 | * `BUNGEE_GUARD` - **BungeeGuard** forwarding type. 76 | 77 | If you use BungeeCord, or Velocity with `LEGACY` forwarding, just set this type in the config. 78 | If you use Velocity with `MODERN` info forwarding, set this type and paste secret key from Velocity 79 | config into `secret` field. 80 | If you installed BungeeGuard on your proxy, then use `BUNGEE_GUARD` forwarding type. 81 | Then add your tokens to `tokens` list. 82 | 83 | ### Contributing 84 | 85 | You can create pull request, if you found some bug, optimization ability, or you want to add some functional, 86 | which is suitable for limbo server and won't significantly load the server. 87 | 88 | ### Building 89 | 90 | Required software: 91 | 92 | * JDK 1.8+ 93 | * Gradle 7+ 94 | 95 | To build minimized .jar, go to project root and write in terminal: 96 | 97 | ``` 98 | gradlew shadowJar 99 | ``` 100 | 101 | ### Contacts 102 | 103 | If you have any question or suggestion, join to [Discord server](https://discord.gg/4VGP3Gv) 104 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | import java.text.SimpleDateFormat 2 | 3 | plugins { 4 | id 'java' 5 | id 'com.github.johnrengelman.shadow' version '7.1.2' 6 | id "io.freefair.lombok" version "6.5.1" 7 | } 8 | 9 | group 'ru.nanit' 10 | version new SimpleDateFormat("yyyy.MM.dd.HHmm").format(new Date()) 11 | 12 | compileJava { 13 | options.encoding = "UTF-8" 14 | } 15 | 16 | tasks.withType(JavaCompile) { 17 | sourceCompatibility = JavaVersion.VERSION_17 18 | targetCompatibility = JavaVersion.VERSION_17 19 | } 20 | 21 | repositories { 22 | mavenCentral() 23 | } 24 | 25 | dependencies { 26 | testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.0' 27 | testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0' 28 | 29 | implementation 'org.spongepowered:configurate-yaml:4.1.2' 30 | implementation 'io.netty:netty-all:4.1.82.Final' 31 | implementation 'net.kyori:adventure-nbt:4.11.0' 32 | implementation 'com.grack:nanojson:1.7' 33 | 34 | implementation 'com.google.guava:guava:31.1-jre' 35 | 36 | //数据库连接池 37 | implementation 'com.zaxxer:HikariCP:5.0.1' 38 | //mysql jdbc 39 | implementation 'mysql:mysql-connector-java:8.0.30' 40 | //阿里短信api 41 | implementation 'com.aliyun:aliyun-java-sdk-core:4.6.2' 42 | 43 | } 44 | 45 | shadowJar { 46 | manifest { 47 | attributes('Main-Class': 'ru.nanit.limbo.NanoLimbo') 48 | } 49 | 50 | // minimize() //这会导致mysql没打包 51 | } 52 | 53 | test { 54 | useJUnitPlatform() 55 | } 56 | sourceCompatibility = JavaVersion.VERSION_17 57 | targetCompatibility = JavaVersion.VERSION_17 58 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaMcAlly/limboauthserver/9b55a55868d318bd3eae51241b1667a6625ff2d2/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'NanoLimbo' 2 | 3 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/ability/AbilityServer.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.ability; 2 | 3 | import cn.moonmc.ability.login.Login; 4 | import cn.moonmc.ability.chooseServer.ChooseServer; 5 | import lombok.Getter; 6 | import ru.nanit.limbo.server.LimboServer; 7 | 8 | public class AbilityServer { 9 | /** 10 | * 登录功能 11 | * */ 12 | @Getter 13 | Login login; 14 | /** 15 | * 选择服务器功能 16 | * */ 17 | @Getter 18 | ChooseServer chooseServer; 19 | @Getter 20 | private final LimboServer server; 21 | public AbilityServer(LimboServer server) { 22 | this.server = server; 23 | chooseServer = new ChooseServer(this); 24 | login = new Login(this); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/ability/chooseServer/ChooseServer.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.ability.chooseServer; 2 | 3 | import cn.moonmc.ability.AbilityServer; 4 | import cn.moonmc.ability.login.event.LoginSuccessfulEvent; 5 | import cn.moonmc.ability.login.lister.LoginState; 6 | import cn.moonmc.limboAdd.packets.out.PacketPluginMessage; 7 | import cn.moonmc.limboAdd.works.event.EventManager; 8 | import cn.moonmc.limboAdd.works.event.playerEvent.PlayerCommandEvent; 9 | import cn.moonmc.limboAdd.works.menu.BookItemNBTs; 10 | import cn.moonmc.limboAdd.works.menu.Item; 11 | import cn.moonmc.limboAdd.works.menu.ItemType; 12 | import cn.moonmc.limboAdd.works.menu.LecternInventory; 13 | import cn.moonmc.limboAdd.works.message.JsonText; 14 | import cn.moonmc.limboAdd.works.message.JsonTextParagraph; 15 | import com.google.common.io.ByteArrayDataOutput; 16 | import com.google.common.io.ByteStreams; 17 | import lombok.Getter; 18 | import ru.nanit.limbo.protocol.registry.Version; 19 | 20 | import java.io.BufferedReader; 21 | import java.io.FileNotFoundException; 22 | import java.io.IOException; 23 | import java.io.InputStream; 24 | import java.nio.file.Files; 25 | import java.nio.file.Path; 26 | import java.nio.file.Paths; 27 | import java.util.List; 28 | 29 | public class ChooseServer { 30 | String jsonText; 31 | @Getter 32 | private final AbilityServer server; 33 | public ChooseServer(AbilityServer server) { 34 | this.server = server; 35 | try { 36 | jsonText = chooseServerBook(); 37 | } catch (IOException e) { 38 | throw new RuntimeException(e); 39 | } 40 | 41 | /** 42 | * 监听玩家登录成功事件 43 | * */ 44 | EventManager.regLister(LoginSuccessfulEvent.class, event -> { 45 | Version version = event.getPlayer().getClientConnection().getClientVersion(); 46 | LecternInventory lecternInventory = new LecternInventory( 47 | new Item(event.getPlayer().getClientConnection().getClientVersion()) 48 | .setItemID(ItemType.written_book) 49 | .setItemNBTs( 50 | new BookItemNBTs(version) 51 | .setBookTitle("选择服务器") 52 | .setBookAuthor("沙盒事件视角") 53 | .setBookPages( 54 | List.of(versiona -> jsonText) 55 | ) 56 | ) 57 | ); 58 | lecternInventory.setCloseLister(event1 -> event1.getPlayer().openInventory(lecternInventory)); 59 | lecternInventory.setClickButtonLister(event1 -> { 60 | if (event1.getButtonId()==3){ 61 | event1.getPlayer().disconnect(new JsonTextParagraph("§6§l玩家自主退出服务器")); 62 | } 63 | }); 64 | event.getPlayer().openInventory(lecternInventory); 65 | 66 | }); 67 | 68 | /** 69 | * 监听玩家命令事件 70 | * */ 71 | EventManager.regLister(PlayerCommandEvent.class,event -> { 72 | LoginState loginState = event.getPlayer().getAttachments().get(LoginState.class); 73 | if (loginState==null|| !loginState.isLogined()){ 74 | return; 75 | } 76 | String[] co = event.getCommand().split(" "); 77 | if (co.length<2){ 78 | return; 79 | } 80 | if (!co[0].equals("gogo")){ 81 | return; 82 | } 83 | ByteArrayDataOutput out = ByteStreams.newDataOutput(); 84 | out.writeUTF("Connect"); 85 | out.writeUTF(co[1]); 86 | PacketPluginMessage packet = new PacketPluginMessage(); 87 | packet.setIdentifier("bungeecord:main"); 88 | packet.setBytes(out.toByteArray()); 89 | event.getPlayer().getClientConnection().sendPacket(packet); 90 | }); 91 | } 92 | 93 | 94 | private String chooseServerBook() throws IOException { 95 | String name = "chooseServerBook.json"; 96 | Path filePath = Paths.get("./", name); 97 | 98 | if (!Files.exists(filePath)) { 99 | InputStream stream = getClass().getResourceAsStream( "/" + name); 100 | 101 | if (stream == null) 102 | throw new FileNotFoundException("Cannot find settings resource file"); 103 | 104 | Files.copy(stream, filePath); 105 | } 106 | 107 | BufferedReader bufferedReader = Files.newBufferedReader(filePath); 108 | StringBuilder stringBuffer = new StringBuilder(); 109 | String i; 110 | while ((i=bufferedReader.readLine())!=null){ 111 | stringBuffer.append(i); 112 | } 113 | return stringBuffer.toString(); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/ability/chooseServer/描述.md: -------------------------------------------------------------------------------- 1 | 选择服务器功能 -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/ability/login/Login.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.ability.login; 2 | 3 | import cn.moonmc.ability.AbilityServer; 4 | import cn.moonmc.ability.login.data.UserManager; 5 | import cn.moonmc.ability.login.lister.PlayerJoin; 6 | import cn.moonmc.limboAdd.config.ConfigFile; 7 | import com.zaxxer.hikari.HikariConfig; 8 | import com.zaxxer.hikari.HikariDataSource; 9 | import lombok.Getter; 10 | import ru.nanit.limbo.server.Logger; 11 | 12 | import java.sql.SQLException; 13 | 14 | /** 15 | * 主要负责加载登录功能 16 | * */ 17 | public class Login { 18 | @Getter 19 | final AbilityServer abilityServer; 20 | @Getter 21 | HikariDataSource dataSource; 22 | @Getter 23 | UserManager userManager; 24 | @Getter 25 | PlayerJoin playerJoin; 26 | public Login(AbilityServer abilityServer){ 27 | this.abilityServer = abilityServer; 28 | try { 29 | HikariConfig config = new HikariConfig(new ConfigFile("loginDataBase.properties").getFile().toString()); 30 | dataSource = new HikariDataSource(config); 31 | } catch (Throwable e) { 32 | e.printStackTrace(); 33 | Logger.error("连接池加载失败!登录功能无法启动。"); 34 | return; 35 | } 36 | try { 37 | userManager = new UserManager(this); 38 | } catch (SQLException e) { 39 | e.printStackTrace(); 40 | Logger.error("创建表失败,无法启动"); 41 | return; 42 | } 43 | playerJoin = new PlayerJoin(this); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/ability/login/data/User.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.ability.login.data; 2 | 3 | import cn.moonmc.ability.login.data.password.HashedPassword; 4 | import cn.moonmc.ability.login.utils.HashUtils; 5 | import lombok.Data; 6 | 7 | import java.util.UUID; 8 | 9 | @Data 10 | public class User { 11 | /** 12 | * 用户uuid 13 | */ 14 | final UUID uuid; 15 | /** 16 | *用户名 17 | */ 18 | String name; 19 | /** 20 | * 密码 21 | * */ 22 | HashedPassword password; 23 | /** 24 | * 手机号 25 | * */ 26 | String phone; 27 | /** 28 | * ip地址 29 | * */ 30 | String ip; 31 | /** 32 | * 上次登录时间 33 | * */ 34 | long lastLogin; 35 | 36 | User(UUID uuid, String name, String ciphertextPassword, String phone, String ip,long lastLogin) { 37 | this.uuid = uuid; 38 | this.name = name; 39 | this.password =ciphertextPassword==null?null:new HashedPassword(ciphertextPassword); 40 | this.phone = phone; 41 | this.ip = ip; 42 | this.lastLogin = lastLogin; 43 | } 44 | 45 | public User(UUID uuid, String name, HashedPassword password, String phone, String ip,long lastLogin) { 46 | this.uuid = uuid; 47 | this.name = name; 48 | this.password = password; 49 | this.phone = phone; 50 | this.ip = ip; 51 | this.lastLogin = lastLogin; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/ability/login/data/bookpage/Paragraph.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.ability.login.data.bookpage; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | /** 6 | * @author CNLuminous 2022/11/28 7 | * Json: {"text":"§6§l同意服规,前往注册\n","hoverEvent":{"text":"点击即认为您同意以上服务器条例,\n并且同意遵守服务器规则"},"clickEvent":{"page":6,"url":"https:","command":"/quit"}} 8 | * 9 | */ 10 | public class Paragraph { 11 | 12 | @SerializedName("text") 13 | private String text; 14 | @SerializedName("hoverEvent") 15 | private HoverEventDTO hoverEvent; 16 | @SerializedName("clickEvent") 17 | private ClickEventDTO clickEvent; 18 | 19 | public String getText() { 20 | return text; 21 | } 22 | 23 | public void setText(String text) { 24 | this.text = text; 25 | } 26 | 27 | public HoverEventDTO getHoverEvent() { 28 | return hoverEvent; 29 | } 30 | 31 | public void setHoverEvent(HoverEventDTO hoverEvent) { 32 | this.hoverEvent = hoverEvent; 33 | } 34 | 35 | public ClickEventDTO getClickEvent() { 36 | return clickEvent; 37 | } 38 | 39 | public void setClickEvent(ClickEventDTO clickEvent) { 40 | this.clickEvent = clickEvent; 41 | } 42 | 43 | public static class HoverEventDTO { 44 | @SerializedName("text") 45 | private String text; 46 | 47 | public String getText() { 48 | return text; 49 | } 50 | 51 | public void setText(String text) { 52 | this.text = text; 53 | } 54 | } 55 | 56 | public static class ClickEventDTO { 57 | @SerializedName("page") 58 | private Integer page; 59 | @SerializedName("url") 60 | private String url; 61 | @SerializedName("command") 62 | private String command; 63 | 64 | public Integer getPage() { 65 | return page; 66 | } 67 | 68 | public void setPage(Integer page) { 69 | this.page = page; 70 | } 71 | 72 | public String getUrl() { 73 | return url; 74 | } 75 | 76 | public void setUrl(String url) { 77 | this.url = url; 78 | } 79 | 80 | public String getCommand() { 81 | return command; 82 | } 83 | 84 | public void setCommand(String command) { 85 | this.command = command; 86 | } 87 | 88 | @Override 89 | public String toString() { 90 | return "ClickEventDTO{" + 91 | "page=" + page + 92 | ", url='" + url + '\'' + 93 | ", command='" + command + '\'' + 94 | '}'; 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/ability/login/data/password/EncryptionMethod.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.ability.login.data.password; 2 | 3 | /** 4 | * 直接复制的authme的awa 5 | * Public interface for custom password encryption methods. 6 | *

7 | * Instantiation of these methods is done via automatic dependency injection. 8 | */ 9 | public interface EncryptionMethod { 10 | 11 | /** 12 | * Hash the given password for the given player name. 13 | * 14 | * @param password The password to hash 15 | * 16 | * @return The hash result for the password. 17 | * @see HashedPassword 18 | */ 19 | HashedPassword computeHash(String password); 20 | 21 | /** 22 | * 使用给定玩家的给定盐对给定密码进行哈希处理。 23 | * Hash the given password with the given salt for the given player. 24 | * 25 | * @param password The password to hash 26 | * @param salt The salt to add to the hash 27 | * 28 | * @return The hashed password 29 | * @see #hasSeparateSalt() 30 | */ 31 | String computeHash(String password, String salt); 32 | 33 | /** 34 | * 检查给定的哈希是否与明文密码匹配。 35 | * Check whether the given hash matches the clear-text password. 36 | * 37 | * @param password The clear-text password to verify 38 | * @param hashedPassword The hash to check the password against 39 | * 40 | * @return True if the password matches, false otherwise 41 | */ 42 | boolean comparePassword(String password, HashedPassword hashedPassword); 43 | 44 | /** 45 | * 生成一个新的盐来散列密码 46 | * Generate a new salt to hash a password with. 47 | * 48 | * @return The generated salt, null if the method does not use a random text-based salt 49 | */ 50 | String generateSalt(); 51 | 52 | /** 53 | * Return whether the encryption method requires the salt to be stored separately and 54 | * passed again to {@link #comparePassword(String, HashedPassword)}. Note that 55 | * an encryption method returning {@code false} does not imply that it uses no salt; it 56 | * may be embedded into the hash or it may use the username as salt. 57 | * 58 | * @return True if the salt has to be stored and retrieved separately, false otherwise 59 | */ 60 | boolean hasSeparateSalt(); 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/ability/login/data/password/HashedPassword.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.ability.login.data.password; 2 | 3 | /** 4 | * 直接复制的authme的awa 5 | * The result of a hash computation. See {@link } for details. 6 | */ 7 | public class HashedPassword { 8 | 9 | /** The generated hash. */ 10 | private final String hash; 11 | 12 | /** 13 | * Constructor. 14 | * 15 | * @param hash The computed hash 16 | */ 17 | public HashedPassword(String hash) { 18 | this.hash = hash; 19 | } 20 | 21 | public String getHash() { 22 | return hash; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/ability/login/data/password/HexSaltedMethod.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.ability.login.data.password; 2 | 3 | import cn.moonmc.ability.login.utils.RandomStringUtils; 4 | 5 | /** 6 | * 直接复制的authme的awa 7 | * Common type for encryption methods which use a random String of hexadecimal characters 8 | * and store the salt with the hash itself. 9 | */ 10 | public abstract class HexSaltedMethod implements EncryptionMethod { 11 | 12 | public abstract int getSaltLength(); 13 | 14 | @Override 15 | public abstract String computeHash(String password, String salt); 16 | 17 | @Override 18 | public HashedPassword computeHash(String password) { 19 | String salt = generateSalt(); 20 | return new HashedPassword(computeHash(password, salt)); 21 | } 22 | 23 | @Override 24 | public abstract boolean comparePassword(String password, HashedPassword hashedPassword); 25 | 26 | @Override 27 | public String generateSalt() { 28 | return RandomStringUtils.generateHex(getSaltLength()); 29 | } 30 | 31 | @Override 32 | public boolean hasSeparateSalt() { 33 | return false; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/ability/login/data/password/Sha256.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.ability.login.data.password; 2 | 3 | import static cn.moonmc.ability.login.utils.HashUtils.isEqual; 4 | import static cn.moonmc.ability.login.utils.HashUtils.sha256; 5 | /** 6 | * 直接复制的authme的awa 7 | * */ 8 | public class Sha256 extends HexSaltedMethod { 9 | 10 | @Override 11 | public String computeHash(String password, String salt) { 12 | return "$SHA$" + salt + "$" + sha256(sha256(password) + salt); 13 | } 14 | 15 | @Override 16 | public boolean comparePassword(String password, HashedPassword hashedPassword) { 17 | String hash = hashedPassword.getHash(); 18 | String[] line = hash.split("\\$"); 19 | return line.length == 4 && isEqual(hash, computeHash(password, line[2])); 20 | } 21 | 22 | @Override 23 | public int getSaltLength() { 24 | return 16; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/ability/login/event/LoginSuccessfulEvent.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.ability.login.event; 2 | 3 | import cn.moonmc.limboAdd.works.entity.Player; 4 | import cn.moonmc.limboAdd.works.event.Event; 5 | import lombok.Getter; 6 | 7 | /** 8 | * 登录成功事件 9 | * */ 10 | public class LoginSuccessfulEvent implements Event { 11 | @Getter 12 | final Player player; 13 | 14 | public LoginSuccessfulEvent(Player player) { 15 | this.player = player; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/ability/login/lister/LoginState.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.ability.login.lister; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | import java.util.UUID; 7 | 8 | public class LoginState { 9 | @Getter 10 | String quitCmd = UUID.randomUUID().toString(); 11 | @Getter 12 | String regCmd = UUID.randomUUID().toString(); 13 | 14 | /** 15 | * 是否已登录 16 | * */ 17 | @Getter @Setter 18 | boolean logined = false; 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/ability/login/utils/RandomStringUtils.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.ability.login.utils; 2 | 3 | import java.security.SecureRandom; 4 | import java.util.Random; 5 | 6 | /** 7 | * 直接复制的authme的awa 8 | * Utility for generating random strings. 9 | */ 10 | public final class RandomStringUtils { 11 | 12 | private static final char[] CHARS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray(); 13 | private static final Random RANDOM = new SecureRandom(); 14 | private static final int NUM_INDEX = 10; 15 | private static final int LOWER_ALPHANUMERIC_INDEX = 36; 16 | private static final int HEX_MAX_INDEX = 16; 17 | 18 | // Utility class 19 | private RandomStringUtils() { 20 | } 21 | 22 | /** 23 | * Generate a string of the given length consisting of random characters within the range [0-9a-z]. 24 | * 25 | * @param length The length of the random string to generate 26 | * @return The random string 27 | */ 28 | public static String generate(int length) { 29 | return generateString(length, LOWER_ALPHANUMERIC_INDEX); 30 | } 31 | 32 | /** 33 | * Generate a random hexadecimal string of the given length. In other words, the generated string 34 | * contains characters only within the range [0-9a-f]. 35 | * 36 | * @param length The length of the random string to generate 37 | * @return The random hexadecimal string 38 | */ 39 | public static String generateHex(int length) { 40 | return generateString(length, HEX_MAX_INDEX); 41 | } 42 | 43 | /** 44 | * Generate a random numbers string of the given length. In other words, the generated string 45 | * contains characters only within the range [0-9]. 46 | * 47 | * @param length The length of the random string to generate 48 | * @return The random numbers string 49 | */ 50 | public static String generateNum(int length) { 51 | return generateString(length, NUM_INDEX); 52 | } 53 | 54 | /** 55 | * Generate a random string with digits and lowercase and uppercase letters. The result of this 56 | * method matches the pattern [0-9a-zA-Z]. 57 | * 58 | * @param length The length of the random string to generate 59 | * @return The random string 60 | */ 61 | public static String generateLowerUpper(int length) { 62 | return generateString(length, CHARS.length); 63 | } 64 | 65 | private static String generateString(int length, int maxIndex) { 66 | if (length < 0) { 67 | throw new IllegalArgumentException("Length must be positive but was " + length); 68 | } 69 | StringBuilder sb = new StringBuilder(length); 70 | for (int i = 0; i < length; ++i) { 71 | sb.append(CHARS[RANDOM.nextInt(maxIndex)]); 72 | } 73 | return sb.toString(); 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/ability/login/utils/SMSCodeUtils.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.ability.login.utils; 2 | 3 | import com.aliyuncs.CommonRequest; 4 | import com.aliyuncs.CommonResponse; 5 | import com.aliyuncs.DefaultAcsClient; 6 | import com.aliyuncs.http.MethodType; 7 | import com.aliyuncs.profile.DefaultProfile; 8 | import com.grack.nanojson.JsonWriter; 9 | import ru.nanit.limbo.configuration.LimboConfig; 10 | import ru.nanit.limbo.server.LimboServer; 11 | import ru.nanit.limbo.server.Logger; 12 | 13 | import java.util.Map; 14 | 15 | /** 16 | * 短信验证码工具,暂时先写死吧,反正也不会改awa 17 | * */ 18 | public class SMSCodeUtils { 19 | private static LimboConfig config = LimboServer.getInstance().getConfig(); 20 | static final String ak = config.getAli_ak(); 21 | static final String sk = config.getAli_sk(); 22 | static final String sign = config.getAli_sign(); 23 | static final String template_bind = config.getAli_template_bind(); 24 | static final String template_resetPassword = config.getAli_template_resetPassword(); 25 | static DefaultAcsClient aliClient = new DefaultAcsClient(DefaultProfile.getProfile("cn-shenzhen",ak, sk)); 26 | 27 | 28 | /** 29 | * 会阻塞线程哦,在新线程调用哦 30 | * */ 31 | public static void sendMessage(String code, Long phone, Type templateType) { 32 | CommonRequest request = new CommonRequest(); 33 | request.setSysMethod(MethodType.POST); 34 | request.setSysDomain("dysmsapi.aliyuncs.com"); 35 | request.setSysVersion("2017-05-25"); 36 | request.setSysAction("SendSms"); 37 | request.putQueryParameter("PhoneNumbers", String.valueOf(phone)); 38 | request.putQueryParameter("SignName", sign); 39 | switch (templateType){ 40 | case bind -> request.putQueryParameter("TemplateCode", template_bind); 41 | case resetpwd -> request.putQueryParameter("TemplateCode", template_resetPassword); 42 | } 43 | request.putQueryParameter("TemplateParam", JsonWriter.string(Map.of("code", code))); 44 | try { 45 | CommonResponse response = aliClient.getCommonResponse(request); 46 | Logger.info("Phone=" + phone + ";template=" + templateType + ";code=" + code + " 's req result => " + response.getData()); 47 | } catch (Exception ignored) { 48 | } 49 | } 50 | 51 | public enum Type { 52 | bind,resetpwd 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/ability/notify/ServerEula.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.ability.notify; 2 | 3 | import cn.moonmc.ability.login.data.bookpage.Paragraph; 4 | import cn.moonmc.ability.login.lister.LoginState; 5 | import cn.moonmc.limboAdd.works.entity.Player; 6 | import cn.moonmc.limboAdd.works.message.*; 7 | import com.google.gson.Gson; 8 | import com.google.gson.JsonArray; 9 | import com.google.gson.JsonElement; 10 | import com.google.gson.JsonObject; 11 | import lombok.Getter; 12 | 13 | import java.io.BufferedReader; 14 | import java.io.FileNotFoundException; 15 | import java.io.IOException; 16 | import java.io.InputStream; 17 | import java.nio.file.Files; 18 | import java.nio.file.Path; 19 | import java.nio.file.Paths; 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | 23 | /** 24 | * @author CNLuminous 2022/11/28 25 | */ 26 | public class ServerEula { 27 | @Getter 28 | String eula; 29 | 30 | public ServerEula() { 31 | try { 32 | eula = serverEula(); 33 | } catch (IOException e) { 34 | throw new RuntimeException(e); 35 | } 36 | } 37 | private String serverEula() throws IOException { 38 | String name = "ServerEula.json"; 39 | Path filePath = Paths.get("./", name); 40 | 41 | if (!Files.exists(filePath)) { 42 | InputStream stream = getClass().getResourceAsStream( "/" + name); 43 | 44 | if (stream == null) { 45 | throw new FileNotFoundException("Cannot find settings resource file"); 46 | } 47 | 48 | Files.copy(stream, filePath); 49 | } 50 | 51 | BufferedReader bufferedReader = Files.newBufferedReader(filePath); 52 | StringBuilder stringBuffer = new StringBuilder(); 53 | String i; 54 | while ((i=bufferedReader.readLine())!=null){ 55 | stringBuffer.append(i); 56 | } 57 | 58 | return stringBuffer.toString(); 59 | } 60 | public static List buildEula(String eula, Player player){ 61 | Gson gson = new Gson(); 62 | List result = new ArrayList<>(); 63 | eula = eula.replace("{quit_command}","/"+player.getAttachments().get(LoginState.class).getQuitCmd()); 64 | eula = eula.replace("{reg_command}","/"+player.getAttachments().get(LoginState.class).getRegCmd()); 65 | JsonArray jsonArray = gson.fromJson(eula, JsonArray.class); 66 | for (JsonElement json : jsonArray){ 67 | JsonTextArticle jsonTextArticle = new JsonTextArticle(new JsonTextParagraph("")); 68 | JsonObject object = (JsonObject) json; 69 | JsonArray array = (JsonArray) object.get("paragraphs"); 70 | for (Object obj: array){ 71 | Paragraph paragraph = gson.fromJson(String.valueOf(obj),Paragraph.class); 72 | JsonTextParagraph jsonTextParagraph = new JsonTextParagraph(paragraph.getText()); 73 | if (paragraph.getHoverEvent()!=null){ 74 | jsonTextParagraph.setHoverEvent(new HoverEventShowText(paragraph.getHoverEvent().getText())); 75 | } 76 | if (paragraph.getClickEvent()!=null){ 77 | if (paragraph.getClickEvent().getCommand()!=null){ 78 | jsonTextParagraph.setClickEvent(new ClickEventRunCommand(paragraph.getClickEvent().getCommand())); 79 | } 80 | if (paragraph.getClickEvent().getUrl()!=null){ 81 | jsonTextParagraph.setClickEvent(new ClickEventoOpenUrl(paragraph.getClickEvent().getUrl())); 82 | } 83 | if (paragraph.getClickEvent().getPage()!=null){ 84 | jsonTextParagraph.setClickEvent(new ClickEventChangePage(paragraph.getClickEvent().getPage())); 85 | } 86 | } 87 | jsonTextArticle.addParagraph(jsonTextParagraph); 88 | } 89 | result.add(jsonTextArticle); 90 | } 91 | 92 | return result; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/ability/描述.md: -------------------------------------------------------------------------------- 1 | ability包下,像插件一样吧,每个包一个功能。比如login包就是登录功能。 -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/AddServer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package cn.moonmc.limboAdd; 19 | 20 | import cn.moonmc.ability.AbilityServer; 21 | import cn.moonmc.limboAdd.works.menu.InventoryManager; 22 | import lombok.Getter; 23 | import ru.nanit.limbo.server.LimboServer; 24 | public final class AddServer { 25 | @Getter 26 | LimboServer server; 27 | @Getter 28 | InventoryManager inventoryManager; 29 | public AddServer(LimboServer server) { 30 | this.server = server; 31 | this.inventoryManager = new InventoryManager(this); 32 | new AbilityServer(server); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/config/ConfigFile.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.config; 2 | 3 | import java.io.*; 4 | import java.nio.file.Files; 5 | import java.nio.file.Path; 6 | import java.nio.file.Paths; 7 | 8 | public class ConfigFile { 9 | private final String fillName; 10 | 11 | public ConfigFile(String fillName) { 12 | this.fillName = fillName; 13 | } 14 | 15 | /** 16 | * 获取配置文件读取流 17 | * 如果配置文件不存在则会从资源文件中复制出来。 18 | * */ 19 | public BufferedReader getReader() throws IOException { 20 | Path filePath = Paths.get("./", fillName); 21 | 22 | 23 | if (!Files.exists(filePath)) { 24 | InputStream stream = getClass().getResourceAsStream( "/" + fillName); 25 | 26 | if (stream == null) 27 | throw new FileNotFoundException("在资源文件中没有找到"+fillName); 28 | 29 | Files.copy(stream, filePath); 30 | } 31 | 32 | return Files.newBufferedReader(filePath); 33 | } 34 | 35 | public File getFile() throws IOException { 36 | Path filePath = Paths.get("./", fillName); 37 | 38 | 39 | if (!Files.exists(filePath)) { 40 | InputStream stream = getClass().getResourceAsStream( "/" + fillName); 41 | 42 | if (stream == null) 43 | throw new FileNotFoundException("在资源文件中没有找到"+fillName); 44 | 45 | Files.copy(stream, filePath); 46 | } 47 | 48 | return filePath.toFile(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/packets/PackReg.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.packets; 2 | 3 | 4 | import cn.moonmc.limboAdd.packets.in.*; 5 | import cn.moonmc.limboAdd.packets.out.*; 6 | import ru.nanit.limbo.protocol.registry.State; 7 | import ru.nanit.limbo.protocol.registry.Version; 8 | 9 | import static ru.nanit.limbo.protocol.registry.Version.*; 10 | 11 | /** 12 | * 包注册类 13 | * @author jja8 CNLuminous 14 | * */ 15 | public class PackReg { 16 | public static void reg(State.ProtocolMappings serverBound, State.ProtocolMappings clientBound) { 17 | //聊天消息包 18 | serverBound.register(PacketPlayerChatMessage::new, 19 | new State.Mapping(0x05,V1_19,V1_19_1), 20 | new State.Mapping(0x03,V1_18,V1_18_2) 21 | ); 22 | //玩家命令包 1.19+ 23 | serverBound.register(PacketPlayerCommand::new, 24 | new State.Mapping(0x04,V1_19,V1_19_1)); 25 | 26 | serverBound.register(PacketClickButtonContainer::new, 27 | new State.Mapping(0x0A,V1_19,V1_19_1), 28 | new State.Mapping(0x07,V1_18,V1_18_2) 29 | ); 30 | //打开窗口包 31 | clientBound.register(PacketOpenMenu::new, 32 | new State.Mapping(0x2D,V1_19,V1_19_1), 33 | new State.Mapping(0x2E,V1_18,V1_18_2)); 34 | clientBound.register(PacketSetContainerSlot::new, 35 | new State.Mapping(0x13,V1_19,V1_19_1), 36 | new State.Mapping(0x16,V1_18,V1_18_2)); 37 | clientBound.register(PacketSetContainerProperty::new, 38 | new State.Mapping(0x12,V1_19,V1_19_1), 39 | new State.Mapping(0x15,V1_18,V1_18_2)); 40 | 41 | serverBound.register(PacketRenameItem::new, 42 | new State.Mapping(0x23,V1_19,V1_19_1), 43 | new State.Mapping(0x20,V1_18,V1_18_2)); 44 | clientBound.register(PlayDisconnect::new, 45 | new State.Mapping(0x19,V1_19,V1_19_1), 46 | new State.Mapping(0x1A,V1_18,V1_18_2) 47 | ); 48 | //关闭window包 49 | clientBound.register(PlayerCloveInventory::new, 50 | new State.Mapping(0x10,V1_19,V1_19_1), 51 | new State.Mapping(0x13,V1_18,V1_18_2) 52 | ); 53 | //打开主手上的书 54 | clientBound.register(PacketOpenBook::new, 55 | new State.Mapping(0x2C,V1_19,V1_19_1), 56 | new State.Mapping(0x2D,V1_18,V1_18_2) 57 | ); 58 | //设置玩家物品栏指向 59 | clientBound.register(PacketSetHeldItem::new, 60 | new State.Mapping(0x4A,V1_19,V1_19_1), 61 | new State.Mapping(0x48,V1_18,V1_18_2) 62 | ); 63 | //客户端关闭容器 64 | serverBound.register(PacketCloseContainer::new, 65 | new State.Mapping(0x0C,V1_19,V1_19_1), 66 | new State.Mapping(0x09,V1_18,V1_18_2)); 67 | 68 | serverBound.register(PacketClickContainer::new, 69 | new State.Mapping(0x0B,V1_19,V1_19_1), 70 | new State.Mapping(0x08,V1_18,V1_18_2)); 71 | 72 | 73 | clientBound.register(PacketPluginMessage::new, 74 | new State.Mapping(0x16,V1_19,V1_19_1), 75 | new State.Mapping(0x18,V1_18,V1_18_2) 76 | ); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/packets/in/PacketClickButtonContainer.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.packets.in; 2 | 3 | import cn.moonmc.limboAdd.works.event.EventManager; 4 | import cn.moonmc.limboAdd.works.event.playerEvent.PlayerClickButtonContainer; 5 | import cn.moonmc.limboAdd.works.message.ClickEventChangePage; 6 | import ru.nanit.limbo.connection.ClientConnection; 7 | import ru.nanit.limbo.protocol.ByteMessage; 8 | import ru.nanit.limbo.protocol.PacketIn; 9 | import ru.nanit.limbo.protocol.registry.Version; 10 | import ru.nanit.limbo.server.LimboServer; 11 | 12 | /** 13 | * @author CNLuminous 2022/10/26 14 | */ 15 | public class PacketClickButtonContainer implements PacketIn { 16 | Integer windowId; 17 | Integer buttonId; 18 | Integer nowPage; 19 | @Override 20 | public void decode(ByteMessage msg, Version version) { 21 | windowId = msg.readVarInt(); 22 | buttonId = msg.readVarInt(); 23 | 24 | } 25 | 26 | @Override 27 | public void handle(ClientConnection conn, LimboServer server) { 28 | EventManager.call(new PlayerClickButtonContainer(conn.getPlayer(),buttonId,windowId)); 29 | } 30 | 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/packets/in/PacketClickContainer.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.packets.in; 2 | 3 | import cn.moonmc.limboAdd.works.event.EventManager; 4 | import cn.moonmc.limboAdd.works.event.playerEvent.PlayerClickContainer; 5 | import ru.nanit.limbo.connection.ClientConnection; 6 | import ru.nanit.limbo.protocol.ByteMessage; 7 | import ru.nanit.limbo.protocol.PacketIn; 8 | import ru.nanit.limbo.protocol.registry.Version; 9 | import ru.nanit.limbo.server.LimboServer; 10 | 11 | /** 12 | * 玩家点击物品栏包 https://wiki.vg/Protocol#Click_Container_Button 13 | * */ 14 | public class PacketClickContainer implements PacketIn { 15 | /** 16 | * windowID 17 | * */ 18 | int windowID; 19 | /** 20 | * 目前来说没什么用 21 | * */ 22 | int stateID; 23 | 24 | /** 25 | * 被点击的格子 26 | * */ 27 | short slot; 28 | 29 | /** 30 | * 点击的模式 31 | * */ 32 | int mode; 33 | /** 34 | * 点击的按键 35 | * */ 36 | int button; 37 | 38 | 39 | 40 | @Override 41 | public void decode(ByteMessage msg, Version version) { 42 | windowID = Byte.toUnsignedInt(msg.readByte()); 43 | stateID= msg.readVarInt(); 44 | slot = msg.readShort(); 45 | mode = msg.readVarInt(); 46 | button = msg.readVarInt(); 47 | 48 | //还有数据懒得读了,反正也没用 49 | } 50 | 51 | @Override 52 | public void handle(ClientConnection conn, LimboServer server) { 53 | EventManager.call(new PlayerClickContainer(conn.getPlayer(),slot,windowID)); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/packets/in/PacketCloseContainer.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.packets.in; 2 | 3 | import cn.moonmc.limboAdd.works.event.EventManager; 4 | import cn.moonmc.limboAdd.works.event.playerEvent.PlayerCloseContainer; 5 | import ru.nanit.limbo.connection.ClientConnection; 6 | import ru.nanit.limbo.protocol.ByteMessage; 7 | import ru.nanit.limbo.protocol.PacketIn; 8 | import ru.nanit.limbo.protocol.registry.Version; 9 | import ru.nanit.limbo.server.LimboServer; 10 | 11 | /** 12 | * 关闭容器包 13 | * @author jja8 14 | * */ 15 | public class PacketCloseContainer implements PacketIn { 16 | 17 | int windowID; 18 | 19 | @Override 20 | public void decode(ByteMessage msg, Version version) { 21 | windowID = Byte.toUnsignedInt(msg.readByte()); 22 | } 23 | 24 | @Override 25 | public void handle(ClientConnection conn, LimboServer server) { 26 | EventManager.call(new PlayerCloseContainer(conn.getPlayer(),windowID)); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/packets/in/PacketPlayerChatMessage.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.packets.in; 2 | 3 | import cn.moonmc.limboAdd.works.event.EventManager; 4 | import cn.moonmc.limboAdd.works.event.playerEvent.PlayerChatEvent; 5 | import cn.moonmc.limboAdd.works.event.playerEvent.PlayerCommandEvent; 6 | import ru.nanit.limbo.connection.ClientConnection; 7 | import ru.nanit.limbo.protocol.ByteMessage; 8 | import ru.nanit.limbo.protocol.PacketIn; 9 | import ru.nanit.limbo.protocol.registry.Version; 10 | import ru.nanit.limbo.server.LimboServer; 11 | 12 | /** 13 | * 接受玩家聊天包 14 | * @author jja8 15 | * */ 16 | public class PacketPlayerChatMessage implements PacketIn { 17 | String cat; 18 | boolean command = false; 19 | 20 | @Override 21 | public void decode(ByteMessage msg, Version version) { 22 | cat = msg.readString(); 23 | if (version.lessOrEqual(Version.V1_18_2)) { 24 | if (cat.startsWith("/")) { 25 | command = true; 26 | cat = cat.substring(1); 27 | } 28 | } 29 | } 30 | 31 | @Override 32 | public void handle(ClientConnection conn, LimboServer server) { 33 | if (command){ 34 | EventManager.call(new PlayerCommandEvent(conn.getPlayer(),cat)); 35 | }else { 36 | EventManager.call(new PlayerChatEvent(conn.getPlayer(),cat)); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/packets/in/PacketPlayerCommand.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.packets.in; 2 | 3 | import cn.moonmc.limboAdd.works.event.EventManager; 4 | import cn.moonmc.limboAdd.works.event.playerEvent.PlayerCommandEvent; 5 | import ru.nanit.limbo.connection.ClientConnection; 6 | import ru.nanit.limbo.protocol.ByteMessage; 7 | import ru.nanit.limbo.protocol.PacketIn; 8 | import ru.nanit.limbo.protocol.registry.Version; 9 | import ru.nanit.limbo.server.LimboServer; 10 | 11 | /** 12 | * 接收玩家命令包 13 | * @author jja8 14 | * */ 15 | public class PacketPlayerCommand implements PacketIn { 16 | String command; 17 | 18 | @Override 19 | public void decode(ByteMessage msg, Version version) { 20 | command = msg.readString(); 21 | } 22 | 23 | @Override 24 | public void handle(ClientConnection conn, LimboServer server) { 25 | EventManager.call(new PlayerCommandEvent(conn.getPlayer(),command)); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/packets/in/PacketRenameItem.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.packets.in; 2 | 3 | import cn.moonmc.limboAdd.works.event.EventManager; 4 | import cn.moonmc.limboAdd.works.event.playerEvent.PlayerRenameItem; 5 | import ru.nanit.limbo.connection.ClientConnection; 6 | import ru.nanit.limbo.protocol.ByteMessage; 7 | import ru.nanit.limbo.protocol.PacketIn; 8 | import ru.nanit.limbo.protocol.registry.Version; 9 | import ru.nanit.limbo.server.LimboServer; 10 | 11 | /** 12 | * 物品重命名包,铁砧每次修改物品名称都会发送给服务器 13 | * @author jja8 14 | * */ 15 | public class PacketRenameItem implements PacketIn { 16 | String name; 17 | 18 | @Override 19 | public void decode(ByteMessage msg, Version version) { 20 | name = msg.readString(); 21 | } 22 | 23 | @Override 24 | public void handle(ClientConnection conn, LimboServer server) { 25 | EventManager.call(new PlayerRenameItem(conn.getPlayer(),name)); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/packets/out/PacketOpenBook.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.packets.out; 2 | 3 | import ru.nanit.limbo.protocol.ByteMessage; 4 | import ru.nanit.limbo.protocol.PacketOut; 5 | import ru.nanit.limbo.protocol.registry.Version; 6 | 7 | /** 8 | * @author CNLuminous 2022/10/23 9 | */ 10 | public class PacketOpenBook implements PacketOut { 11 | @Override 12 | public void encode(ByteMessage msg, Version version) { 13 | msg.writeVarInt(0); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/packets/out/PacketOpenMenu.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.packets.out; 2 | 3 | import cn.moonmc.limboAdd.works.message.JsonText; 4 | import cn.moonmc.limboAdd.works.message.JsonTextParagraph; 5 | import lombok.Data; 6 | import ru.nanit.limbo.protocol.ByteMessage; 7 | import ru.nanit.limbo.protocol.PacketOut; 8 | import ru.nanit.limbo.protocol.registry.Version; 9 | 10 | /** 11 | * 打开界面包 https://wiki.vg/Protocol#Open_Screen 12 | * @author jja8 13 | * */ 14 | @Data 15 | public class PacketOpenMenu implements PacketOut { 16 | /** 17 | * 每个windowID都不能相同,如果相同会认为是同一个window 18 | * */ 19 | int windowID = 56; 20 | 21 | /** 22 | * window类型 23 | * */ 24 | int windowsTypeID = WindowsType.generic_9x3.ID; 25 | 26 | /** 27 | * window标题 28 | * */ 29 | JsonText title = new JsonTextParagraph("null"); 30 | 31 | /** 32 | * 格子数量 33 | * */ 34 | int slots = 0; //格子数量 35 | 36 | public void setWindowsType(WindowsType windowsType){ 37 | windowsTypeID=windowsType.ID; 38 | } 39 | 40 | @Override 41 | public void encode(ByteMessage msg, Version version) { 42 | msg.writeVarInt(windowID); 43 | msg.writeVarInt(windowsTypeID); 44 | msg.writeString(title.toJsonText(version)); 45 | } 46 | 47 | 48 | public enum WindowsType{ 49 | //参考 https://wiki.vg/Inventory 50 | 51 | generic_9x1(0), 52 | generic_9x2(1), 53 | generic_9x3(2), 54 | generic_9x4(3), 55 | generic_9x5(4), 56 | generic_9x6(5), 57 | generic_3x3(6), 58 | anvil(7), 59 | beacon(8), 60 | blast_furnace(9), 61 | brewing_stand(10), 62 | crafting(11), 63 | enchantment(12), 64 | furnace(13), 65 | grindstone(14), 66 | hopper(15), 67 | lectern(16), 68 | loom(17), 69 | merchant(18), 70 | shulker_box(19), 71 | smithing(20), 72 | smoker(21), 73 | cartography(22), 74 | stonecutter(23); 75 | final int ID; 76 | WindowsType(int s) { 77 | this.ID=s; 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/packets/out/PacketPluginMessage.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.packets.out; 2 | 3 | import io.netty.buffer.Unpooled; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | import ru.nanit.limbo.protocol.ByteMessage; 7 | import ru.nanit.limbo.protocol.PacketOut; 8 | import ru.nanit.limbo.protocol.registry.Version; 9 | 10 | /** 11 | * 插件消息包 12 | * */ 13 | public class PacketPluginMessage implements PacketOut { 14 | 15 | /** 16 | * 数据包标示 17 | * */ 18 | @Getter @Setter 19 | String identifier; 20 | 21 | /** 22 | * 数据 23 | * */ 24 | @Getter @Setter 25 | byte[] bytes; 26 | 27 | 28 | @Override 29 | public void encode(ByteMessage msg, Version version) { 30 | msg.writeString(identifier); 31 | msg.writeBytes(Unpooled.wrappedBuffer(bytes)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/packets/out/PacketSetContainerProperty.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.packets.out; 2 | 3 | import lombok.Data; 4 | import ru.nanit.limbo.protocol.ByteMessage; 5 | import ru.nanit.limbo.protocol.PacketOut; 6 | import ru.nanit.limbo.protocol.registry.Version; 7 | 8 | /** 9 | * 更新属性包 https://wiki.vg/Protocol#Set_Container_Property 10 | * @author jja8 11 | * */ 12 | @Data 13 | public class PacketSetContainerProperty implements PacketOut { 14 | 15 | /** 16 | * 要设置的窗口id -1设置玩家鼠标 -2设置玩家背包 其他窗口使用PacketOpenWindow的id 17 | * */ 18 | int windowID = 56; 19 | 20 | /** 21 | * 设置项目 22 | * */ 23 | short property = 0; 24 | 25 | /** 26 | * 设置值 27 | * */ 28 | short value = 0; 29 | 30 | 31 | @Override 32 | public void encode(ByteMessage msg, Version version) { 33 | msg.writeByte(windowID); 34 | msg.writeShort(property); 35 | msg.writeShort(value); 36 | 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/packets/out/PacketSetContainerSlot.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.packets.out; 2 | 3 | import cn.moonmc.limboAdd.works.menu.Slot; 4 | import lombok.Data; 5 | import ru.nanit.limbo.protocol.ByteMessage; 6 | import ru.nanit.limbo.protocol.PacketOut; 7 | import ru.nanit.limbo.protocol.registry.Version; 8 | 9 | /** 10 | * 设置物品栏内容包 https://wiki.vg/Protocol#Set_Container_Slot 11 | * @author jja8 12 | * */ 13 | @Data 14 | public class PacketSetContainerSlot implements PacketOut { 15 | 16 | /** 17 | * 要设置的窗口id -1设置玩家鼠标 -2设置玩家背包 其他窗口使用PacketOpenWindow的id 18 | * */ 19 | int windowID = 56; 20 | 21 | /** 22 | * 设置要更新的格子 23 | * */ 24 | short slotID = 0; 25 | 26 | /** 27 | * 目前来说没什么用 28 | * */ 29 | int stateID = 0; 30 | 31 | /** 32 | * 设置格子内容 33 | * */ 34 | Slot slot = new Slot(); 35 | 36 | @Override 37 | public void encode(ByteMessage msg, Version version) { 38 | msg.writeByte(windowID); 39 | msg.writeVarInt(stateID); 40 | msg.writeShort(slotID); 41 | 42 | //物品 43 | msg.writeBoolean(slot.isHasItem()); 44 | msg.writeVarInt(slot.getItemType().getItemTypeNetID(version)); 45 | msg.writeByte(slot.getCount()); 46 | msg.writeCompoundTag(slot.getNbt()); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/packets/out/PacketSetHeldItem.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.packets.out; 2 | 3 | import ru.nanit.limbo.protocol.ByteMessage; 4 | import ru.nanit.limbo.protocol.PacketOut; 5 | import ru.nanit.limbo.protocol.registry.Version; 6 | 7 | /** 8 | * 设置玩家指向物品栏的物品包 https://wiki.vg/Protocol#Set_Held_Item_.28serverbound.29 9 | * @author CNLuminous 2022/10/23 10 | */ 11 | public class PacketSetHeldItem implements PacketOut { 12 | 13 | /** 14 | * 设置玩家指向物品栏的物品 0-8 15 | */ 16 | private byte slot; 17 | 18 | public PacketSetHeldItem(byte slot) { 19 | this.slot = slot; 20 | } 21 | 22 | public PacketSetHeldItem() { 23 | this.slot = 0; 24 | } 25 | 26 | @Override 27 | public void encode(ByteMessage msg, Version version) { 28 | msg.writeVarInt(slot); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/packets/out/PlayDisconnect.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.packets.out; 2 | 3 | import cn.moonmc.limboAdd.works.message.JsonText; 4 | import cn.moonmc.limboAdd.works.message.JsonTextParagraph; 5 | import ru.nanit.limbo.protocol.ByteMessage; 6 | import ru.nanit.limbo.protocol.PacketOut; 7 | import ru.nanit.limbo.protocol.registry.Version; 8 | 9 | /** 10 | * 玩家在游戏中踢出服务器数据包 11 | * @author CNLuminous 12 | */ 13 | public class PlayDisconnect implements PacketOut { 14 | private final JsonText reason; 15 | public PlayDisconnect(JsonText reason) { 16 | this.reason = reason; 17 | } 18 | public PlayDisconnect(){ 19 | reason = new JsonTextParagraph("null"); 20 | } 21 | 22 | @Override 23 | public void encode(ByteMessage msg, Version version) { 24 | msg.writeString(reason.toJsonText(version)); 25 | } 26 | 27 | @Override 28 | public String toString() { 29 | return getClass().getSimpleName(); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/packets/out/PlayerCloveInventory.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.packets.out; 2 | 3 | import ru.nanit.limbo.protocol.ByteMessage; 4 | import ru.nanit.limbo.protocol.PacketOut; 5 | import ru.nanit.limbo.protocol.registry.Version; 6 | 7 | /** 8 | * 关闭用户所打开界面 9 | * @author CNLuminous 2022/10/19 10 | */ 11 | public class PlayerCloveInventory implements PacketOut { 12 | int windowId = 0; 13 | @Override 14 | public void encode(ByteMessage msg, Version version) { 15 | msg.writeVarInt(windowId); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/works/entity/Attachments.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.works.entity; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * 代表可以被添加附件 8 | * @author jja8 9 | * */ 10 | public class Attachments { 11 | Map,Object> attachmentMap = new HashMap<>(); 12 | 13 | /** 14 | * 设置附件,每个类只能附一个,如果赋了新的对象旧的就失效了 15 | * */ 16 | public void set(Class attachmentClass, T attachment){ 17 | attachmentMap.put(attachmentClass,attachment); 18 | } 19 | 20 | /** 21 | * 获取某附件 22 | * */ 23 | public T get(Class attachmentClass){ 24 | return (T) attachmentMap.get(attachmentClass); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/works/event/Cancelable.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.works.event; 2 | 3 | /** 4 | * 可取消事件 5 | * @author jja8 6 | * */ 7 | public interface Cancelable extends Event{ 8 | boolean isCancel(); 9 | 10 | void setCancel(boolean cancel); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/works/event/Event.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.works.event; 2 | 3 | /** 4 | * 所有事件的父类 5 | * @author jja8 6 | * */ 7 | public interface Event { 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/works/event/EventManager.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.works.event; 2 | 3 | import java.lang.reflect.Method; 4 | import java.util.ArrayList; 5 | import java.util.HashMap; 6 | import java.util.List; 7 | import java.util.Map; 8 | 9 | /** 10 | * 事件管理器 11 | * @author jja8 12 | * */ 13 | public class EventManager { 14 | static Map, List>> listerMap = new HashMap<>(); 15 | 16 | /** 17 | * 注册指定事件的监听器 18 | * */ 19 | public static void regLister(Class t,Lister lister){ 20 | List> listerList = listerMap.computeIfAbsent(t, k -> new ArrayList<>()); 21 | listerList.add(lister); 22 | } 23 | /** 24 | * 通知事件到所有监听器 25 | * */ 26 | public static void call(Event event){ 27 | List> listerList = listerMap.get(event.getClass()); 28 | if (listerList==null){ 29 | return; 30 | } 31 | for (Lister lister : listerList) { 32 | try { 33 | Method method = lister.getClass().getMethod("listen",Event.class); 34 | method.setAccessible(true); 35 | method.invoke(lister,event); 36 | } catch (Throwable e) { 37 | e.printStackTrace(); 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/works/event/Lister.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.works.event; 2 | 3 | /** 4 | * 事件监听器的抽象类 5 | * @author jja8 6 | * */ 7 | public interface Lister{ 8 | void listen(T event); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/works/event/playerEvent/PlayerCancelableEvent.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.works.event.playerEvent; 2 | 3 | import cn.moonmc.limboAdd.works.entity.Player; 4 | import cn.moonmc.limboAdd.works.event.Cancelable; 5 | import lombok.Getter; 6 | import lombok.Setter; 7 | 8 | /** 9 | * 玩家可取消事件 10 | * @author jja8 11 | * */ 12 | public abstract class PlayerCancelableEvent extends PlayerEvent implements Cancelable { 13 | @Getter @Setter 14 | boolean isCancel = false; 15 | 16 | public PlayerCancelableEvent(Player player) { 17 | super(player); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/works/event/playerEvent/PlayerChatEvent.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.works.event.playerEvent; 2 | 3 | import cn.moonmc.limboAdd.works.entity.Player; 4 | import lombok.Getter; 5 | 6 | /** 7 | * 玩家聊天事件 8 | * @author jja8 9 | * */ 10 | public class PlayerChatEvent extends PlayerEvent { 11 | /** 12 | * 获取玩家的聊天信息 13 | * */ 14 | @Getter 15 | String chat; 16 | 17 | public PlayerChatEvent(Player player, String chat) { 18 | super(player); 19 | this.chat = chat; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/works/event/playerEvent/PlayerClickButtonContainer.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.works.event.playerEvent; 2 | 3 | import cn.moonmc.limboAdd.works.entity.Player; 4 | import lombok.Getter; 5 | 6 | /** 7 | * @author CNLuminous 2022/10/26 8 | */ 9 | public class PlayerClickButtonContainer extends PlayerEvent{ 10 | 11 | @Getter 12 | private Integer buttonId; 13 | @Getter 14 | Integer windowId; 15 | 16 | public PlayerClickButtonContainer(Player player, Integer buttonId, Integer windowId) { 17 | super(player); 18 | this.buttonId = buttonId; 19 | this.windowId = windowId; 20 | } 21 | 22 | 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/works/event/playerEvent/PlayerClickContainer.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.works.event.playerEvent; 2 | 3 | import cn.moonmc.limboAdd.works.entity.Player; 4 | import lombok.Getter; 5 | 6 | /** 7 | * 玩家点击物品栏格子事件 8 | * @author jja8 9 | * 点击类型太复杂了,就先这样吧,知道格子应该够用了QAQ 10 | * */ 11 | public class PlayerClickContainer extends PlayerEvent { 12 | /** 13 | * 被点击的格子 14 | * */ 15 | @Getter 16 | short slot; 17 | @Getter 18 | int windowID; 19 | 20 | 21 | public PlayerClickContainer(Player player, short slot, int windowID) { 22 | super(player); 23 | this.slot = slot; 24 | this.windowID = windowID; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/works/event/playerEvent/PlayerCloseContainer.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.works.event.playerEvent; 2 | 3 | import cn.moonmc.limboAdd.works.entity.Player; 4 | import lombok.Getter; 5 | 6 | /** 7 | * 玩家关闭容器事件 8 | * @author jja8 9 | * */ 10 | public class PlayerCloseContainer extends PlayerEvent { 11 | @Getter 12 | int windowID; 13 | 14 | public PlayerCloseContainer(Player player, int windowID) { 15 | super(player); 16 | this.windowID = windowID; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/works/event/playerEvent/PlayerCommandEvent.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.works.event.playerEvent; 2 | 3 | import cn.moonmc.limboAdd.works.entity.Player; 4 | import lombok.Getter; 5 | 6 | /** 7 | * 玩家命令事件 8 | * @author jja8 9 | * */ 10 | public class PlayerCommandEvent extends PlayerEvent { 11 | @Getter 12 | String command; 13 | 14 | public PlayerCommandEvent(Player player, String command) { 15 | super(player); 16 | this.command = command; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/works/event/playerEvent/PlayerConnectEvent.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.works.event.playerEvent; 2 | 3 | import cn.moonmc.limboAdd.works.entity.Player; 4 | 5 | /** 6 | * 玩家进入服务器,但是还没完成握手时触发此事件 7 | * @author jja8 8 | * */ 9 | public class PlayerConnectEvent extends PlayerEvent{ 10 | public PlayerConnectEvent(Player player) { 11 | super(player); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/works/event/playerEvent/PlayerEvent.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.works.event.playerEvent; 2 | 3 | import cn.moonmc.limboAdd.works.entity.Player; 4 | import cn.moonmc.limboAdd.works.event.Event; 5 | import lombok.Getter; 6 | 7 | /** 8 | * 玩家事件 9 | * @author jja8 10 | * */ 11 | public abstract class PlayerEvent implements Event { 12 | /** 13 | * 获得触发此事件的玩家 14 | * */ 15 | @Getter 16 | Player player; 17 | public PlayerEvent(Player player) { 18 | this.player = player; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/works/event/playerEvent/PlayerJoinEvent.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.works.event.playerEvent; 2 | 3 | import cn.moonmc.limboAdd.works.entity.Player; 4 | 5 | /*** 6 | * 玩家进入服务器事件 7 | * @author 夜光 8 | * */ 9 | public class PlayerJoinEvent extends PlayerEvent{ 10 | public PlayerJoinEvent(Player player) { 11 | super(player); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/works/event/playerEvent/PlayerQuitEvent.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.works.event.playerEvent; 2 | 3 | import cn.moonmc.limboAdd.works.entity.Player; 4 | 5 | /** 6 | * 玩家退出事件 7 | * @author jja8 8 | * */ 9 | public class PlayerQuitEvent extends PlayerEvent{ 10 | public PlayerQuitEvent(Player player) { 11 | super(player); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/works/event/playerEvent/PlayerRenameItem.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.works.event.playerEvent; 2 | 3 | import cn.moonmc.limboAdd.works.entity.Player; 4 | import lombok.Getter; 5 | 6 | /** 7 | * 铁砧每次修改物品名称都会触发 8 | * @author jja8 9 | * */ 10 | public class PlayerRenameItem extends PlayerEvent { 11 | /** 12 | * 获取被修改的名称 13 | * */ 14 | @Getter 15 | String name; 16 | 17 | public PlayerRenameItem(Player player, String name) { 18 | super(player); 19 | this.name = name; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/works/menu/AnvilInventory.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.works.menu; 2 | 3 | import cn.moonmc.limboAdd.packets.out.PacketOpenMenu; 4 | import cn.moonmc.limboAdd.packets.out.PacketSetContainerProperty; 5 | import cn.moonmc.limboAdd.works.entity.Player; 6 | import cn.moonmc.limboAdd.works.event.Lister; 7 | import cn.moonmc.limboAdd.works.event.playerEvent.PlayerClickContainer; 8 | import cn.moonmc.limboAdd.works.event.playerEvent.PlayerRenameItem; 9 | import cn.moonmc.limboAdd.works.message.JsonText; 10 | import lombok.Getter; 11 | import lombok.Setter; 12 | 13 | /** 14 | * 一个铁砧界面,玩家拿走物品或放上物品in1,in2并不会更新哈。因为反正也用不着awa 15 | * @author jja8 16 | * */ 17 | public class AnvilInventory extends ShowInventory { 18 | @Getter 19 | JsonText title; 20 | 21 | @Getter 22 | Item in1; 23 | @Getter 24 | Item in2; 25 | @Getter 26 | Item out; 27 | 28 | /** 29 | * 重命名的名称 30 | * */ 31 | @Getter 32 | String reSetName; 33 | 34 | /** 35 | * 重命名事件监听器,当玩家在此界面重命名时传递事件 36 | * */ 37 | @Getter @Setter 38 | Lister renameItemLister; 39 | 40 | /** 41 | * 维修成本 42 | * */ 43 | @Getter 44 | short repairCost = 0; 45 | 46 | public AnvilInventory(JsonText title) { 47 | this.title = title; 48 | } 49 | 50 | public void setIn1(Item in1) { 51 | this.in1 = in1; 52 | getOpenPlayers().forEachRemaining(player -> sendSlotUp(0,in1,player)); 53 | } 54 | 55 | public void setIn2(Item in2) { 56 | this.in2 = in2; 57 | getOpenPlayers().forEachRemaining(player -> sendSlotUp(1,in2,player)); 58 | } 59 | 60 | public void setOut(Item out) { 61 | this.out = out; 62 | getOpenPlayers().forEachRemaining(player -> sendSlotUp(2,out,player)); 63 | } 64 | 65 | /** 66 | * 设置维修成本 67 | * */ 68 | public void setRepairCost(short repairCost) { 69 | this.repairCost = repairCost; 70 | getOpenPlayers().forEachRemaining(this::sendRepairCost); 71 | } 72 | 73 | @Override 74 | protected void show(Player player) { 75 | PacketOpenMenu packetOpenMenu = new PacketOpenMenu(); 76 | packetOpenMenu.setTitle(title); 77 | packetOpenMenu.setSlots(0); 78 | packetOpenMenu.setWindowsType(PacketOpenMenu.WindowsType.anvil); 79 | packetOpenMenu.setWindowID(windowID); 80 | player.getClientConnection().sendPacket(packetOpenMenu); 81 | sendSlotUp(0,in1,player); 82 | sendSlotUp(1,in2,player); 83 | sendSlotUp(2,out,player); 84 | } 85 | 86 | @Override 87 | protected void beClick(PlayerClickContainer event) { 88 | super.beClick(event); 89 | //先触发父类监听器再更新 90 | switch (event.getSlot()) { 91 | case 0->{ 92 | reSetName = null; //点击物品0后名字会被清空 93 | sendSlotAndRepairCost(2,out,event.getPlayer()); 94 | } 95 | case 1->{ 96 | sendSlotAndRepairCost(2,out,event.getPlayer()); 97 | } 98 | } 99 | } 100 | 101 | 102 | public void renameItem(PlayerRenameItem event) { 103 | try { 104 | if (renameItemLister!=null){ 105 | renameItemLister.listen(event); 106 | } 107 | }catch (Throwable throwable){ 108 | throwable.printStackTrace(); 109 | } 110 | reSetName = event.getName(); 111 | //先触发监听器再更新 112 | sendSlotAndRepairCost(2,out,event.getPlayer()); 113 | } 114 | 115 | /** 116 | * 发送物品更新和维修等级 117 | * */ 118 | private void sendSlotAndRepairCost(int slot,Item item,Player player){ 119 | sendSlotUp(slot,item,player); 120 | sendRepairCost(player); 121 | } 122 | 123 | 124 | protected void sendSlotUp(int slot,Item item, Player player) { 125 | if (item!=null){ 126 | super.sendSlot(slot, item, player); 127 | //每次更新都需要发送维修成本 128 | sendRepairCost(player); 129 | } 130 | } 131 | 132 | /** 133 | * 发送维修成本 134 | * */ 135 | private void sendRepairCost(Player player){ 136 | PacketSetContainerProperty packetSetContainerProperty = new PacketSetContainerProperty(); 137 | packetSetContainerProperty.setWindowID(windowID); 138 | packetSetContainerProperty.setProperty((short) 0); 139 | packetSetContainerProperty.setValue(repairCost); 140 | player.getClientConnection().sendPacket(packetSetContainerProperty); 141 | } 142 | 143 | 144 | } 145 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/works/menu/BookItemNBTs.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.works.menu; 2 | 3 | import cn.moonmc.limboAdd.works.message.JsonText; 4 | import cn.moonmc.limboAdd.works.message.JsonTextParagraph; 5 | import lombok.Data; 6 | import lombok.EqualsAndHashCode; 7 | import net.kyori.adventure.nbt.CompoundBinaryTag; 8 | import net.kyori.adventure.nbt.ListBinaryTag; 9 | import net.kyori.adventure.nbt.StringBinaryTag; 10 | import org.jetbrains.annotations.NotNull; 11 | import ru.nanit.limbo.protocol.registry.Version; 12 | 13 | import java.util.List; 14 | 15 | /** 16 | * @author jja8 17 | * */ 18 | @EqualsAndHashCode(callSuper=false) 19 | public class BookItemNBTs extends ItemNBTs{ 20 | 21 | /** 22 | * 书的标题 23 | * */ 24 | String bookTitle = "默认的书"; 25 | /** 26 | * 书的作者 27 | * */ 28 | String bookAuthor = "jianjian"; 29 | 30 | /** 31 | * 书的页面 32 | * */ 33 | List bookPages = List.of(new JsonTextParagraph("默认页面")); 34 | 35 | public BookItemNBTs(Version version) { 36 | super(version); 37 | } 38 | 39 | /** 40 | * 设置书的标题 41 | * @return 返回自己,用于神奇写法 42 | * */ 43 | public BookItemNBTs setBookTitle(String bookTitle) { 44 | this.bookTitle = bookTitle; 45 | return this; 46 | } 47 | /** 48 | * 设置书的作者 49 | * @return 返回自己,用于神奇写法 50 | * */ 51 | public BookItemNBTs setBookAuthor(String bookAuthor) { 52 | this.bookAuthor = bookAuthor; 53 | return this; 54 | } 55 | /** 56 | * 设置书的页面 57 | * @return 返回自己,用于神奇写法 58 | * */ 59 | public BookItemNBTs setBookPages(List bookPages) { 60 | this.bookPages = bookPages; 61 | return this; 62 | } 63 | 64 | @Override 65 | protected void builderNBT(CompoundBinaryTag.@NotNull Builder nbt) { 66 | super.builderNBT(nbt); 67 | addTitle(nbt); 68 | addAuthor(nbt); 69 | addPages(nbt,version); 70 | } 71 | 72 | private void addPages(CompoundBinaryTag.@NotNull Builder nbt, Version version) { 73 | ListBinaryTag.Builder binaryTagBuilder = ListBinaryTag.builder(); 74 | for (JsonText jsonText : bookPages) { 75 | binaryTagBuilder.add(StringBinaryTag.of(jsonText.toJsonText(version))); 76 | } 77 | nbt.put("pages",binaryTagBuilder.build()); 78 | } 79 | 80 | private void addAuthor(CompoundBinaryTag.Builder nbt) { 81 | nbt.putString("author", bookAuthor); 82 | } 83 | 84 | private void addTitle(CompoundBinaryTag.Builder nbt) { 85 | nbt.putString("title", bookTitle); 86 | } 87 | 88 | 89 | 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/works/menu/GenericInventory.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.works.menu; 2 | 3 | import cn.moonmc.limboAdd.packets.out.PacketOpenMenu; 4 | import cn.moonmc.limboAdd.works.entity.Player; 5 | import cn.moonmc.limboAdd.works.message.JsonText; 6 | import lombok.Getter; 7 | 8 | import java.util.Random; 9 | 10 | /** 11 | * 代表一个箱子库存 12 | * @author jja8 13 | * */ 14 | public class GenericInventory extends ShowInventory{ 15 | int windowID = new Random().nextInt(0,127); 16 | /** 17 | * 箱子标题 18 | * */ 19 | @Getter 20 | JsonText title; 21 | /** 22 | * 箱子大小,(箱子的行数*9) 23 | * */ 24 | @Getter 25 | int genericSize; 26 | /** 27 | * 箱子的物品数组 28 | * */ 29 | Item[] itmes; 30 | 31 | public GenericInventory(JsonText title, int genericSize) { 32 | if (genericSize%9!=0 || genericSize<=0 || genericSize>54){ 33 | throw new Error("箱子的大小必须是9的倍数,并且大于0小于等于54"); 34 | } 35 | this.title = title; 36 | this.genericSize = genericSize; 37 | this.itmes = new Item[genericSize]; 38 | } 39 | 40 | @Override 41 | protected void show(Player player) { 42 | PacketOpenMenu packetOpenMenu = new PacketOpenMenu(); 43 | packetOpenMenu.setWindowID(windowID); 44 | packetOpenMenu.setWindowsTypeID(genericSize/9-1); 45 | packetOpenMenu.setSlots(genericSize); 46 | packetOpenMenu.setTitle(title); 47 | player.getClientConnection().sendPacket(packetOpenMenu); 48 | 49 | //发送物品信息 50 | for (int i = 0; i < itmes.length; i++) { 51 | if (itmes[i]!=null){ 52 | sendSlot(i,itmes[i],player); 53 | } 54 | } 55 | } 56 | 57 | /** 58 | * 设置某格子的物品 59 | * */ 60 | public void setItem(int slot,Item item){ 61 | if (slot>0&&slot sendSlot(slot,item,player)); 65 | }else { 66 | throw new Error("物品位置超出容器范围!"); 67 | } 68 | } 69 | 70 | /** 71 | * 获取某格子的物品 72 | * */ 73 | public Item getItem(int slot){ 74 | if (slot>0&&slot { 21 | Control control = playerControlMap.remove(event.getPlayer()); 22 | if (control!=null){ 23 | control.openPlayers.remove(event.getPlayer()); 24 | control.beClose(event.getPlayer()); 25 | } 26 | }); 27 | EventManager.regLister(PlayerCloseContainer.class, event -> { 28 | Control control = playerControlMap.get(event.getPlayer()); 29 | if (control!=null && control.windowID==event.getWindowID()){ 30 | playerControlMap.remove(event.getPlayer()); 31 | control.openPlayers.remove(event.getPlayer()); 32 | control.beClose(event.getPlayer()); 33 | } 34 | }); 35 | EventManager.regLister(PlayerClickContainer.class, event -> { 36 | Control control = playerControlMap.get(event.getPlayer()); 37 | if (control!=null && control.windowID==event.getWindowID()){ 38 | control.beClick(event); 39 | } 40 | }); 41 | EventManager.regLister(PlayerClickButtonContainer.class,event -> { 42 | Control control = playerControlMap.get(event.getPlayer()); 43 | if (control!=null && control.windowID==event.getWindowId()){ 44 | control.beClickButton(event); 45 | } 46 | 47 | }); 48 | 49 | //通知铁砧改变名字 50 | EventManager.regLister(PlayerRenameItem.class, event -> { 51 | Control control = playerControlMap.get(event.getPlayer()); 52 | if (control instanceof AnvilInventory anvilInventory) { 53 | anvilInventory.renameItem(event); 54 | } 55 | }); 56 | } 57 | 58 | 59 | abstract static class Control{ 60 | private static int windowIdCount = 0; 61 | private static int nexWindowId(){ 62 | return (windowIdCount++ % 126)+1; 63 | } 64 | 65 | protected int windowID = nexWindowId(); 66 | 67 | private final List openPlayers = new ArrayList<>(); 68 | //需要实现或者用来实现 69 | /** 70 | * 给玩家打开界面 71 | * */ 72 | protected abstract void show(Player player); 73 | /** 74 | * 当窗口被关闭时 75 | * */ 76 | protected void beClose(Player player){}; 77 | /** 78 | * 被点击时通知 79 | * */ 80 | protected void beClick(PlayerClickContainer event){}; 81 | /** 82 | * 点击按钮时通知 83 | */ 84 | protected void beClickButton(PlayerClickButtonContainer event){}; 85 | //用来调用 86 | /** 87 | * 获取所有正在查看此界面的玩家 88 | * */ 89 | protected Iterator getOpenPlayers(){ 90 | return openPlayers.iterator(); 91 | } 92 | } 93 | 94 | 95 | static Map playerControlMap = new HashMap<>(); 96 | 97 | /** 98 | * 当窗口被打开时传递进来注册打开状态,才能监听点击事件和关闭事件 99 | * */ 100 | public void openInventory(Control control, Player player){ 101 | Control nastControl = playerControlMap.remove(player); 102 | if (nastControl!=null){ 103 | nastControl.openPlayers.remove(player); 104 | nastControl.beClose(player); 105 | } 106 | try { 107 | control.show(player); 108 | }catch (Throwable e){ 109 | e.printStackTrace(); 110 | } 111 | playerControlMap.put(player,control); 112 | control.openPlayers.add(player); 113 | } 114 | 115 | /** 116 | * 获取玩家正在查看的界面 117 | * */ 118 | public Control lookingInventory(Player player){ 119 | return playerControlMap.get(player); 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/works/menu/Item.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.works.menu; 2 | 3 | import lombok.Data; 4 | import net.kyori.adventure.nbt.CompoundBinaryTag; 5 | import org.jetbrains.annotations.NotNull; 6 | import ru.nanit.limbo.protocol.registry.Version; 7 | 8 | /** 9 | * 代表一个物品 10 | * @author jja8 11 | * */ 12 | @Data 13 | public class Item { 14 | ItemType itemID; 15 | int count = 1; 16 | ItemNBTs itemNBTs; 17 | Version version; 18 | 19 | public Item(Version version) { 20 | this.version = version; 21 | } 22 | 23 | public Item setItemID(ItemType itemID) { 24 | this.itemID = itemID; 25 | return this; 26 | } 27 | 28 | public Item setCount(int count) { 29 | this.count = count; 30 | return this; 31 | } 32 | 33 | public Item setItemNBTs(ItemNBTs itemNBTs) { 34 | this.itemNBTs = itemNBTs; 35 | return this; 36 | } 37 | 38 | public Slot createSlot(){ 39 | Slot slot = new Slot(); 40 | if (itemID==null||count<=0){ 41 | slot.setHasItem(false); 42 | return slot; 43 | } 44 | slot.setItemType(itemID); 45 | slot.setCount(count); 46 | if (itemNBTs==null){ 47 | slot.setNbt(CompoundBinaryTag.builder().build()); 48 | }else { 49 | slot.setNbt(itemNBTs.getNBT()); 50 | } 51 | return slot; 52 | } 53 | 54 | public CompoundBinaryTag ToNBT(){ 55 | CompoundBinaryTag.@NotNull Builder nbt = CompoundBinaryTag.builder(); 56 | nbt.putInt("id",itemID.getItemTypeNetID(version)); 57 | nbt.put("tag", itemNBTs.getNBT()); 58 | return nbt.build(); 59 | } 60 | 61 | public Item copy() { 62 | return new Item(version).setItemID(itemID).setItemNBTs(itemNBTs.copy()).setCount(count); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/works/menu/ItemNBTs.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.works.menu; 2 | 3 | import cn.moonmc.limboAdd.works.message.JsonText; 4 | import lombok.Data; 5 | import net.kyori.adventure.nbt.CompoundBinaryTag; 6 | import net.kyori.adventure.nbt.ListBinaryTag; 7 | import net.kyori.adventure.nbt.StringBinaryTag; 8 | import org.jetbrains.annotations.NotNull; 9 | import ru.nanit.limbo.protocol.registry.Version; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | /** 15 | * 先就只搞个名称,到时候再加附魔啥的 16 | * @author jja8 17 | * */ 18 | @Data 19 | public class ItemNBTs { 20 | JsonText displayName; 21 | List lore; 22 | protected Version version; 23 | 24 | public ItemNBTs(Version version) { 25 | this.version = version; 26 | } 27 | 28 | /** 29 | * 设置物品显示名称 30 | * @return 返回自己,用于神奇写法 31 | * */ 32 | public ItemNBTs setDisplayName(JsonText displayName) { 33 | this.displayName = displayName; 34 | return this; 35 | } 36 | 37 | /** 38 | * 设置物品lore 39 | * @return 返回自己,用于神奇写法 40 | * */ 41 | public ItemNBTs setLore(List lore) { 42 | this.lore = lore; 43 | return this; 44 | } 45 | 46 | public CompoundBinaryTag getNBT() { 47 | CompoundBinaryTag.@NotNull Builder nbt = CompoundBinaryTag.builder(); 48 | builderNBT(nbt); 49 | return nbt.build(); 50 | } 51 | 52 | /** 53 | * 子类可重写此方法添加更多属性 54 | * */ 55 | protected void builderNBT(CompoundBinaryTag.@NotNull Builder nbt){ 56 | addDisplay(nbt); 57 | } 58 | 59 | 60 | private void addDisplay(CompoundBinaryTag.Builder builder){ 61 | CompoundBinaryTag.@NotNull Builder display = CompoundBinaryTag.builder(); 62 | addDisplayName(display); 63 | addLore(display); 64 | builder.put("display", display.build()); 65 | } 66 | 67 | private void addDisplayName(CompoundBinaryTag.Builder display){ 68 | if (displayName==null){ 69 | return; 70 | } 71 | display.putString( 72 | "Name", 73 | displayName.toJsonText(version) 74 | ); 75 | } 76 | 77 | private void addLore(CompoundBinaryTag.Builder display){ 78 | if (lore==null){ 79 | return; 80 | } 81 | ListBinaryTag.Builder binaryTagBuilder = ListBinaryTag.builder(); 82 | for (JsonText jsonText : lore) { 83 | binaryTagBuilder.add(StringBinaryTag.of(jsonText.toJsonText(version))); 84 | } 85 | display.put("Lore",binaryTagBuilder.build()); 86 | } 87 | 88 | public ItemNBTs copy() { 89 | ItemNBTs itemNBTs = new ItemNBTs(version); 90 | if (lore!=null){ 91 | itemNBTs.setLore(new ArrayList<>(lore)); 92 | } 93 | return itemNBTs.setDisplayName(displayName); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/works/menu/LecternInventory.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.works.menu; 2 | 3 | import cn.moonmc.limboAdd.packets.out.PacketOpenMenu; 4 | import cn.moonmc.limboAdd.packets.out.PacketSetContainerProperty; 5 | import cn.moonmc.limboAdd.works.entity.Player; 6 | import cn.moonmc.limboAdd.works.event.Lister; 7 | import cn.moonmc.limboAdd.works.event.playerEvent.PlayerClickButtonContainer; 8 | import lombok.Getter; 9 | 10 | import java.util.function.Consumer; 11 | 12 | /** 13 | * @author CNLuminous 2022/10/26 14 | */ 15 | public class LecternInventory extends ShowInventory { 16 | private Item book; 17 | 18 | @Getter 19 | private int nowId; 20 | 21 | public LecternInventory(Item book) { 22 | this.book = book; 23 | } 24 | 25 | @Override 26 | protected void show(Player player) { 27 | 28 | //打开窗口 29 | PacketOpenMenu packetOpenMenu = new PacketOpenMenu(); 30 | packetOpenMenu.setSlots(1); 31 | packetOpenMenu.setWindowsType(PacketOpenMenu.WindowsType.lectern); 32 | packetOpenMenu.setWindowID(windowID); 33 | player.getClientConnection().sendPacket(packetOpenMenu); 34 | //设置书 35 | sendSlotUp(player); 36 | 37 | //解决跳页问题 38 | nowId = 0; 39 | } 40 | 41 | @Override 42 | protected void beClickButton(PlayerClickButtonContainer event) { 43 | if (event.getButtonId()==1){ 44 | nowId -= 1; 45 | }else if (event.getButtonId()==2){ 46 | nowId += 1; 47 | } 48 | changePage(); 49 | super.beClickButton(event); 50 | } 51 | 52 | protected void sendSlotUp(Player player) { 53 | if (book!=null){ 54 | super.sendSlot(0, book, player); 55 | } 56 | } 57 | 58 | /** 59 | * 给所有玩家更新页码 60 | * */ 61 | protected void changePage(){ 62 | PacketSetContainerProperty packetSetContainerProperty = new PacketSetContainerProperty(); 63 | packetSetContainerProperty.setWindowID(windowID); 64 | packetSetContainerProperty.setProperty((short) 0); 65 | packetSetContainerProperty.setValue((short) nowId); 66 | getOpenPlayers().forEachRemaining(player -> player.getClientConnection().sendPacket(packetSetContainerProperty)); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/works/menu/PlayerInventory.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.works.menu; 2 | 3 | import cn.moonmc.limboAdd.packets.out.PacketSetContainerSlot; 4 | import cn.moonmc.limboAdd.works.entity.Player; 5 | 6 | /** 7 | * 代表玩家物品栏,背包里物品设置的功能就不写了awa反正也没用。就写一个设置光标上物品的功能够用了awa。 8 | * 也不记录光标上的物品了,反正也没用。至于玩家把物品放到什么地方了光标上还有没有物品啥的,知道这些干啥,反正也没用。 9 | * @author jja8 10 | * */ 11 | public class PlayerInventory implements Inventory{ 12 | final Player player; 13 | 14 | /** 15 | * 请使用Player.getPlayerInventory(); 16 | * */ 17 | public PlayerInventory(Player player) { 18 | this.player = player; 19 | } 20 | 21 | /** 22 | * 设置玩家光标上的物品 23 | * */ 24 | public void setCursor(Item item){ 25 | PacketSetContainerSlot packetSetContainerSlot = new PacketSetContainerSlot(); 26 | packetSetContainerSlot.setWindowID(-1); 27 | packetSetContainerSlot.setStateID(0); 28 | packetSetContainerSlot.setSlotID((short) 0); 29 | packetSetContainerSlot.setSlot(item.createSlot()); 30 | player.getClientConnection().sendPacket(packetSetContainerSlot); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/works/menu/ShowInventory.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.works.menu; 2 | 3 | import cn.moonmc.limboAdd.packets.out.PacketSetContainerSlot; 4 | import cn.moonmc.limboAdd.works.entity.Player; 5 | import cn.moonmc.limboAdd.works.event.Event; 6 | import cn.moonmc.limboAdd.works.event.Lister; 7 | import cn.moonmc.limboAdd.works.event.playerEvent.PlayerClickButtonContainer; 8 | import cn.moonmc.limboAdd.works.event.playerEvent.PlayerClickContainer; 9 | import lombok.Getter; 10 | import lombok.Setter; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | /** 14 | * 代表一个需要打开展示的库存 15 | * @author jja8 16 | * */ 17 | public abstract class ShowInventory extends InventoryManager.Control implements Inventory{ 18 | 19 | public static class BeClose implements Event { 20 | @Getter 21 | final Player player; 22 | public BeClose(Player player) { 23 | this.player = player; 24 | } 25 | } 26 | 27 | /** 28 | * 点击事件监听器,当玩家在此界面点击时传递事件 29 | * */ 30 | @Getter 31 | @Setter 32 | Lister clickLister; 33 | 34 | /** 35 | * 点击按钮监听器 36 | */ 37 | @Getter 38 | @Setter 39 | Lister clickButtonLister; 40 | /** 41 | * 关闭事件监听器 42 | * */ 43 | @Getter 44 | @Setter 45 | Lister closeLister; 46 | 47 | /** 48 | * 被点击时传递事件 49 | * */ 50 | @Override 51 | protected void beClick(PlayerClickContainer event) { 52 | try { 53 | if (clickLister!=null){ 54 | clickLister.listen(event); 55 | } 56 | }catch (Throwable throwable){ 57 | throwable.printStackTrace(); 58 | } 59 | 60 | } 61 | 62 | @Override 63 | protected void beClickButton(PlayerClickButtonContainer event){ 64 | try { 65 | if (clickButtonLister!=null){ 66 | clickButtonLister.listen(event); 67 | } 68 | }catch (Throwable throwable){ 69 | throwable.printStackTrace(); 70 | } 71 | 72 | } 73 | /** 74 | * 被关闭时传递事件 75 | * */ 76 | @Override 77 | protected void beClose(Player player) { 78 | try { 79 | if (closeLister!=null){ 80 | closeLister.listen(new BeClose(player)); 81 | } 82 | }catch (Throwable throwable){ 83 | throwable.printStackTrace(); 84 | } 85 | 86 | } 87 | 88 | /** 89 | * 发送物品更新 90 | * */ 91 | protected void sendSlot(int slot, @NotNull Item item,@NotNull Player player){ 92 | PacketSetContainerSlot packetSetContainerSlot = new PacketSetContainerSlot(); 93 | packetSetContainerSlot.setWindowID(windowID); 94 | packetSetContainerSlot.setSlotID((short) slot); 95 | packetSetContainerSlot.setSlot(item.createSlot()); 96 | player.getClientConnection().sendPacket(packetSetContainerSlot); 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/works/menu/Slot.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.works.menu; 2 | 3 | import lombok.Data; 4 | import net.kyori.adventure.nbt.CompoundBinaryTag; 5 | 6 | @Data 7 | public class Slot { 8 | boolean hasItem = true; 9 | ItemType itemType = ItemType.stone; 10 | int count = 1; 11 | CompoundBinaryTag nbt = CompoundBinaryTag.builder().build(); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/works/message/ClickEvent.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.works.message; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * 代表鼠点击时动作 7 | * */ 8 | public interface ClickEvent { 9 | Map toMap(); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/works/message/ClickEventChangePage.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.works.message; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * 鼠标点击执给书本翻页 7 | * */ 8 | public class ClickEventChangePage implements ClickEvent{ 9 | int page; 10 | 11 | public ClickEventChangePage(int page) { 12 | this.page = page; 13 | } 14 | 15 | @Override 16 | public Map toMap() { 17 | return Map.of("action","change_page","value", String.valueOf(page)); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/works/message/ClickEventRunCommand.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.works.message; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * 鼠标点击执行命令 7 | * */ 8 | public class ClickEventRunCommand implements ClickEvent{ 9 | String command; 10 | 11 | public ClickEventRunCommand(String command) { 12 | this.command = command; 13 | } 14 | 15 | @Override 16 | public Map toMap() { 17 | return Map.of("action","run_command","value",command); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/works/message/ClickEventoOpenUrl.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.works.message; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * 鼠标点击执行打开链接 7 | * */ 8 | public class ClickEventoOpenUrl implements ClickEvent{ 9 | String url; 10 | 11 | public ClickEventoOpenUrl(String url) { 12 | this.url = url; 13 | } 14 | 15 | @Override 16 | public Map toMap() { 17 | return Map.of("action","open_url","value", url); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/works/message/HoverEvent.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.works.message; 2 | 3 | import ru.nanit.limbo.protocol.registry.Version; 4 | 5 | import java.util.Map; 6 | 7 | /** 8 | * 代表一个鼠标停留时动作 9 | * 10 | * @author jja8 11 | */ 12 | public interface HoverEvent { 13 | Map toMap(Version version); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/works/message/HoverEventShowItem.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.works.message; 2 | 3 | import cn.moonmc.limboAdd.works.menu.Item; 4 | import net.kyori.adventure.nbt.TagStringIO; 5 | import ru.nanit.limbo.protocol.registry.Version; 6 | 7 | import java.io.IOException; 8 | import java.util.Map; 9 | 10 | /** 11 | * 鼠标停留时显示物品属性,这个先不要用,我生成的json是没问题的但是就是显示不出来文本到时候再修吧 12 | * @author jja8 13 | */ 14 | @Deprecated 15 | public class HoverEventShowItem implements HoverEvent { 16 | final Item item; 17 | 18 | public HoverEventShowItem(Item item) { 19 | this.item = item; 20 | } 21 | 22 | @Override 23 | public Map toMap(Version version) { 24 | try { 25 | return Map.of("action", "show_item", "value", TagStringIO.get().asString(item.ToNBT())); 26 | } catch (IOException e) { 27 | throw new RuntimeException(e); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/works/message/HoverEventShowText.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.works.message; 2 | 3 | import ru.nanit.limbo.protocol.registry.Version; 4 | 5 | import java.util.Map; 6 | 7 | /** 8 | * 鼠标停留时显示文本动作 9 | * @author jja8 10 | */ 11 | public class HoverEventShowText implements HoverEvent { 12 | final String text; 13 | 14 | public HoverEventShowText(String text) { 15 | this.text = text; 16 | } 17 | 18 | @Override 19 | public Map toMap(Version version) { 20 | return Map.of("action", "show_text", "value", text); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/works/message/JsonText.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.works.message; 2 | 3 | import ru.nanit.limbo.protocol.registry.Version; 4 | 5 | /** 6 | * @author jja8 7 | * */ 8 | public interface JsonText { 9 | String toJsonText(Version version); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/works/message/JsonTextArticle.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.works.message; 2 | 3 | import com.grack.nanojson.JsonWriter; 4 | import ru.nanit.limbo.protocol.registry.Version; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | /** 11 | * 代表一篇文章,由许多段落组成 12 | * @author jja 13 | * */ 14 | public class JsonTextArticle implements JsonText{ 15 | 16 | List paragraphs = new ArrayList<>(); 17 | 18 | public JsonTextArticle(JsonTextParagraph jsonTextArticle) { 19 | paragraphs.add(jsonTextArticle); 20 | } 21 | 22 | /** 23 | * 添加一段 24 | * */ 25 | public JsonTextArticle addParagraph(JsonTextParagraph jsonTextParagraph){ 26 | paragraphs.add(jsonTextParagraph); 27 | return this; 28 | } 29 | 30 | @Override 31 | public String toJsonText(Version version) { 32 | List> list = new ArrayList<>(); 33 | for (JsonTextParagraph paragraph : paragraphs) { 34 | list.add(paragraph.toMap(version)); 35 | } 36 | return JsonWriter.string(list); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/works/message/JsonTextParagraph.java: -------------------------------------------------------------------------------- 1 | package cn.moonmc.limboAdd.works.message; 2 | 3 | import com.grack.nanojson.JsonWriter; 4 | import lombok.Getter; 5 | import ru.nanit.limbo.protocol.registry.Version; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | /** 11 | * 代表一个段落,可以单独使用也可以添加到文章中 12 | * @author jja8 13 | * */ 14 | public class JsonTextParagraph implements JsonText{ 15 | @Getter 16 | final String text; 17 | 18 | /** 19 | * 鼠标停留时动作 20 | * */ 21 | @Getter 22 | HoverEvent hoverEvent; 23 | 24 | /** 25 | * 鼠标点击时动作 26 | * */ 27 | @Getter 28 | ClickEvent clickEvent; 29 | 30 | public JsonTextParagraph(String text) { 31 | this.text = text; 32 | } 33 | 34 | @Override 35 | public String toJsonText(Version version){ 36 | return JsonWriter.string(toMap(version)); 37 | } 38 | 39 | /** 40 | * 鼠标停留时动作 41 | * */ 42 | public JsonTextParagraph setHoverEvent(HoverEvent hoverEvent) { 43 | this.hoverEvent = hoverEvent; 44 | return this; 45 | } 46 | 47 | /** 48 | * 鼠标点击时动作 49 | * */ 50 | public JsonTextParagraph setClickEvent(ClickEvent clickEvent) { 51 | this.clickEvent = clickEvent; 52 | return this; 53 | } 54 | 55 | Map toMap(Version version){ 56 | Map map = new HashMap<>(); 57 | map.put("text",text); 58 | if (hoverEvent!=null){ 59 | map.put("hoverEvent",hoverEvent.toMap(version)); 60 | } 61 | if (clickEvent!=null){ 62 | map.put("clickEvent",clickEvent.toMap()); 63 | } 64 | return map; 65 | } 66 | 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/works/readme.md: -------------------------------------------------------------------------------- 1 | works下的内容,用于提供基础的对象和方法。提供给其他功能使用。 2 | 也就是说,再开发其他功能都会用到这个包下的东西。 3 | 4 | ### event提供了事件 5 | EventManager可以通知事件和注册事件监听器。 6 | 7 | ### entity提供了player对象 8 | 通过Player对象可以对玩家进行操作 9 | 10 | ### menu提供了Inventory和他的实现 11 | 可对Inventory进行操作 12 | 13 | ### message提供了客户端消息处理 14 | 目前只能纯文本,后面可能会添加彩色文本等其他内容 -------------------------------------------------------------------------------- /src/main/java/cn/moonmc/limboAdd/描述.md: -------------------------------------------------------------------------------- 1 | limboAdd下的内容是对limbo的修改和添加,不负责添加功能。比如登录功能,选择大厅功能。 2 | 3 | 4 | 更多请看works/描述.md -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/LimboConstants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo; 19 | 20 | public final class LimboConstants { 21 | 22 | public static final String VELOCITY_INFO_CHANNEL = "velocity:player_info"; 23 | public static final String BRAND_CHANNEL = "minecraft:brand"; 24 | 25 | private LimboConstants() {} 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/NanoLimbo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo; 19 | 20 | import ru.nanit.limbo.server.LimboServer; 21 | import ru.nanit.limbo.server.Logger; 22 | 23 | public final class NanoLimbo { 24 | 25 | public static void main(String[] args) { 26 | try { 27 | new LimboServer(); 28 | } catch (Exception e) { 29 | Logger.error("Cannot start server: ", e); 30 | } 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/configuration/SocketAddressSerializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.configuration; 19 | 20 | import org.checkerframework.checker.nullness.qual.Nullable; 21 | import org.spongepowered.configurate.ConfigurationNode; 22 | import org.spongepowered.configurate.serialize.TypeSerializer; 23 | 24 | import java.lang.reflect.Type; 25 | import java.net.InetSocketAddress; 26 | import java.net.SocketAddress; 27 | 28 | public class SocketAddressSerializer implements TypeSerializer { 29 | 30 | @Override 31 | public SocketAddress deserialize(Type type, ConfigurationNode node) { 32 | String ip = node.node("ip").getString(); 33 | int port = node.node("port").getInt(); 34 | SocketAddress address; 35 | 36 | if (ip == null || ip.isEmpty()) { 37 | address = new InetSocketAddress(port); 38 | } else { 39 | address = new InetSocketAddress(ip, port); 40 | } 41 | 42 | return address; 43 | } 44 | 45 | @Override 46 | public void serialize(Type type, @Nullable SocketAddress obj, ConfigurationNode node) { 47 | 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/connection/ClientChannelInitializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.connection; 19 | 20 | import io.netty.channel.Channel; 21 | import io.netty.channel.ChannelInitializer; 22 | import io.netty.channel.ChannelPipeline; 23 | import io.netty.handler.timeout.ReadTimeoutHandler; 24 | import ru.nanit.limbo.connection.pipeline.PacketDecoder; 25 | import ru.nanit.limbo.connection.pipeline.PacketEncoder; 26 | import ru.nanit.limbo.connection.pipeline.VarIntFrameDecoder; 27 | import ru.nanit.limbo.connection.pipeline.VarIntLengthEncoder; 28 | import ru.nanit.limbo.server.LimboServer; 29 | 30 | import java.util.concurrent.TimeUnit; 31 | 32 | public class ClientChannelInitializer extends ChannelInitializer { 33 | 34 | private final LimboServer server; 35 | 36 | public ClientChannelInitializer(LimboServer server) { 37 | this.server = server; 38 | } 39 | 40 | @Override 41 | protected void initChannel(Channel channel) { 42 | ChannelPipeline pipeline = channel.pipeline(); 43 | 44 | PacketDecoder decoder = new PacketDecoder(); 45 | PacketEncoder encoder = new PacketEncoder(); 46 | ClientConnection connection = new ClientConnection(channel, server, decoder, encoder); 47 | 48 | pipeline.addLast("timeout", new ReadTimeoutHandler(server.getConfig().getReadTimeout(), 49 | TimeUnit.MILLISECONDS)); 50 | pipeline.addLast("frame_decoder", new VarIntFrameDecoder()); 51 | pipeline.addLast("frame_encoder", new VarIntLengthEncoder()); 52 | pipeline.addLast("decoder", decoder); 53 | pipeline.addLast("encoder", encoder); 54 | pipeline.addLast("handler", connection); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/connection/GameProfile.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.connection; 19 | 20 | import java.util.UUID; 21 | 22 | public class GameProfile { 23 | 24 | private UUID uuid; 25 | private String username; 26 | 27 | public UUID getUuid() { 28 | return uuid; 29 | } 30 | 31 | public void setUuid(UUID uuid) { 32 | this.uuid = uuid; 33 | } 34 | 35 | public String getUsername() { 36 | return username; 37 | } 38 | 39 | public void setUsername(String username) { 40 | this.username = username; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/connection/pipeline/PacketDecoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.connection.pipeline; 19 | 20 | import io.netty.buffer.ByteBuf; 21 | import io.netty.channel.ChannelHandlerContext; 22 | import io.netty.handler.codec.MessageToMessageDecoder; 23 | import ru.nanit.limbo.protocol.ByteMessage; 24 | import ru.nanit.limbo.protocol.Packet; 25 | import ru.nanit.limbo.protocol.registry.State; 26 | import ru.nanit.limbo.protocol.registry.Version; 27 | import ru.nanit.limbo.server.Logger; 28 | 29 | import java.util.List; 30 | 31 | public class PacketDecoder extends MessageToMessageDecoder { 32 | 33 | private State.PacketRegistry mappings; 34 | private Version version; 35 | 36 | public PacketDecoder() { 37 | updateVersion(Version.getMin()); 38 | updateState(State.HANDSHAKING); 39 | } 40 | 41 | @Override 42 | protected void decode(ChannelHandlerContext ctx, ByteBuf buf, List out) throws Exception { 43 | if (!ctx.channel().isActive() || mappings == null) return; 44 | 45 | ByteMessage msg = new ByteMessage(buf); 46 | int packetId = msg.readVarInt(); 47 | Packet packet = mappings.getPacket(packetId); 48 | 49 | if (packet != null) { 50 | Logger.debug("Received packet %s[0x%s]", packet.toString(), Integer.toHexString(packetId)); 51 | try { 52 | packet.decode(msg, version); 53 | } catch (Exception e) { 54 | e.printStackTrace(); 55 | Logger.warning("Cannot decode packet 0x%s: %s", Integer.toHexString(packetId), e.getMessage()); 56 | } 57 | 58 | ctx.fireChannelRead(packet); 59 | } else { 60 | Logger.debug("Undefined incoming packet: 0x" + Integer.toHexString(packetId)); 61 | } 62 | } 63 | 64 | public void updateVersion(Version version) { 65 | this.version = version; 66 | } 67 | 68 | public void updateState(State state) { 69 | this.mappings = state.serverBound.getRegistry(version); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/connection/pipeline/PacketEncoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.connection.pipeline; 19 | 20 | import io.netty.buffer.ByteBuf; 21 | import io.netty.channel.ChannelHandlerContext; 22 | import io.netty.handler.codec.MessageToByteEncoder; 23 | import ru.nanit.limbo.protocol.ByteMessage; 24 | import ru.nanit.limbo.protocol.Packet; 25 | import ru.nanit.limbo.protocol.PacketSnapshot; 26 | import ru.nanit.limbo.protocol.registry.State; 27 | import ru.nanit.limbo.protocol.registry.Version; 28 | import ru.nanit.limbo.server.Logger; 29 | 30 | public class PacketEncoder extends MessageToByteEncoder { 31 | 32 | private State.PacketRegistry registry; 33 | private Version version; 34 | 35 | public PacketEncoder() { 36 | updateVersion(Version.getMin()); 37 | updateState(State.HANDSHAKING); 38 | } 39 | 40 | @Override 41 | protected void encode(ChannelHandlerContext ctx, Packet packet, ByteBuf out) throws Exception { 42 | if (registry == null) return; 43 | 44 | ByteMessage msg = new ByteMessage(out); 45 | int packetId; 46 | 47 | if (packet instanceof PacketSnapshot) { 48 | packetId = registry.getPacketId(((PacketSnapshot)packet).getWrappedPacket().getClass()); 49 | } else { 50 | packetId = registry.getPacketId(packet.getClass()); 51 | } 52 | 53 | if (packetId == -1) { 54 | Logger.warning("Undefined packet class: %s[0x%s]", packet.getClass().getName(), Integer.toHexString(packetId)); 55 | return; 56 | } 57 | 58 | msg.writeVarInt(packetId); 59 | 60 | try { 61 | packet.encode(msg, version); 62 | 63 | if (Logger.getLevel() >= Logger.Level.DEBUG.getIndex()) { 64 | Logger.debug("Sending %s[0x%s] packet (%d bytes)", packet.toString(), Integer.toHexString(packetId), msg.readableBytes()); 65 | } 66 | } catch (Exception e) { 67 | Logger.error("Cannot encode packet 0x%s: %s", Integer.toHexString(packetId), e.getMessage()); 68 | } 69 | } 70 | 71 | public void updateVersion(Version version) { 72 | this.version = version; 73 | } 74 | 75 | public void updateState(State state) { 76 | this.registry = state.clientBound.getRegistry(version); 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/connection/pipeline/VarIntByteDecoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.connection.pipeline; 19 | 20 | import io.netty.util.ByteProcessor; 21 | 22 | public class VarIntByteDecoder implements ByteProcessor { 23 | 24 | private int readVarInt; 25 | private int bytesRead; 26 | private DecodeResult result = DecodeResult.TOO_SHORT; 27 | 28 | @Override 29 | public boolean process(byte k) { 30 | readVarInt |= (k & 0x7F) << bytesRead++ * 7; 31 | if (bytesRead > 3) { 32 | result = DecodeResult.TOO_BIG; 33 | return false; 34 | } 35 | if ((k & 0x80) != 128) { 36 | result = DecodeResult.SUCCESS; 37 | return false; 38 | } 39 | return true; 40 | } 41 | 42 | public int getReadVarInt() { 43 | return readVarInt; 44 | } 45 | 46 | public int getBytesRead() { 47 | return bytesRead; 48 | } 49 | 50 | public DecodeResult getResult() { 51 | return result; 52 | } 53 | 54 | public enum DecodeResult { 55 | SUCCESS, 56 | TOO_SHORT, 57 | TOO_BIG 58 | } 59 | } -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/connection/pipeline/VarIntFrameDecoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.connection.pipeline; 19 | 20 | import io.netty.buffer.ByteBuf; 21 | import io.netty.channel.ChannelHandlerContext; 22 | import io.netty.handler.codec.ByteToMessageDecoder; 23 | import ru.nanit.limbo.server.Logger; 24 | 25 | import java.util.List; 26 | 27 | public class VarIntFrameDecoder extends ByteToMessageDecoder { 28 | 29 | @Override 30 | protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) { 31 | if (!ctx.channel().isActive()) { 32 | in.clear(); 33 | return; 34 | } 35 | 36 | VarIntByteDecoder reader = new VarIntByteDecoder(); 37 | int varIntEnd = in.forEachByte(reader); 38 | 39 | if (varIntEnd == -1) return; 40 | 41 | if (reader.getResult() == VarIntByteDecoder.DecodeResult.SUCCESS) { 42 | int readVarInt = reader.getReadVarInt(); 43 | int bytesRead = reader.getBytesRead(); 44 | if (readVarInt < 0) { 45 | Logger.error("[VarIntFrameDecoder] Bad data length"); 46 | } else if (readVarInt == 0) { 47 | in.readerIndex(varIntEnd + 1); 48 | } else { 49 | int minimumRead = bytesRead + readVarInt; 50 | if (in.isReadable(minimumRead)) { 51 | out.add(in.retainedSlice(varIntEnd + 1, readVarInt)); 52 | in.skipBytes(minimumRead); 53 | } 54 | } 55 | } else if (reader.getResult() == VarIntByteDecoder.DecodeResult.TOO_BIG) { 56 | Logger.error("[VarIntFrameDecoder] Too big data"); 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/connection/pipeline/VarIntLengthEncoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.connection.pipeline; 19 | 20 | import io.netty.buffer.ByteBuf; 21 | import io.netty.channel.ChannelHandler; 22 | import io.netty.channel.ChannelHandlerContext; 23 | import io.netty.handler.codec.MessageToByteEncoder; 24 | import ru.nanit.limbo.protocol.ByteMessage; 25 | 26 | @ChannelHandler.Sharable 27 | public class VarIntLengthEncoder extends MessageToByteEncoder { 28 | 29 | @Override 30 | protected void encode(ChannelHandlerContext ctx, ByteBuf buf, ByteBuf out) { 31 | ByteMessage msg = new ByteMessage(out); 32 | msg.writeVarInt(buf.readableBytes()); 33 | msg.writeBytes(buf); 34 | } 35 | 36 | @Override 37 | protected ByteBuf allocateBuffer(ChannelHandlerContext ctx, ByteBuf msg, boolean preferDirect) { 38 | int anticipatedRequiredCapacity = 5 + msg.readableBytes(); 39 | return ctx.alloc().heapBuffer(anticipatedRequiredCapacity); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/protocol/Packet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.protocol; 19 | 20 | import ru.nanit.limbo.connection.ClientConnection; 21 | import ru.nanit.limbo.protocol.registry.Version; 22 | import ru.nanit.limbo.server.LimboServer; 23 | 24 | public interface Packet { 25 | 26 | void encode(ByteMessage msg, Version version); 27 | 28 | void decode(ByteMessage msg, Version version); 29 | 30 | default void handle(ClientConnection conn, LimboServer server) { 31 | // Ignored by default 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/protocol/PacketIn.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.protocol; 19 | 20 | import ru.nanit.limbo.protocol.registry.Version; 21 | 22 | public interface PacketIn extends Packet { 23 | 24 | @Override 25 | default void encode(ByteMessage msg, Version version) { 26 | // Can be ignored for incoming packets 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/protocol/PacketOut.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.protocol; 19 | 20 | import ru.nanit.limbo.protocol.registry.Version; 21 | 22 | public interface PacketOut extends Packet { 23 | 24 | @Override 25 | default void decode(ByteMessage msg, Version version) { 26 | // Can be ignored for outgoing packets 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/protocol/PacketSnapshot.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.protocol; 19 | 20 | import ru.nanit.limbo.protocol.registry.Version; 21 | 22 | import java.util.HashMap; 23 | import java.util.Map; 24 | 25 | /** 26 | * PacketSnapshot encodes packet to byte array for each MC version. 27 | * Some versions have same snapshot, so there are mappings to avoid data copying 28 | */ 29 | public class PacketSnapshot implements PacketOut { 30 | 31 | private final PacketOut packet; 32 | private final Map versionMessages = new HashMap<>(); 33 | private final Map mappings = new HashMap<>(); 34 | 35 | public PacketSnapshot(PacketOut packet) { 36 | this.packet = packet; 37 | } 38 | 39 | public PacketOut getWrappedPacket() { 40 | return packet; 41 | } 42 | 43 | public void encode() { 44 | Map hashes = new HashMap<>(); 45 | 46 | for (Version version : Version.values()) { 47 | if (version.equals(Version.UNDEFINED)) continue; 48 | 49 | ByteMessage encodedMessage = ByteMessage.create(); 50 | packet.encode(encodedMessage, version); 51 | 52 | int hash = encodedMessage.hashCode(); 53 | Version hashed = hashes.get(hash); 54 | 55 | if (hashed != null) { 56 | mappings.put(version, hashed); 57 | } else { 58 | hashes.put(hash, version); 59 | mappings.put(version, version); 60 | versionMessages.put(version, encodedMessage.toByteArray()); 61 | } 62 | 63 | encodedMessage.release(); 64 | } 65 | } 66 | 67 | @Override 68 | public void encode(ByteMessage msg, Version version) { 69 | Version mapped = mappings.get(version); 70 | byte[] message = versionMessages.get(mapped); 71 | 72 | if (message != null) 73 | msg.writeBytes(message); 74 | else 75 | throw new IllegalArgumentException("No mappings for version " + version); 76 | } 77 | 78 | @Override 79 | public String toString() { 80 | return packet.getClass().getSimpleName(); 81 | } 82 | 83 | public static PacketSnapshot of(PacketOut packet) { 84 | PacketSnapshot snapshot = new PacketSnapshot(packet); 85 | snapshot.encode(); 86 | return snapshot; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/protocol/packets/PacketHandshake.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.protocol.packets; 19 | 20 | import ru.nanit.limbo.connection.ClientConnection; 21 | import ru.nanit.limbo.protocol.ByteMessage; 22 | import ru.nanit.limbo.protocol.PacketIn; 23 | import ru.nanit.limbo.protocol.registry.State; 24 | import ru.nanit.limbo.protocol.registry.Version; 25 | import ru.nanit.limbo.server.LimboServer; 26 | import ru.nanit.limbo.server.Logger; 27 | import ru.nanit.limbo.util.UuidUtil; 28 | 29 | public class PacketHandshake implements PacketIn { 30 | 31 | private Version version; 32 | private String host; 33 | private int port; 34 | private State nextState; 35 | 36 | public Version getVersion() { 37 | return version; 38 | } 39 | 40 | public String getHost() { 41 | return host; 42 | } 43 | 44 | public int getPort() { 45 | return port; 46 | } 47 | 48 | public State getNextState() { 49 | return nextState; 50 | } 51 | 52 | @Override 53 | public void decode(ByteMessage msg, Version version) { 54 | try { 55 | this.version = Version.of(msg.readVarInt()); 56 | } catch (IllegalArgumentException e) { 57 | this.version = Version.UNDEFINED; 58 | } 59 | 60 | this.host = msg.readString(); 61 | this.port = msg.readUnsignedShort(); 62 | this.nextState = State.getById(msg.readVarInt()); 63 | } 64 | 65 | @Override 66 | public String toString() { 67 | return getClass().getSimpleName(); 68 | } 69 | 70 | @Override 71 | public void handle(ClientConnection conn, LimboServer server) { 72 | server.getPacketHandler().handle(conn, this); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/protocol/packets/login/PacketDisconnect.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.protocol.packets.login; 19 | 20 | import ru.nanit.limbo.protocol.ByteMessage; 21 | import ru.nanit.limbo.protocol.PacketOut; 22 | import ru.nanit.limbo.protocol.registry.Version; 23 | 24 | public class PacketDisconnect implements PacketOut { 25 | 26 | private String reason; 27 | 28 | public void setReason(String reason) { 29 | this.reason = reason; 30 | } 31 | 32 | @Override 33 | public void encode(ByteMessage msg, Version version) { 34 | msg.writeString(String.format("{\"text\": \"%s\"}", reason)); 35 | } 36 | 37 | @Override 38 | public String toString() { 39 | return getClass().getSimpleName(); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/protocol/packets/login/PacketLoginPluginRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.protocol.packets.login; 19 | 20 | import io.netty.buffer.ByteBuf; 21 | import ru.nanit.limbo.protocol.ByteMessage; 22 | import ru.nanit.limbo.protocol.PacketOut; 23 | import ru.nanit.limbo.protocol.registry.Version; 24 | 25 | public class PacketLoginPluginRequest implements PacketOut { 26 | 27 | private int messageId; 28 | private String channel; 29 | private ByteBuf data; 30 | 31 | public void setMessageId(int messageId) { 32 | this.messageId = messageId; 33 | } 34 | 35 | public void setChannel(String channel) { 36 | this.channel = channel; 37 | } 38 | 39 | public void setData(ByteBuf data) { 40 | this.data = data; 41 | } 42 | 43 | @Override 44 | public void encode(ByteMessage msg, Version version) { 45 | msg.writeVarInt(messageId); 46 | msg.writeString(channel); 47 | msg.writeBytes(data); 48 | } 49 | 50 | @Override 51 | public String toString() { 52 | return getClass().getSimpleName(); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/protocol/packets/login/PacketLoginPluginResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.protocol.packets.login; 19 | 20 | import ru.nanit.limbo.connection.ClientConnection; 21 | import ru.nanit.limbo.protocol.ByteMessage; 22 | import ru.nanit.limbo.protocol.PacketIn; 23 | import ru.nanit.limbo.protocol.registry.Version; 24 | import ru.nanit.limbo.server.LimboServer; 25 | 26 | public class PacketLoginPluginResponse implements PacketIn { 27 | 28 | private int messageId; 29 | private boolean successful; 30 | private ByteMessage data; 31 | 32 | public int getMessageId() { 33 | return messageId; 34 | } 35 | 36 | public boolean isSuccessful() { 37 | return successful; 38 | } 39 | 40 | public ByteMessage getData() { 41 | return data; 42 | } 43 | 44 | @Override 45 | public void decode(ByteMessage msg, Version version) { 46 | messageId = msg.readVarInt(); 47 | successful = msg.readBoolean(); 48 | 49 | if (msg.readableBytes() > 0) { 50 | int i = msg.readableBytes(); 51 | data = new ByteMessage(msg.readBytes(i)); 52 | } 53 | } 54 | 55 | @Override 56 | public void handle(ClientConnection conn, LimboServer server) { 57 | server.getPacketHandler().handle(conn, this); 58 | } 59 | 60 | @Override 61 | public String toString() { 62 | return getClass().getSimpleName(); 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/protocol/packets/login/PacketLoginStart.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.protocol.packets.login; 19 | 20 | import ru.nanit.limbo.connection.ClientConnection; 21 | import ru.nanit.limbo.protocol.ByteMessage; 22 | import ru.nanit.limbo.protocol.PacketIn; 23 | import ru.nanit.limbo.protocol.registry.Version; 24 | import ru.nanit.limbo.server.LimboServer; 25 | 26 | public class PacketLoginStart implements PacketIn { 27 | 28 | private String username; 29 | 30 | public String getUsername() { 31 | return username; 32 | } 33 | 34 | @Override 35 | public void decode(ByteMessage msg, Version version) { 36 | this.username = msg.readString(); 37 | } 38 | 39 | @Override 40 | public void handle(ClientConnection conn, LimboServer server) { 41 | server.getPacketHandler().handle(conn, this); 42 | } 43 | 44 | @Override 45 | public String toString() { 46 | return getClass().getSimpleName(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/protocol/packets/login/PacketLoginSuccess.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.protocol.packets.login; 19 | 20 | import ru.nanit.limbo.protocol.ByteMessage; 21 | import ru.nanit.limbo.protocol.PacketOut; 22 | import ru.nanit.limbo.protocol.registry.Version; 23 | 24 | import java.util.UUID; 25 | 26 | public class PacketLoginSuccess implements PacketOut { 27 | 28 | private UUID uuid; 29 | private String username; 30 | 31 | public void setUuid(UUID uuid) { 32 | this.uuid = uuid; 33 | } 34 | 35 | public void setUsername(String username) { 36 | this.username = username; 37 | } 38 | 39 | @Override 40 | public void encode(ByteMessage msg, Version version) { 41 | if (version.moreOrEqual(Version.V1_16)) { 42 | msg.writeUuid(uuid); 43 | } else { 44 | msg.writeString(uuid.toString()); 45 | } 46 | msg.writeString(username); 47 | if (version.moreOrEqual(Version.V1_19)) { 48 | msg.writeVarInt(0); 49 | } 50 | } 51 | 52 | @Override 53 | public String toString() { 54 | return getClass().getSimpleName(); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/protocol/packets/play/PacketBossBar.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.protocol.packets.play; 19 | 20 | import ru.nanit.limbo.protocol.ByteMessage; 21 | import ru.nanit.limbo.protocol.PacketOut; 22 | import ru.nanit.limbo.protocol.registry.Version; 23 | import ru.nanit.limbo.server.data.BossBar; 24 | 25 | import java.util.UUID; 26 | 27 | /** 28 | * Packet for 1.9+ 29 | */ 30 | public class PacketBossBar implements PacketOut { 31 | 32 | private UUID uuid; 33 | private BossBar bossBar; 34 | private int flags; 35 | 36 | public void setUuid(UUID uuid) { 37 | this.uuid = uuid; 38 | } 39 | 40 | public void setBossBar(BossBar bossBar) { 41 | this.bossBar = bossBar; 42 | } 43 | 44 | public void setFlags(int flags) { 45 | this.flags = flags; 46 | } 47 | 48 | @Override 49 | public void encode(ByteMessage msg, Version version) { 50 | msg.writeUuid(uuid); 51 | msg.writeVarInt(0); // Create bossbar 52 | msg.writeString(bossBar.getText()); 53 | msg.writeFloat(bossBar.getHealth()); 54 | msg.writeVarInt(bossBar.getColor().getIndex()); 55 | msg.writeVarInt(bossBar.getDivision().getIndex()); 56 | msg.writeByte(flags); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/protocol/packets/play/PacketChatMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.protocol.packets.play; 19 | 20 | import ru.nanit.limbo.connection.ClientConnection; 21 | import ru.nanit.limbo.protocol.ByteMessage; 22 | import ru.nanit.limbo.protocol.PacketIn; 23 | import ru.nanit.limbo.protocol.PacketOut; 24 | import ru.nanit.limbo.protocol.registry.Version; 25 | import ru.nanit.limbo.server.LimboServer; 26 | 27 | import java.nio.charset.StandardCharsets; 28 | import java.util.Arrays; 29 | import java.util.UUID; 30 | 31 | public class PacketChatMessage implements PacketOut{ 32 | 33 | private String jsonData; 34 | private PositionLegacy position; 35 | private UUID sender; 36 | 37 | public void setJsonData(String jsonData) { 38 | this.jsonData = jsonData; 39 | } 40 | 41 | public void setPosition(PositionLegacy position) { 42 | this.position = position; 43 | } 44 | 45 | public void setSender(UUID sender) { 46 | this.sender = sender; 47 | } 48 | 49 | @Override 50 | public void encode(ByteMessage msg, Version version) { 51 | msg.writeString(jsonData); 52 | if (version.moreOrEqual(Version.V1_19_1)) { 53 | msg.writeBoolean(position.index == PositionLegacy.ACTION_BAR.index); 54 | } 55 | else if (version.moreOrEqual(Version.V1_19)) { 56 | msg.writeVarInt(position.index); 57 | } 58 | else { 59 | msg.writeByte(position.index); 60 | } 61 | 62 | if (version.moreOrEqual(Version.V1_16) && version.less(Version.V1_19)) 63 | msg.writeUuid(sender); 64 | } 65 | 66 | public enum PositionLegacy { 67 | 68 | CHAT(0), 69 | SYSTEM_MESSAGE(1), 70 | ACTION_BAR(2); 71 | 72 | private final int index; 73 | 74 | PositionLegacy(int index) { 75 | this.index = index; 76 | } 77 | 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/protocol/packets/play/PacketDeclareCommands.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.protocol.packets.play; 19 | 20 | import ru.nanit.limbo.protocol.ByteMessage; 21 | import ru.nanit.limbo.protocol.PacketOut; 22 | import ru.nanit.limbo.protocol.registry.Version; 23 | 24 | import java.util.List; 25 | 26 | /** 27 | * Packet for 1.13+ 28 | */ 29 | public class PacketDeclareCommands implements PacketOut { 30 | 31 | private List commands; 32 | 33 | public void setCommands(List commands) { 34 | this.commands = commands; 35 | } 36 | 37 | @Override 38 | public void encode(ByteMessage msg, Version version) { 39 | msg.writeVarInt(commands.size() * 2 + 1); // +1 because declaring root node 40 | 41 | // Declare root node 42 | 43 | msg.writeByte(0); 44 | msg.writeVarInt(commands.size()); 45 | 46 | for (int i = 1; i <= commands.size() * 2; i++) { 47 | msg.writeVarInt(i++); 48 | } 49 | 50 | // Declare other commands 51 | 52 | int i = 1; 53 | for (String cmd : commands) { 54 | msg.writeByte(1 | 0x04); 55 | msg.writeVarInt(1); 56 | msg.writeVarInt(i + 1); 57 | msg.writeString(cmd); 58 | i++; 59 | 60 | msg.writeByte(2 | 0x04 | 0x10); 61 | msg.writeVarInt(1); 62 | msg.writeVarInt(i); 63 | msg.writeString("arg"); 64 | msg.writeString("brigadier:string"); 65 | msg.writeVarInt(0); 66 | msg.writeString("minecraft:ask_server"); 67 | i++; 68 | } 69 | 70 | msg.writeVarInt(0); 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/protocol/packets/play/PacketKeepAlive.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.protocol.packets.play; 19 | 20 | import ru.nanit.limbo.protocol.ByteMessage; 21 | import ru.nanit.limbo.protocol.Packet; 22 | import ru.nanit.limbo.protocol.registry.Version; 23 | 24 | public class PacketKeepAlive implements Packet { 25 | 26 | private long id; 27 | 28 | public long getId() { 29 | return id; 30 | } 31 | 32 | public void setId(long id) { 33 | this.id = id; 34 | } 35 | 36 | @Override 37 | public void encode(ByteMessage msg, Version version) { 38 | if (version.moreOrEqual(Version.V1_12_2)) { 39 | msg.writeLong(id); 40 | } else { 41 | msg.writeVarInt((int) id); 42 | } 43 | } 44 | 45 | @Override 46 | public void decode(ByteMessage msg, Version version) { 47 | if (version.moreOrEqual(Version.V1_12_2)) { 48 | this.id = msg.readLong(); 49 | } else { 50 | this.id = msg.readVarInt(); 51 | } 52 | } 53 | 54 | @Override 55 | public String toString() { 56 | return getClass().getSimpleName(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/protocol/packets/play/PacketPlayerAbilities.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.protocol.packets.play; 19 | 20 | import ru.nanit.limbo.protocol.ByteMessage; 21 | import ru.nanit.limbo.protocol.PacketOut; 22 | import ru.nanit.limbo.protocol.registry.Version; 23 | 24 | public class PacketPlayerAbilities implements PacketOut { 25 | 26 | private int flags = 0x02; 27 | private float flyingSpeed = 0.0F; 28 | private float fieldOfView = 0.1F; 29 | 30 | public void setFlags(int flags) { 31 | this.flags = flags; 32 | } 33 | 34 | public void setFlyingSpeed(float flyingSpeed) { 35 | this.flyingSpeed = flyingSpeed; 36 | } 37 | 38 | public void setFieldOfView(float fieldOfView) { 39 | this.fieldOfView = fieldOfView; 40 | } 41 | 42 | @Override 43 | public void encode(ByteMessage msg, Version version) { 44 | msg.writeByte(flags); 45 | msg.writeFloat(flyingSpeed); 46 | msg.writeFloat(fieldOfView); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/protocol/packets/play/PacketPlayerInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.protocol.packets.play; 19 | 20 | import ru.nanit.limbo.protocol.ByteMessage; 21 | import ru.nanit.limbo.protocol.PacketOut; 22 | import ru.nanit.limbo.protocol.registry.Version; 23 | 24 | import java.util.UUID; 25 | 26 | /** 27 | * This packet was very simplified and using only for ADD_PLAYER action 28 | */ 29 | public class PacketPlayerInfo implements PacketOut { 30 | 31 | private int gameMode = 3; 32 | private String username = ""; 33 | private UUID uuid; 34 | 35 | public void setGameMode(int gameMode) { 36 | this.gameMode = gameMode; 37 | } 38 | 39 | public void setUsername(String username) { 40 | this.username = username; 41 | } 42 | 43 | public void setUuid(UUID uuid) { 44 | this.uuid = uuid; 45 | } 46 | 47 | @Override 48 | public void encode(ByteMessage msg, Version version) { 49 | msg.writeVarInt(0); // Add player action 50 | msg.writeVarInt(1); 51 | msg.writeUuid(uuid); 52 | msg.writeString(username); 53 | msg.writeVarInt(0); 54 | msg.writeVarInt(gameMode); 55 | msg.writeVarInt(60); 56 | msg.writeBoolean(false); 57 | if (version.moreOrEqual(Version.V1_19)) { 58 | msg.writeBoolean(false); 59 | } 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/protocol/packets/play/PacketPlayerListHeader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.protocol.packets.play; 19 | 20 | import ru.nanit.limbo.protocol.ByteMessage; 21 | import ru.nanit.limbo.protocol.PacketOut; 22 | import ru.nanit.limbo.protocol.registry.Version; 23 | 24 | public class PacketPlayerListHeader implements PacketOut { 25 | 26 | private String header; 27 | private String footer; 28 | 29 | public void setHeader(String header) { 30 | this.header = header; 31 | } 32 | 33 | public void setFooter(String footer) { 34 | this.footer = footer; 35 | } 36 | 37 | @Override 38 | public void encode(ByteMessage msg, Version version) { 39 | msg.writeString(header); 40 | msg.writeString(footer); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/protocol/packets/play/PacketPlayerPositionAndLook.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.protocol.packets.play; 19 | 20 | import ru.nanit.limbo.protocol.ByteMessage; 21 | import ru.nanit.limbo.protocol.PacketOut; 22 | import ru.nanit.limbo.protocol.registry.Version; 23 | 24 | public class PacketPlayerPositionAndLook implements PacketOut { 25 | 26 | private double x; 27 | private double y; 28 | private double z; 29 | private float yaw; 30 | private float pitch; 31 | private byte flags = 0x08; 32 | private int teleportId; 33 | 34 | public void setX(double x) { 35 | this.x = x; 36 | } 37 | 38 | public void setY(double y) { 39 | this.y = y; 40 | } 41 | 42 | public void setZ(double z) { 43 | this.z = z; 44 | } 45 | 46 | public void setYaw(float yaw) { 47 | this.yaw = yaw; 48 | } 49 | 50 | public void setPitch(float pitch) { 51 | this.pitch = pitch; 52 | } 53 | 54 | public void setFlags(byte flags) { 55 | this.flags = flags; 56 | } 57 | 58 | public void setTeleportId(int teleportId) { 59 | this.teleportId = teleportId; 60 | } 61 | 62 | @Override 63 | public void encode(ByteMessage msg, Version version) { 64 | msg.writeDouble(x); 65 | msg.writeDouble(y); 66 | msg.writeDouble(z); 67 | msg.writeFloat(yaw); 68 | msg.writeFloat(pitch); 69 | 70 | if (version.less(Version.V1_9)) { 71 | msg.writeBoolean(true); // On ground 72 | } else { 73 | msg.writeByte(flags); 74 | msg.writeVarInt(teleportId); 75 | } 76 | 77 | if (version.moreOrEqual(Version.V1_17)) { 78 | msg.writeBoolean(false); // Dismount vehicle 79 | } 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/protocol/packets/play/PacketPluginMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.protocol.packets.play; 19 | 20 | import ru.nanit.limbo.protocol.ByteMessage; 21 | import ru.nanit.limbo.protocol.PacketOut; 22 | import ru.nanit.limbo.protocol.registry.Version; 23 | 24 | public class PacketPluginMessage implements PacketOut { 25 | 26 | private String channel; 27 | private String message; 28 | 29 | public void setChannel(String channel) { 30 | this.channel = channel; 31 | } 32 | 33 | public void setMessage(String message) { 34 | this.message = message; 35 | } 36 | 37 | @Override 38 | public void encode(ByteMessage msg, Version version) { 39 | msg.writeString(channel); 40 | msg.writeString(message); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/protocol/packets/play/PacketTitleLegacy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.protocol.packets.play; 19 | 20 | import ru.nanit.limbo.protocol.ByteMessage; 21 | import ru.nanit.limbo.protocol.PacketOut; 22 | import ru.nanit.limbo.protocol.registry.Version; 23 | import ru.nanit.limbo.server.data.Title; 24 | 25 | public class PacketTitleLegacy implements PacketOut { 26 | 27 | private Action action; 28 | private final PacketTitleSetTitle title; 29 | private final PacketTitleSetSubTitle subtitle; 30 | private final PacketTitleTimes times; 31 | 32 | public PacketTitleLegacy() { 33 | this.title = new PacketTitleSetTitle(); 34 | this.subtitle = new PacketTitleSetSubTitle(); 35 | this.times = new PacketTitleTimes(); 36 | } 37 | 38 | public void setAction(Action action) { 39 | this.action = action; 40 | } 41 | 42 | public void setTitle(Title title) { 43 | this.title.setTitle(title.getTitle()); 44 | this.subtitle.setSubtitle(title.getSubtitle()); 45 | this.times.setFadeIn(title.getFadeIn()); 46 | this.times.setStay(title.getStay()); 47 | this.times.setFadeOut(title.getFadeOut()); 48 | } 49 | 50 | @Override 51 | public void encode(ByteMessage msg, Version version) { 52 | msg.writeVarInt(action.getId(version)); 53 | 54 | switch (action) { 55 | case SET_TITLE: 56 | title.encode(msg, version); 57 | break; 58 | case SET_SUBTITLE: 59 | subtitle.encode(msg, version); 60 | break; 61 | case SET_TIMES_AND_DISPLAY: 62 | times.encode(msg, version); 63 | break; 64 | default: 65 | throw new IllegalArgumentException("Invalid title action: " + action); 66 | } 67 | } 68 | 69 | public enum Action { 70 | SET_TITLE(0), 71 | SET_SUBTITLE(1), 72 | SET_TIMES_AND_DISPLAY(3, 2); 73 | 74 | private final int id; 75 | private final int legacyId; 76 | 77 | Action(int id, int legacyId) { 78 | this.id = id; 79 | this.legacyId = legacyId; 80 | } 81 | 82 | Action(int id) { 83 | this(id, id); 84 | } 85 | 86 | public int getId(Version version) { 87 | return version.less(Version.V1_11) ? legacyId : id; 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/protocol/packets/play/PacketTitleSetSubTitle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.protocol.packets.play; 19 | 20 | import ru.nanit.limbo.protocol.ByteMessage; 21 | import ru.nanit.limbo.protocol.PacketOut; 22 | import ru.nanit.limbo.protocol.registry.Version; 23 | 24 | public class PacketTitleSetSubTitle implements PacketOut { 25 | 26 | private String subtitle; 27 | 28 | public void setSubtitle(String subtitle) { 29 | this.subtitle = subtitle; 30 | } 31 | 32 | @Override 33 | public void encode(ByteMessage msg, Version version) { 34 | msg.writeString(subtitle); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/protocol/packets/play/PacketTitleSetTitle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.protocol.packets.play; 19 | 20 | import ru.nanit.limbo.protocol.ByteMessage; 21 | import ru.nanit.limbo.protocol.PacketOut; 22 | import ru.nanit.limbo.protocol.registry.Version; 23 | 24 | public class PacketTitleSetTitle implements PacketOut { 25 | 26 | private String title; 27 | 28 | public void setTitle(String title) { 29 | this.title = title; 30 | } 31 | 32 | @Override 33 | public void encode(ByteMessage msg, Version version) { 34 | msg.writeString(title); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/protocol/packets/play/PacketTitleTimes.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.protocol.packets.play; 19 | 20 | import ru.nanit.limbo.protocol.ByteMessage; 21 | import ru.nanit.limbo.protocol.PacketOut; 22 | import ru.nanit.limbo.protocol.registry.Version; 23 | 24 | public class PacketTitleTimes implements PacketOut { 25 | 26 | private int fadeIn; 27 | private int stay; 28 | private int fadeOut; 29 | 30 | public void setFadeIn(int fadeIn) { 31 | this.fadeIn = fadeIn; 32 | } 33 | 34 | public void setStay(int stay) { 35 | this.stay = stay; 36 | } 37 | 38 | public void setFadeOut(int fadeOut) { 39 | this.fadeOut = fadeOut; 40 | } 41 | 42 | @Override 43 | public void encode(ByteMessage msg, Version version) { 44 | msg.writeInt(fadeIn); 45 | msg.writeInt(stay); 46 | msg.writeInt(fadeOut); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/protocol/packets/status/PacketStatusPing.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.protocol.packets.status; 19 | 20 | import ru.nanit.limbo.connection.ClientConnection; 21 | import ru.nanit.limbo.protocol.ByteMessage; 22 | import ru.nanit.limbo.protocol.Packet; 23 | import ru.nanit.limbo.protocol.registry.Version; 24 | import ru.nanit.limbo.server.LimboServer; 25 | 26 | public class PacketStatusPing implements Packet { 27 | 28 | private long randomId; 29 | 30 | @Override 31 | public void encode(ByteMessage msg, Version version) { 32 | msg.writeLong(randomId); 33 | } 34 | 35 | @Override 36 | public void decode(ByteMessage msg, Version version) { 37 | this.randomId = msg.readLong(); 38 | } 39 | 40 | @Override 41 | public void handle(ClientConnection conn, LimboServer server) { 42 | server.getPacketHandler().handle(conn, this); 43 | } 44 | 45 | @Override 46 | public String toString() { 47 | return getClass().getSimpleName(); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/protocol/packets/status/PacketStatusRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.protocol.packets.status; 19 | 20 | import ru.nanit.limbo.connection.ClientConnection; 21 | import ru.nanit.limbo.protocol.ByteMessage; 22 | import ru.nanit.limbo.protocol.PacketIn; 23 | import ru.nanit.limbo.protocol.registry.Version; 24 | import ru.nanit.limbo.server.LimboServer; 25 | 26 | public class PacketStatusRequest implements PacketIn { 27 | 28 | @Override 29 | public void decode(ByteMessage msg, Version version) { 30 | 31 | } 32 | 33 | @Override 34 | public void handle(ClientConnection conn, LimboServer server) { 35 | server.getPacketHandler().handle(conn, this); 36 | } 37 | 38 | @Override 39 | public String toString() { 40 | return getClass().getSimpleName(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/protocol/packets/status/PacketStatusResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.protocol.packets.status; 19 | 20 | import ru.nanit.limbo.protocol.ByteMessage; 21 | import ru.nanit.limbo.protocol.PacketOut; 22 | import ru.nanit.limbo.protocol.registry.Version; 23 | import ru.nanit.limbo.server.LimboServer; 24 | 25 | public class PacketStatusResponse implements PacketOut { 26 | 27 | private static final String TEMPLATE = "{ \"version\": { \"name\": \"%s\", \"protocol\": %d }, \"players\": { \"max\": %d, \"online\": %d, \"sample\": [] }, \"description\": %s }"; 28 | 29 | private LimboServer server; 30 | 31 | public PacketStatusResponse() { } 32 | 33 | public PacketStatusResponse(LimboServer server) { 34 | this.server = server; 35 | } 36 | 37 | @Override 38 | public void encode(ByteMessage msg, Version version) { 39 | int protocol = server.getConfig().getInfoForwarding().isNone() 40 | ? version.getProtocolNumber() 41 | : Version.getMax().getProtocolNumber(); 42 | 43 | String ver = server.getConfig().getPingData().getVersion(); 44 | String desc = server.getConfig().getPingData().getDescription(); 45 | 46 | msg.writeString(getResponseJson(ver, protocol, 47 | server.getConfig().getMaxPlayers(), 48 | server.getConnections().getCount(), desc)); 49 | } 50 | 51 | @Override 52 | public String toString() { 53 | return getClass().getSimpleName(); 54 | } 55 | 56 | private String getResponseJson(String version, int protocol, int maxPlayers, int online, String description) { 57 | return String.format(TEMPLATE, version, protocol, maxPlayers, online, description); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/protocol/registry/Version.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.protocol.registry; 19 | 20 | import java.util.HashMap; 21 | import java.util.Map; 22 | 23 | public enum Version { 24 | 25 | UNDEFINED(-1), 26 | V1_8(47), 27 | // 1.8-1.8.8 has same protocol numbers 28 | V1_9(107), 29 | V1_9_1(108), 30 | V1_9_2(109), 31 | V1_9_4(110), 32 | V1_10(210), 33 | // 1.10-1.10.2 has same protocol numbers 34 | V1_11(315), 35 | V1_11_1(316), 36 | // 1.11.2 has same protocol number 37 | V1_12(335), 38 | V1_12_1(338), 39 | V1_12_2(340), 40 | V1_13(393), 41 | V1_13_1(401), 42 | V1_13_2(404), 43 | V1_14(477), 44 | V1_14_1(480), 45 | V1_14_2(485), 46 | V1_14_3(490), 47 | V1_14_4(498), 48 | V1_15(573), 49 | V1_15_1(575), 50 | V1_15_2(578), 51 | V1_16(735), 52 | V1_16_1(736), 53 | V1_16_2(751), 54 | V1_16_3(753), 55 | V1_16_4(754), 56 | // 1.16.5 has same protocol number 57 | V1_17(755), 58 | V1_17_1(756), 59 | V1_18(757), 60 | // 1.18.1 has same protocol number 61 | V1_18_2(758), 62 | V1_19(759), 63 | V1_19_1(760); 64 | 65 | private static final Map VERSION_MAP; 66 | private static final Version MAX; 67 | 68 | static { 69 | Version[] values = values(); 70 | 71 | VERSION_MAP = new HashMap<>(); 72 | MAX = values[values.length - 1]; 73 | 74 | Version last = null; 75 | for (Version version : values) { 76 | version.prev = last; 77 | last = version; 78 | VERSION_MAP.put(version.getProtocolNumber(), version); 79 | } 80 | } 81 | 82 | private final int protocolNumber; 83 | private Version prev; 84 | 85 | Version(int protocolNumber) { 86 | this.protocolNumber = protocolNumber; 87 | } 88 | 89 | public int getProtocolNumber() { 90 | return this.protocolNumber; 91 | } 92 | 93 | public Version getPrev() { 94 | return prev; 95 | } 96 | 97 | public boolean more(Version another) { 98 | return this.protocolNumber > another.protocolNumber; 99 | } 100 | 101 | public boolean moreOrEqual(Version another) { 102 | return this.protocolNumber >= another.protocolNumber; 103 | } 104 | 105 | public boolean less(Version another) { 106 | return this.protocolNumber < another.protocolNumber; 107 | } 108 | 109 | public boolean lessOrEqual(Version another) { 110 | return this.protocolNumber <= another.protocolNumber; 111 | } 112 | 113 | public boolean fromTo(Version min, Version max) { 114 | return this.protocolNumber >= min.protocolNumber && this.protocolNumber <= max.protocolNumber; 115 | } 116 | 117 | public boolean isSupported() { 118 | return this != UNDEFINED; 119 | } 120 | 121 | public static Version getMin() { 122 | return V1_8; 123 | } 124 | 125 | public static Version getMax() { 126 | return MAX; 127 | } 128 | 129 | public static Version of(int protocolNumber) { 130 | return VERSION_MAP.getOrDefault(protocolNumber, UNDEFINED); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/server/Command.java: -------------------------------------------------------------------------------- 1 | package ru.nanit.limbo.server; 2 | 3 | public interface Command { 4 | 5 | void execute(); 6 | 7 | String description(); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/server/CommandManager.java: -------------------------------------------------------------------------------- 1 | package ru.nanit.limbo.server; 2 | 3 | import ru.nanit.limbo.server.commands.CmdConn; 4 | import ru.nanit.limbo.server.commands.CmdHelp; 5 | import ru.nanit.limbo.server.commands.CmdMem; 6 | import ru.nanit.limbo.server.commands.CmdStop; 7 | 8 | import java.util.*; 9 | 10 | public final class CommandManager extends Thread { 11 | 12 | private final Map commands = new HashMap<>(); 13 | 14 | public Map getCommands() { 15 | return Collections.unmodifiableMap(commands); 16 | } 17 | 18 | public Command getCommand(String name) { 19 | return commands.get(name.toLowerCase()); 20 | } 21 | 22 | public void register(String name, Command cmd) { 23 | commands.put(name.toLowerCase(), cmd); 24 | } 25 | 26 | @Override 27 | public void run() { 28 | Scanner scanner = new Scanner(System.in); 29 | String command; 30 | 31 | while (true) { 32 | try { 33 | command = scanner.nextLine().trim(); 34 | } catch (NoSuchElementException e) { 35 | break; 36 | } 37 | 38 | Command handler = getCommand(command); 39 | 40 | if (handler != null) { 41 | try { 42 | handler.execute(); 43 | } catch (Throwable t) { 44 | Logger.error("Cannot execute command:", t); 45 | } 46 | continue; 47 | } 48 | 49 | Logger.info("Unknown command. Type \"help\" to get commands list"); 50 | } 51 | } 52 | 53 | public void registerAll(LimboServer server) { 54 | register("help", new CmdHelp(server)); 55 | register("conn", new CmdConn(server)); 56 | register("mem", new CmdMem()); 57 | register("stop", new CmdStop()); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/server/Connections.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.server; 19 | 20 | import cn.moonmc.limboAdd.works.event.EventManager; 21 | import cn.moonmc.limboAdd.works.event.playerEvent.PlayerConnectEvent; 22 | import cn.moonmc.limboAdd.works.event.playerEvent.PlayerQuitEvent; 23 | import ru.nanit.limbo.connection.ClientConnection; 24 | 25 | import java.util.Collection; 26 | import java.util.Collections; 27 | import java.util.Map; 28 | import java.util.UUID; 29 | import java.util.concurrent.ConcurrentHashMap; 30 | 31 | public final class Connections { 32 | 33 | private final Map connections; 34 | 35 | public Connections() { 36 | connections = new ConcurrentHashMap<>(); 37 | } 38 | 39 | public Collection getAllConnections() { 40 | return Collections.unmodifiableCollection(connections.values()); 41 | } 42 | 43 | public int getCount() { 44 | return connections.size(); 45 | } 46 | 47 | public void addConnection(ClientConnection connection) { 48 | connections.put(connection.getUuid(), connection); 49 | Logger.info("玩家 %s 加入服务器 (%s) [%s]", connection.getUsername(), 50 | connection.getAddress(), connection.getClientVersion()); 51 | EventManager.call(new PlayerConnectEvent(connection.getPlayer())); 52 | } 53 | 54 | public void removeConnection(ClientConnection connection) { 55 | connections.remove(connection.getUuid()); 56 | Logger.info("玩家 %s 离开服务器", connection.getUsername()); 57 | EventManager.call(new PlayerQuitEvent(connection.getPlayer())); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/server/Logger.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.server; 19 | 20 | import java.time.LocalTime; 21 | import java.time.format.DateTimeFormatter; 22 | 23 | public final class Logger { 24 | 25 | private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("hh:mm:ss"); 26 | private static int debugLevel = Level.INFO.getIndex(); 27 | 28 | private Logger() {} 29 | 30 | public static int getLevel() { 31 | return debugLevel; 32 | } 33 | 34 | public static void info(Object msg, Object... args) { 35 | print(Level.INFO, msg, null, args); 36 | } 37 | 38 | public static void debug(Object msg, Object... args) { 39 | print(Level.DEBUG, msg, null, args); 40 | } 41 | 42 | public static void warning(Object msg, Object... args) { 43 | print(Level.WARNING, msg, null, args); 44 | } 45 | 46 | public static void warning(Object msg, Throwable t, Object... args) { 47 | print(Level.WARNING, msg, t, args); 48 | } 49 | 50 | public static void error(Object msg, Object... args) { 51 | print(Level.ERROR, msg, null, args); 52 | } 53 | 54 | public static void error(Object msg, Throwable t, Object... args) { 55 | print(Level.ERROR, msg, t, args); 56 | } 57 | 58 | public static void print(Level level, Object msg, Throwable t, Object... args) { 59 | if (debugLevel >= level.getIndex()) { 60 | String log = String.format("%s: %s%n", getPrefix(level), String.format(msg.toString(), args)); 61 | System.out.print(getFormatLogString(log,level.getColor(),1)); 62 | if (t != null) t.printStackTrace(); 63 | } 64 | } 65 | /** 66 | * @param colour 颜色代号:背景颜色代号(41-46);前景色代号(31-36) 67 | * @param type 样式代号:0无;1加粗;3斜体;4下划线 68 | * @param content 要打印的内容 69 | */ 70 | private static String getFormatLogString(String content, int colour, int type) { 71 | boolean hasType = type != 1 && type != 3 && type != 4; 72 | if (hasType) { 73 | return String.format("\033[%dm%s\033[0m", colour, content); 74 | } else { 75 | return String.format("\033[%d;%dm%s\033[0m", colour, type, content); 76 | } 77 | } 78 | private static String getPrefix(Level level) { 79 | return String.format("[%s] [%s]", getTime(), level.getDisplay()); 80 | } 81 | 82 | private static String getTime() { 83 | return LocalTime.now().format(FORMATTER); 84 | } 85 | 86 | static void setLevel(int level) { 87 | debugLevel = level; 88 | } 89 | 90 | public enum Level { 91 | /** 92 | * 错误 93 | */ 94 | ERROR("ERROR", 0, 91), 95 | /** 96 | * 警告 97 | */ 98 | WARNING("WARNING", 1, 93), 99 | /** 100 | * 信息 101 | */ 102 | INFO("INFO", 2, 92), 103 | /** 104 | * 调试 105 | */ 106 | DEBUG("DEBUG", 3, 94); 107 | 108 | private final String display; 109 | private final int index; 110 | private final int color; 111 | 112 | Level(String display, int index, int color) { 113 | this.display = display; 114 | this.index = index; 115 | this.color = color; 116 | } 117 | 118 | public String getDisplay() { 119 | return display; 120 | } 121 | 122 | public int getIndex() { 123 | return index; 124 | } 125 | 126 | public int getColor() { 127 | return color; 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/server/commands/CmdConn.java: -------------------------------------------------------------------------------- 1 | package ru.nanit.limbo.server.commands; 2 | 3 | import ru.nanit.limbo.server.Command; 4 | import ru.nanit.limbo.server.LimboServer; 5 | import ru.nanit.limbo.server.Logger; 6 | 7 | public class CmdConn implements Command { 8 | 9 | private final LimboServer server; 10 | 11 | public CmdConn(LimboServer server) { 12 | this.server = server; 13 | } 14 | 15 | @Override 16 | public void execute() { 17 | Logger.info("连接数: %d", server.getConnections().getCount()); 18 | } 19 | 20 | @Override 21 | public String description() { 22 | return "显示连接数"; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/server/commands/CmdHelp.java: -------------------------------------------------------------------------------- 1 | package ru.nanit.limbo.server.commands; 2 | 3 | import ru.nanit.limbo.server.Command; 4 | import ru.nanit.limbo.server.LimboServer; 5 | import ru.nanit.limbo.server.Logger; 6 | 7 | import java.util.Map; 8 | 9 | public class CmdHelp implements Command { 10 | 11 | private final LimboServer server; 12 | 13 | public CmdHelp(LimboServer server) { 14 | this.server = server; 15 | } 16 | 17 | @Override 18 | public void execute() { 19 | Map commands = server.getCommandManager().getCommands(); 20 | 21 | Logger.info("可用命令:"); 22 | 23 | for (Map.Entry entry : commands.entrySet()) { 24 | Logger.info("%s - %s", entry.getKey(), entry.getValue().description()); 25 | } 26 | } 27 | 28 | @Override 29 | public String description() { 30 | return "帮助"; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/server/commands/CmdMem.java: -------------------------------------------------------------------------------- 1 | package ru.nanit.limbo.server.commands; 2 | 3 | import ru.nanit.limbo.server.Command; 4 | import ru.nanit.limbo.server.Logger; 5 | 6 | public class CmdMem implements Command { 7 | 8 | @Override 9 | public void execute() { 10 | Runtime runtime = Runtime.getRuntime(); 11 | long mb = 1024 * 1024; 12 | long used = (runtime.totalMemory() - runtime.freeMemory()) / mb; 13 | long total = runtime.totalMemory() / mb; 14 | long free = runtime.freeMemory() / mb; 15 | long max = runtime.maxMemory() / mb; 16 | 17 | Logger.info("内存使用情况:"); 18 | Logger.info("使用中: %d MB", used); 19 | Logger.info("已申请: %d MB", total); 20 | Logger.info("剩余: %d MB", free); 21 | Logger.info("最大: %d MB", max); 22 | } 23 | 24 | @Override 25 | public String description() { 26 | return "显示内存使用情况"; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/server/commands/CmdStop.java: -------------------------------------------------------------------------------- 1 | package ru.nanit.limbo.server.commands; 2 | 3 | import ru.nanit.limbo.server.Command; 4 | 5 | public class CmdStop implements Command { 6 | 7 | @Override 8 | public void execute() { 9 | System.exit(0); 10 | } 11 | 12 | @Override 13 | public String description() { 14 | return "关闭服务器"; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/server/data/BossBar.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.server.data; 19 | 20 | import org.checkerframework.checker.nullness.qual.Nullable; 21 | import org.spongepowered.configurate.ConfigurationNode; 22 | import org.spongepowered.configurate.serialize.SerializationException; 23 | import org.spongepowered.configurate.serialize.TypeSerializer; 24 | import ru.nanit.limbo.util.Colors; 25 | 26 | import java.lang.reflect.Type; 27 | 28 | public class BossBar { 29 | 30 | private String text; 31 | private float health; 32 | private Color color; 33 | private Division division; 34 | 35 | public String getText() { 36 | return text; 37 | } 38 | 39 | public float getHealth() { 40 | return health; 41 | } 42 | 43 | public Color getColor() { 44 | return color; 45 | } 46 | 47 | public Division getDivision() { 48 | return division; 49 | } 50 | 51 | public void setText(String text) { 52 | this.text = text; 53 | } 54 | 55 | public void setHealth(float health) { 56 | this.health = health; 57 | } 58 | 59 | public void setColor(Color color) { 60 | this.color = color; 61 | } 62 | 63 | public void setDivision(Division division) { 64 | this.division = division; 65 | } 66 | 67 | public enum Color { 68 | 69 | PINK(0), 70 | BLUE(1), 71 | RED(2), 72 | GREEN(3), 73 | YELLOW(4), 74 | PURPLE(5), 75 | WHITE(6); 76 | 77 | private final int index; 78 | 79 | Color(int index) { 80 | this.index = index; 81 | } 82 | 83 | public int getIndex() { 84 | return index; 85 | } 86 | } 87 | 88 | public enum Division { 89 | 90 | SOLID(0), 91 | DASHES_6(1), 92 | DASHES_10(2), 93 | DASHES_12(3), 94 | DASHES_20(4); 95 | 96 | private final int index; 97 | 98 | Division(int index) { 99 | this.index = index; 100 | } 101 | 102 | public int getIndex() { 103 | return index; 104 | } 105 | } 106 | 107 | public static class Serializer implements TypeSerializer { 108 | 109 | @Override 110 | public BossBar deserialize(Type type, ConfigurationNode node) throws SerializationException { 111 | BossBar bossBar = new BossBar(); 112 | 113 | bossBar.setText(Colors.of(node.node("text").getString(""))); 114 | bossBar.setHealth(node.node("health").getFloat()); 115 | 116 | if (bossBar.getHealth() < 0 || bossBar.getHealth() > 1) 117 | throw new SerializationException("BossBar health value must be between 0.0 and 1.0"); 118 | 119 | try { 120 | bossBar.setColor(Color.valueOf(node.node("color").getString("").toUpperCase())); 121 | } catch (IllegalArgumentException e) { 122 | throw new SerializationException("Invalid bossbar color"); 123 | } 124 | 125 | try { 126 | bossBar.setDivision(Division.valueOf(node.node("division").getString("").toUpperCase())); 127 | } catch (IllegalArgumentException e) { 128 | throw new SerializationException("Invalid bossbar division"); 129 | } 130 | 131 | return bossBar; 132 | } 133 | 134 | @Override 135 | public void serialize(Type type, @Nullable BossBar obj, ConfigurationNode node) { 136 | 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/server/data/InfoForwarding.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.server.data; 19 | 20 | import org.checkerframework.checker.nullness.qual.Nullable; 21 | import org.spongepowered.configurate.ConfigurationNode; 22 | import org.spongepowered.configurate.serialize.SerializationException; 23 | import org.spongepowered.configurate.serialize.TypeSerializer; 24 | 25 | import java.nio.charset.StandardCharsets; 26 | import java.util.List; 27 | 28 | public class InfoForwarding { 29 | 30 | private Type type; 31 | private byte[] secretKey; 32 | private List tokens; 33 | 34 | public Type getType() { 35 | return type; 36 | } 37 | 38 | public byte[] getSecretKey() { 39 | return secretKey; 40 | } 41 | 42 | public List getTokens() { 43 | return tokens; 44 | } 45 | 46 | public boolean hasToken(String token) { 47 | return tokens != null && token != null && tokens.contains(token); 48 | } 49 | 50 | public boolean isNone() { 51 | return type == Type.NONE; 52 | } 53 | 54 | public boolean isLegacy() { 55 | return type == Type.LEGACY; 56 | } 57 | 58 | public boolean isModern() { 59 | return type == Type.MODERN; 60 | } 61 | 62 | public boolean isBungeeGuard() { 63 | return type == Type.BUNGEE_GUARD; 64 | } 65 | 66 | public enum Type { 67 | NONE, 68 | LEGACY, 69 | MODERN, 70 | BUNGEE_GUARD 71 | } 72 | 73 | public static class Serializer implements TypeSerializer { 74 | 75 | @Override 76 | public InfoForwarding deserialize(java.lang.reflect.Type type, ConfigurationNode node) throws SerializationException { 77 | InfoForwarding forwarding = new InfoForwarding(); 78 | 79 | try { 80 | forwarding.type = Type.valueOf(node.node("type").getString("").toUpperCase()); 81 | } catch (IllegalArgumentException e) { 82 | throw new SerializationException("Undefined info forwarding type"); 83 | } 84 | 85 | if (forwarding.type == Type.MODERN) { 86 | forwarding.secretKey = node.node("secret").getString("").getBytes(StandardCharsets.UTF_8); 87 | } 88 | 89 | if (forwarding.type == Type.BUNGEE_GUARD) { 90 | forwarding.tokens = node.node("tokens").getList(String.class); 91 | } 92 | 93 | return forwarding; 94 | } 95 | 96 | @Override 97 | public void serialize(java.lang.reflect.Type type, @Nullable InfoForwarding obj, ConfigurationNode node) throws SerializationException { 98 | 99 | } 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/server/data/PingData.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.server.data; 19 | 20 | import org.checkerframework.checker.nullness.qual.Nullable; 21 | import org.spongepowered.configurate.ConfigurationNode; 22 | import org.spongepowered.configurate.serialize.TypeSerializer; 23 | import ru.nanit.limbo.util.Colors; 24 | 25 | import java.lang.reflect.Type; 26 | 27 | public class PingData { 28 | 29 | private String version; 30 | private String description; 31 | 32 | public String getVersion() { 33 | return version; 34 | } 35 | 36 | public void setVersion(String version) { 37 | this.version = version; 38 | } 39 | 40 | public String getDescription() { 41 | return description; 42 | } 43 | 44 | public void setDescription(String description) { 45 | this.description = description; 46 | } 47 | 48 | public static class Serializer implements TypeSerializer { 49 | 50 | @Override 51 | public PingData deserialize(Type type, ConfigurationNode node) { 52 | PingData pingData = new PingData(); 53 | pingData.setDescription(Colors.of(node.node("description").getString(""))); 54 | pingData.setVersion(Colors.of(node.node("version").getString(""))); 55 | return pingData; 56 | } 57 | 58 | @Override 59 | public void serialize(Type type, @Nullable PingData obj, ConfigurationNode node) { 60 | 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/server/data/Title.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | package ru.nanit.limbo.server.data; 19 | 20 | import org.checkerframework.checker.nullness.qual.Nullable; 21 | import org.spongepowered.configurate.ConfigurationNode; 22 | import org.spongepowered.configurate.serialize.TypeSerializer; 23 | import ru.nanit.limbo.util.Colors; 24 | 25 | import java.lang.reflect.Type; 26 | 27 | public class Title { 28 | 29 | private String title; 30 | private String subtitle; 31 | private int fadeIn; 32 | private int stay; 33 | private int fadeOut; 34 | 35 | public String getTitle() { 36 | return title; 37 | } 38 | 39 | public String getSubtitle() { 40 | return subtitle; 41 | } 42 | 43 | public int getFadeIn() { 44 | return fadeIn; 45 | } 46 | 47 | public int getStay() { 48 | return stay; 49 | } 50 | 51 | public int getFadeOut() { 52 | return fadeOut; 53 | } 54 | 55 | public void setTitle(String title) { 56 | this.title = title; 57 | } 58 | 59 | public void setSubtitle(String subtitle) { 60 | this.subtitle = subtitle; 61 | } 62 | 63 | public void setFadeIn(int fadeIn) { 64 | this.fadeIn = fadeIn; 65 | } 66 | 67 | public void setStay(int stay) { 68 | this.stay = stay; 69 | } 70 | 71 | public void setFadeOut(int fadeOut) { 72 | this.fadeOut = fadeOut; 73 | } 74 | 75 | public static class Serializer implements TypeSerializer { 76 | 77 | @Override 78 | public Title deserialize(Type type, ConfigurationNode node) { 79 | Title title = new Title(); 80 | title.setTitle(Colors.of(node.node("title").getString(""))); 81 | title.setSubtitle(Colors.of(node.node("subtitle").getString(""))); 82 | title.setFadeIn(node.node("fadeIn").getInt(10)); 83 | title.setStay(node.node("stay").getInt(100)); 84 | title.setFadeOut(node.node("fadeOut").getInt(10)); 85 | return title; 86 | } 87 | 88 | @Override 89 | public void serialize(Type type, @Nullable Title obj, ConfigurationNode node) { 90 | // Not used 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/util/Colors.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see <https://www.gnu.org/licenses/>. 16 | */ 17 | 18 | package ru.nanit.limbo.util; 19 | 20 | public final class Colors { 21 | 22 | private static final char CHAR_FROM = '&'; 23 | private static final char CHAR_TO = '\u00a7'; 24 | 25 | private Colors() { 26 | } 27 | 28 | public static String of(String text) { 29 | if (text == null) return null; 30 | return text.replace(CHAR_FROM, CHAR_TO); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/util/UuidUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see <https://www.gnu.org/licenses/>. 16 | */ 17 | 18 | package ru.nanit.limbo.util; 19 | 20 | import java.nio.charset.StandardCharsets; 21 | import java.util.UUID; 22 | 23 | public final class UuidUtil { 24 | 25 | private UuidUtil() {} 26 | 27 | public static UUID getOfflineModeUuid(String username) { 28 | return UUID.nameUUIDFromBytes(("OfflinePlayer:" + username) 29 | .getBytes(StandardCharsets.UTF_8)); 30 | } 31 | 32 | public static UUID fromString(String str) { 33 | if(str.contains("-")) return UUID.fromString(str); 34 | return UUID.fromString(str.replaceFirst("(\\p{XDigit}{8})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}+)", "$1-$2-$3-$4-$5")); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/world/Location.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see <https://www.gnu.org/licenses/>. 16 | */ 17 | 18 | package ru.nanit.limbo.world; 19 | 20 | import org.checkerframework.checker.nullness.qual.Nullable; 21 | import org.spongepowered.configurate.ConfigurationNode; 22 | import org.spongepowered.configurate.serialize.TypeSerializer; 23 | 24 | import java.lang.reflect.Type; 25 | 26 | public class Location { 27 | 28 | private final double x; 29 | private final double y; 30 | private final double z; 31 | private final float yaw; 32 | private final float pitch; 33 | 34 | Location(double x, double y, double z, float yaw, float pitch) { 35 | this.x = x; 36 | this.y = y; 37 | this.z = z; 38 | this.yaw = yaw; 39 | this.pitch = pitch; 40 | } 41 | 42 | Location(double x, double y, double z) { 43 | this(x, y, z, 0.0F, 0.0F); 44 | } 45 | 46 | public double getX() { 47 | return x; 48 | } 49 | 50 | public int getBlockX() { 51 | return (int) x; 52 | } 53 | 54 | public double getY() { 55 | return y; 56 | } 57 | 58 | public int getBlockY() { 59 | return (int) y; 60 | } 61 | 62 | public double getZ() { 63 | return z; 64 | } 65 | 66 | public int getBlockZ() { 67 | return (int) z; 68 | } 69 | 70 | public float getYaw() { 71 | return yaw; 72 | } 73 | 74 | public float getPitch() { 75 | return pitch; 76 | } 77 | 78 | public static Location of(double x, double y, double z) { 79 | return new Location(x, y, z); 80 | } 81 | 82 | public static Location of(double x, double y, double z, float yaw, float pitch) { 83 | return new Location(x, y, z, yaw, pitch); 84 | } 85 | 86 | public static Location pos(int x, int y, int z) { 87 | return new Location(x, y, z); 88 | } 89 | 90 | public static class Serializer implements TypeSerializer<Location> { 91 | 92 | @Override 93 | public Location deserialize(Type type, ConfigurationNode node) { 94 | double x = node.node("x").getDouble(0); 95 | double y = node.node("y").getDouble(0); 96 | double z = node.node("z").getDouble(0); 97 | float yaw = node.node("yaw").getFloat(0.0F); 98 | float pitch = node.node("pitch").getFloat(0.0F); 99 | 100 | return new Location(x, y, z, yaw, pitch); 101 | } 102 | 103 | @Override 104 | public void serialize(Type type, @Nullable Location obj, ConfigurationNode node) { } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/ru/nanit/limbo/world/dimension/Dimension.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Nan1t 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see <https://www.gnu.org/licenses/>. 16 | */ 17 | 18 | package ru.nanit.limbo.world.dimension; 19 | 20 | import net.kyori.adventure.nbt.CompoundBinaryTag; 21 | 22 | public class Dimension { 23 | 24 | private final int id; 25 | private final String name; 26 | private final CompoundBinaryTag data; 27 | 28 | public Dimension(int id, String name, CompoundBinaryTag data) { 29 | this.id = id; 30 | this.name = name; 31 | this.data = data; 32 | } 33 | 34 | public int getId() { 35 | return id; 36 | } 37 | 38 | public String getName() { 39 | return name; 40 | } 41 | 42 | public CompoundBinaryTag getData() { 43 | return data; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/resources/ServerEula.json: -------------------------------------------------------------------------------- 1 | [ 2 | {"paragraphs":[{"text":"服规《服务器法则手册》\n核心观念:禁止以下行为\n游戏作弊 不尊重他人 故意卡服 不爱惜服务器\n推广第三方 引流第三方 不珍惜游玩资格\n服主态度:\n对于君子 以礼相待\n对于小人 更加小人\n\n请继续阅读本条例后面的内容,阅读完成后即可注册。"},{"text":"\n\n§c§l拒绝服规,退出服务器\n","hoverEvent":{"text":"点击即认为您拒绝以上服务器条例,\n并且拒绝遵守服务器规则\n您可以在下次进入服务器时重新选择"},"clickEvent":{"command":"{quit_command}"}}]}, 3 | {"paragraphs":[{"text":"【服务器法则手册】\n更新日期2021年7月17日\n《服务器法则手册》以下简称“法律手册”\n在你开始游玩本服务器之前,请确认您已认真阅读本“法律手册”,并已经完全了解和同意本法律手册的条款。否则你应该拒绝游玩本服!如果你对服务器法律和条款有建议,欢迎提出!\n"}]}, 4 | {"paragraphs":[{"text":"法律手册的意义:国有国法,家有家规,服有服规,无规则不成方圆。为了给大家带来更好的游戏体验,保证服务器的和平公正,这一切都是为了给大家带来更好的游戏体验,才特设此法律手册。"}]}, 5 | {"paragraphs":[{"text":"重要提醒:\n\n服务器法律会不定时更新,请随时注意官网play.moonmc.cn的公示!保证你已阅读最新版“法律手册”。发现违规者请及时举报,知情不报将视为同罪。服务器鼓励玩家举报违法违规行为。可以使用截图,视频录制等方法,把违规违法资料发到官网,并联系在线管理员以解决"}]}, 6 | {"paragraphs":[{"text":"服务器装有监控插件,使用指令/co i可以查询记录,举报者将获得罚款的60%作为报酬,可匿名举报。服务器法则为玩家必看,管理有权在不通知的前提下直接处罚违规玩家。罚款可以作为管理的私有财产以做奖励。本服处罚只认违规ID,请各位保管好自己的账号。自首可以从轻处罚或免于处罚。"}]}, 7 | {"paragraphs":[{"text":"帮好友自首也可以减免处罚!手册内规定罚款无法偿还的,按10w游戏币=1天计算。服主享有本法则的解释权。"}]}, 8 | {"paragraphs":[{"text":"一.破坏游戏平衡(作弊/辅助)违规\n作为一款以原版生存为主要玩法的服务器,拒绝任何利用,外挂软件/插件漏洞/程序/游戏漏洞/辅助等,破坏正常游戏平衡的行为。有相关(使用作弊工具等)违规行为被视为非平衡游戏违规。处30天至永久封禁,罚款25w至无 上限的惩罚。"}]}, 9 | {"paragraphs":[{"text":"二.干扰他人游戏体验违规\n作为以多人游戏为基础的生存服务器,玩家之间的信息及交流与游戏体验尤为重要,有破坏,干扰,影响,他人正常游戏及游戏成果包括但不限于(破坏建筑,未经允许击杀其他玩家,盗窃,骗取,言语攻击其他玩家等)行为被视为干扰他人游戏体验违规。处1小时至永久封禁,罚款1w-400w不等。 禁言1分钟至720小时不等,清空或收回非正常所得的一切"}]}, 10 | {"paragraphs":[{"text":"利益,须尽力恢复受害者受侵害的部分。"}]}, 11 | {"paragraphs":[{"text":"三.破坏服务器运行违规\n因服务器应用限制,服务器负载有限,使用任何形式干扰服务器的流畅运行,干扰他人游戏体验,在管理警告三次后无作为继续侵害的。视为破坏服务器运行违规。每一名玩家都必须知道什么行为是破坏服务器稳定运行的行为,并制止这种行为。在服务器里不知不等于无罪。处1天至永久封禁不等,罚款10w-1300w不等,及恢复非法侵害行为等。"}]}, 12 | {"paragraphs":[{"text":"四.违规推流引流\n本服拒绝任何形式在游戏内发布商业信息,包括但不限于:视频连接,直播连接,正版代购,购物消费,其它服务器。尤其是庄主已经运营或即将运营的项目。无论是商业还是非商业形式的。有发现以任何形式推流引流或其他商业非商业行为的,视为违规推流引流。处封禁1天至永久封禁,罚款5w-5000w不等.及禁言1小时-无上限等。"}]}, 13 | {"paragraphs":[{"text":"五.虚拟财产套现货币(人民币及其它法定货币)违规\n以任何形式(包括但不限于骗取、偷取、赌博、买卖、集资套取、高利贷、非法借贷、游戏内道具、游戏金币、游戏权限、游戏账号等)与其他玩家换取货币的行为。无论最终获利者为谁,实行行为的侵犯者,都将视为非法手段获取货币违规。处封禁30天至永久封禁,罚款涉案金额*1.5倍~3值的赔偿。"}]}, 14 | {"paragraphs":[{"text":"注:请各位玩家保管好自己的游戏资产及私人财产安全,利用服务器与其他玩家进行货币交易或进行赌博的行为,本服务器有义务进行监管和向有关部门举报,所造成的损失与服务器无关。"}]}, 15 | {"paragraphs":[{"text":" 六.管理员法\n 请各位管理员严格按照服规秉公执法,每个执法都要有服规条款的支持。不能封禁玩家超过30天。永久封号的需提交给服主处理! 对于新玩家和首犯,管理员应以劝导为主,或从轻处罚!\n ●保证不公报私仇\n ●保证不情绪化执法\n ●保证不以个人意愿代替服规\n ●保证执法量刑参考《服务器案例 》"}]}, 16 | {"paragraphs":[{"text":"前往注册\n"},{"text":"§6§l同意服规,前往注册\n","hoverEvent":{"text":"点击即认为您同意以上服务器条例,\n并且同意遵守服务器规则"},"clickEvent":{"command":"{reg_command}"}},{"text":"§c§l拒绝服规,退出服务器\n","hoverEvent":{"text":"点击即认为您拒绝以上服务器条例,\n并且拒绝遵守服务器规则\n您可以在下次进入服务器时重新选择"},"clickEvent":{"command":"{quit_command}"}}]} 17 | ] -------------------------------------------------------------------------------- /src/main/resources/chooseServerBook.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "text": "§6————————§d§l选择服务器§6————————\n\n\n" 3 | },{ 4 | "text": " ————>生存服务器<———— \n\n", 5 | "clickEvent": { 6 | "action": "run_command", 7 | "value": "/gogo 生存" 8 | }, 9 | "hoverEvent": { 10 | "action": "show_text", 11 | "value": "进入生存服务器" 12 | } 13 | }, { 14 | "text": " ————>创造服务器<———— \n\n", 15 | "clickEvent": { 16 | "action": "run_command", 17 | "value": "/gogo 创造" 18 | }, 19 | "hoverEvent": { 20 | "action": "show_text", 21 | "value": "进入创造服务器" 22 | } 23 | }] -------------------------------------------------------------------------------- /src/main/resources/dimension/codec_old.snbt: -------------------------------------------------------------------------------- 1 | { 2 | "dimension": [ 3 | { 4 | name: "minecraft:overworld", 5 | id: 0, 6 | piglin_safe: 0b, 7 | natural: 1b, 8 | ambient_light: 0.0f, 9 | infiniburn: "minecraft:infiniburn_overworld", 10 | respawn_anchor_works: 0b, 11 | has_skylight: 1b, 12 | bed_works: 1b, 13 | shrunk: 0, 14 | effects: "minecraft:overworld", 15 | has_raids: 1b, 16 | min_y: 0, 17 | height: 256, 18 | logical_height: 256, 19 | coordinate_scale: 1.0d, 20 | ultrawarm: 0b, 21 | has_ceiling: 0b 22 | }, 23 | { 24 | name: "minecraft:overworld_caves", 25 | id: 1, 26 | piglin_safe: 0b, 27 | natural: 1b, 28 | shrunk: 0, 29 | ambient_light: 0.0f, 30 | infiniburn: "minecraft:infiniburn_overworld", 31 | respawn_anchor_works: 0b, 32 | has_skylight: 1b, 33 | bed_works: 1b, 34 | effects: "minecraft:overworld", 35 | has_raids: 1b, 36 | min_y: 0, 37 | height: 256, 38 | logical_height: 256, 39 | coordinate_scale: 1.0d, 40 | ultrawarm: 0b, 41 | has_ceiling: 1b 42 | }, 43 | { 44 | name: "minecraft:the_nether", 45 | id: 2, 46 | piglin_safe: 1b, 47 | natural: 0b, 48 | shrunk: 0, 49 | ambient_light: 0.1f, 50 | infiniburn: "minecraft:infiniburn_nether", 51 | respawn_anchor_works: 1b, 52 | has_skylight: 0b, 53 | bed_works: 0b, 54 | effects: "minecraft:the_nether", 55 | fixed_time: 18000L, 56 | has_raids: 0b, 57 | min_y: 0, 58 | height: 256, 59 | logical_height: 128, 60 | coordinate_scale: 8.0d, 61 | ultrawarm: 1b, 62 | has_ceiling: 1b 63 | }, 64 | { 65 | name: "minecraft:the_end", 66 | id: 3, 67 | piglin_safe: 0b, 68 | natural: 0b, 69 | ambient_light: 0.0f, 70 | infiniburn: "minecraft:infiniburn_end", 71 | respawn_anchor_works: 0b, 72 | has_skylight: 0b, 73 | shrunk: 0, 74 | bed_works: 0b, 75 | effects: "minecraft:the_end", 76 | fixed_time: 6000L, 77 | has_raids: 1b, 78 | min_y: 0, 79 | height: 256, 80 | logical_height: 256, 81 | coordinate_scale: 1.0d, 82 | ultrawarm: 0b, 83 | has_ceiling: 0b 84 | } 85 | ] 86 | } 87 | -------------------------------------------------------------------------------- /src/main/resources/loginDataBase.properties: -------------------------------------------------------------------------------- 1 | dataSourceClassName=com.mysql.cj.jdbc.MysqlDataSource 2 | dataSource.user=root 3 | dataSource.password=root 4 | dataSource.databaseName=works 5 | dataSource.portNumber=3306 6 | dataSource.serverName=localhost -------------------------------------------------------------------------------- /src/main/resources/settings.yml: -------------------------------------------------------------------------------- 1 | aliYun: 2 | ak : "ak" 3 | sk : "sk" 4 | sign : "sign" 5 | template_bind : "SMS_10086" 6 | template_resetPassword : "SMS_10010" 7 | 8 | # 9 | # NanoLimbo 配置 10 | # 11 | 12 | # 服务器的地址和端口. 设置ip为空使用本机ip地址 13 | bind: 14 | ip: 'localhost' 15 | port: 65535 16 | 17 | # 最多可加入的玩家数量 18 | # 设置为 -1 不限制玩家数量 19 | maxPlayers: 100 20 | 21 | # 服务器列表中显示的信息 22 | ping: 23 | description: '{"text": "&9NanoLimbo"}' 24 | version: 'NanoLimbo' 25 | 26 | # 可用的世界类型: OVERWORLD, NETHER, THE_END 27 | dimension: THE_END 28 | 29 | # 是否在玩家列表中显示玩家 30 | # 在1.16.5中无法关闭此功能,为了防止客户端无法正常工作。 31 | playerList: 32 | enable: false 33 | username: 'NanoLimbo' 34 | 35 | # 是否在玩家列表中显示页眉和页脚 36 | headerAndFooter: 37 | enable: false 38 | header: '{"text": "&eWelcome!"}' 39 | footer: '{"text": "&9NanoLimbo"}' 40 | 41 | # 出生点设置 42 | spawnPosition: 43 | 'x': 0.0 44 | 'y': 400.0 45 | 'z': 0.0 46 | 'yaw': 0.0 47 | 'pitch': 0.0 48 | 49 | # 玩家的游戏模式 50 | # 0 - 生存 51 | # 1 - 创造 52 | # 2 - 冒险 53 | # 3 - 旁观者 54 | gameMode: 0 55 | 56 | # F3中显示的服务器名称 57 | brandName: 58 | enable: true 59 | content: 'NanoLimbo' 60 | 61 | # 玩家加入服务器时发送的消息 62 | joinMessage: 63 | enable: true 64 | text: '{"text": "&eWelcome to the Limbo!"}' 65 | 66 | # 玩家加入时显示boos血条 67 | # 只能在1.9版本以上工作 68 | bossBar: 69 | enable: true 70 | text: '{"text": "Welcome to the Limbo!"}' 71 | health: 1.0 72 | # A血条颜色: PINK, BLUE, RED, GREEN, YELLOW, PURPLE, WHITE 73 | color: PINK 74 | # 血条分割线: SOLID, DASHES_6, DASHES_10, DASHES_12, DASHES_20 75 | division: SOLID 76 | 77 | # 显示标题和副标题 78 | title: 79 | enable: false 80 | # 如果只显示主标题请将 subtitle 设置为空 81 | title: '{"text": "&9&lWelcome!"}' 82 | # 如果只显示副标题,请将 title 设置为空 83 | subtitle: '{"text": "&6NanoLimbo"}' 84 | # 淡入时间 (1秒 = 20 ticks) 85 | fadeIn: 10 86 | # 显示时间 87 | stay: 100 88 | # 淡出时间 89 | fadeOut: 10 90 | 91 | # 玩家信息转发支持 92 | # 可用类型: 93 | # - NONE 94 | # - LEGACY 95 | # - MODERN 96 | # - BUNGEE_GUARD 97 | # 如果你使用 MODERN ,请不要加密 98 | infoForwarding: 99 | type: NONE 100 | secret: '<YOUR_SECRET_HERE>' 101 | tokens: 102 | - '<BUNGEE_GUARD_TOKEN>' 103 | 104 | # 连接超时时间 (毫秒) 105 | readTimeout: 30000 106 | 107 | # 日志级别. 如果在生产环境, 我建议使用2级 108 | # 日志级别: 109 | # 0 - 只显示 errors 110 | # 1 - 显示 errors, warnings 111 | # 2 - 显示 errors, warnings, info 112 | # 3 - 显示 errors, warnings, info, debug 113 | debugLevel: 2 114 | 115 | # 如果你不知道这是什么,请不要修改 116 | netty: 117 | # Use Linux native transport type, if it possible 118 | useEpoll: true 119 | # EventLoopGroup threads count 120 | threads: 121 | bossGroup: 1 122 | workerGroup: 4 -------------------------------------------------------------------------------- /src/test/java/pattern.java: -------------------------------------------------------------------------------- 1 | import java.util.regex.Matcher; 2 | import java.util.regex.Pattern; 3 | 4 | /** 5 | * @author CNLuminous 2022/10/30 6 | */ 7 | public class pattern { 8 | public static void main(String[] args) { 9 | String name = "^^^^12122aa"; 10 | String pattern = "[A-Za-z0-9_]{3,15}"; 11 | Pattern r = Pattern.compile(pattern); 12 | Matcher m = r.matcher(name); 13 | if (!m.matches()){ 14 | System.out.println("不匹配"); 15 | }else{ 16 | System.out.println("匹配"); 17 | } 18 | 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/生成uuid.java: -------------------------------------------------------------------------------- 1 | import com.zaxxer.hikari.HikariConfig; 2 | import com.zaxxer.hikari.HikariDataSource; 3 | import ru.nanit.limbo.util.UuidUtil; 4 | 5 | import java.sql.Connection; 6 | import java.sql.PreparedStatement; 7 | import java.sql.ResultSet; 8 | import java.sql.SQLException; 9 | import java.util.UUID; 10 | 11 | public class 生成uuid { 12 | static HikariDataSource hikariDataSource; 13 | public static void main(String[] args) { 14 | HikariConfig hikariConfig = new HikariConfig(); 15 | hikariConfig.setUsername("root"); 16 | hikariConfig.setPassword("root"); 17 | hikariConfig.setJdbcUrl("jdbc:mysql://127.0.0.1/works"); 18 | hikariDataSource = new HikariDataSource(hikariConfig); 19 | 20 | try (Connection connection = hikariDataSource.getConnection()){ 21 | ResultSet resultSet = connection.createStatement().executeQuery(""" 22 | SELECT authme.realname,authme.`password`,users.phone_number,authme.ip 23 | FROM authme,users 24 | WHERE authme.realname = users.player_name; 25 | """); 26 | while (resultSet.next()) { 27 | user( 28 | resultSet.getString(1), 29 | resultSet.getString(2), 30 | resultSet.getString(3), 31 | resultSet.getString(4) 32 | ); 33 | } 34 | } catch (SQLException e) { 35 | throw new RuntimeException(e); 36 | } 37 | } 38 | 39 | private static void user(String name, String password, String phone, String ip) { 40 | UUID uuid = UuidUtil.getOfflineModeUuid(name); 41 | System.out.print(uuid); 42 | System.out.print(" "); 43 | System.out.print(name); 44 | System.out.print(" "); 45 | System.out.print(password); 46 | System.out.print(" "); 47 | System.out.print(phone); 48 | System.out.print(" "); 49 | System.out.println(ip); 50 | 51 | try ( 52 | Connection c = hikariDataSource.getConnection(); 53 | PreparedStatement p = c.prepareStatement("insert into user(uuid,name,password,phone,ip) values (?,?,?,?,?)"); 54 | ){ 55 | p.setString(1,uuid.toString()); 56 | p.setString(2,name); 57 | p.setString(3,password); 58 | p.setString(4,phone); 59 | p.setString(5,ip); 60 | p.executeLargeUpdate(); 61 | } catch (SQLException e) { 62 | throw new RuntimeException(e); 63 | } 64 | 65 | } 66 | } 67 | --------------------------------------------------------------------------------