1 /* 2 * Copyright (c) 2017-2018 sel-project 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a copy 5 * of this software and associated documentation files (the "Software"), to deal 6 * in the Software without restriction, including without limitation the rights 7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 * copies of the Software, and to permit persons to whom the Software is 9 * furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in all 12 * copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 * SOFTWARE. 21 * 22 */ 23 /** 24 * Copyright: 2017-2018 sel-project 25 * License: MIT 26 * Authors: Kripth 27 * Source: $(HTTP github.com/sel-project/selery/source/selery/config.d, selery/config.d) 28 */ 29 module selery.config; 30 31 import std.algorithm : canFind, min; 32 import std.conv : to; 33 import std.file : exists, isFile, read, write; 34 import std.json : JSONValue; 35 import std.path : dirSeparator; 36 import std.random : uniform; 37 import std.socket : getAddress; 38 import std.string : indexOf, startsWith, endsWith; 39 import std.uuid : UUID, randomUUID; 40 41 import selery.about; 42 import selery.lang : LanguageManager; 43 44 enum Gamemode : ubyte { 45 46 survival = 0, s = 0, 47 creative = 1, c = 1, 48 adventure = 2, a = 2, 49 spectator = 3, sp = 3, 50 51 } 52 53 enum Difficulty : ubyte { 54 55 peaceful = 0, 56 easy = 1, 57 normal = 2, 58 hard = 3, 59 60 } 61 62 enum Dimension : ubyte { 63 64 overworld = 0, 65 nether = 1, 66 end = 2, 67 68 } 69 70 /** 71 * Configuration for the server. 72 */ 73 class Config { 74 75 UUID uuid; 76 77 Files files; 78 LanguageManager lang; 79 80 Hub hub; 81 Node node; 82 83 public this(UUID uuid=randomUUID()) { 84 this.uuid = uuid; 85 } 86 87 /** 88 * Configuration for the hub. 89 */ 90 class Hub { 91 92 static struct Address { 93 94 string ip; 95 ushort port; 96 97 inout string toString() { 98 return (this.ip.canFind(":") ? "[" ~ this.ip ~ "]" : this.ip) ~ ":" ~ this.port.to!string; 99 } 100 101 } 102 103 static struct Game { 104 105 bool enabled; 106 string motd; 107 bool onlineMode; 108 Address[] addresses; 109 uint[] protocols; 110 111 alias enabled this; 112 113 } 114 115 bool edu; 116 117 string displayName = "A Minecraft Server"; 118 119 Game bedrock = Game(true, "A Minecraft Server", false, [Address("0.0.0.0", 19132)], latestBedrockProtocols); 120 121 Game java = Game(true, "A Minecraft Server", false, [Address("0.0.0.0", 25565)], latestJavaProtocols); 122 123 bool allowVanillaPlayers = false; 124 125 bool query = true; 126 127 string serverIp; 128 129 string favicon = "favicon.png"; 130 131 bool rcon = false; 132 133 string rconPassword; 134 135 Address[] rconAddresses = [Address("0.0.0.0", 25575)]; 136 137 bool webView = false; 138 139 Address[] webViewAddresses = [Address("0.0.0.0", 80), Address("::", 80)]; 140 141 bool webAdmin = false; 142 143 bool webAdminOpen; 144 145 Address[] webAdminAddresses = [Address("127.0.0.1", 19134)]; 146 147 string webAdminPassword = ""; 148 149 uint webAdminMaxClients = 1; 150 151 JSONValue social; 152 153 string[] acceptedNodes; 154 155 string hncomPassword; 156 157 uint maxNodes = 0; 158 159 ushort hncomPort = 28232; 160 161 public this() { 162 163 string randomPassword() { 164 char[] password = new char[uniform!"[]"(8, 12)]; 165 foreach(ref char c ; password) { 166 c = uniform!"[]"('a', 'z'); 167 if(!uniform!"[]"(0, 4)) c -= 32; 168 } 169 return password.idup; 170 } 171 172 if(lang !is null) { 173 this.displayName = this.java.motd = this.bedrock.motd = (){ 174 switch(lang.language[0..min(cast(size_t)lang.language.indexOf("_"), $)]) { 175 case "es": return "Un Servidor de Minecraft"; 176 case "it": return "Un Server di Minecraft"; 177 case "pt": return "Um Servidor de Minecraft"; 178 default: return "A Minecraft Server"; 179 } 180 }(); 181 } 182 183 this.rconPassword = randomPassword(); 184 185 this.acceptedNodes ~= getAddress("localhost")[0].toAddrString(); 186 } 187 188 } 189 190 /** 191 * Configuration for the node. 192 */ 193 class Node { 194 195 static struct Game { 196 197 bool enabled; 198 uint[] protocols; 199 200 alias enabled this; 201 202 } 203 204 string name = "node"; 205 206 string password = ""; 207 208 string ip; 209 210 ushort port = 28232; 211 212 bool main = true; 213 214 Game java = Game(true, latestJavaProtocols); 215 216 Game bedrock = Game(true, latestBedrockProtocols); 217 218 uint maxPlayers = 20; 219 220 uint gamemode = Gamemode.survival; 221 222 uint difficulty = Difficulty.normal; 223 224 bool depleteHunger = true; 225 226 bool doDaylightCycle = true; 227 228 bool doEntityDrops = true; 229 230 bool doFireTick = true; 231 232 bool doScheduledTicks = true; 233 234 bool doWeatherCycle = true; 235 236 bool naturalRegeneration = true; 237 238 bool pvp = true; 239 240 uint randomTickSpeed = 3; 241 242 uint viewDistance = 10; 243 244 bool aboutCommand = true; 245 246 bool clearCommand = true; 247 248 bool cloneCommand = true; 249 250 bool defaultgamemodeCommand = true; 251 252 bool deopCommand = true; 253 254 bool difficultyCommand = true; 255 256 bool effectCommand = true; 257 258 bool enchantCommand = true; 259 260 bool experienceCommand = true; 261 262 bool executeCommand = true; 263 264 bool fillCommand = true; 265 266 bool gamemodeCommand = true; 267 268 bool gameruleCommand = true; 269 270 bool giveCommand = true; 271 272 bool helpCommand = true; 273 274 bool kickCommand = true; 275 276 bool killCommand = true; 277 278 bool listCommand = true; 279 280 bool locateCommand = true; 281 282 bool meCommand = true; 283 284 bool opCommand = true; 285 286 bool permissionCommand = true; 287 288 bool sayCommand = true; 289 290 bool seedCommand = true; 291 292 bool setmaxplayersCommand = true; 293 294 bool setworldspawnCommand = true; 295 296 bool spawnpointCommand = true; 297 298 bool stopCommand = true; 299 300 bool summonCommand = true; 301 302 bool titleCommand = true; 303 304 bool tellCommand = true; 305 306 bool timeCommand = true; 307 308 bool toggledownfallCommand = true; 309 310 bool tpCommand = true; 311 312 bool transferCommand = true; 313 314 bool transferserverCommand = true; 315 316 bool weatherCommand = true; 317 318 bool worldCommand = true; 319 320 public this() { 321 322 this.ip = getAddress("localhost")[0].toAddrString(); 323 324 } 325 326 } 327 328 /** 329 * Loads the configuration for the first time. 330 */ 331 public void load() {} 332 333 /** 334 * Reloads the configuration. 335 */ 336 public void reload() {} 337 338 /** 339 * Saves the configuration. 340 */ 341 public void save() {} 342 343 } 344 345 /** 346 * File manager for assets and temp files. 347 */ 348 class Files { 349 350 public immutable string assets; 351 public immutable string temp; 352 353 public this(string assets, string temp) { 354 if(!assets.endsWith(dirSeparator)) assets ~= dirSeparator; 355 this.assets = assets; 356 if(!temp.endsWith(dirSeparator)) temp ~= dirSeparator; 357 this.temp = temp; 358 } 359 360 /** 361 * Indicates whether an asset exists. 362 * Returns: true if the asset exists, false otherwise 363 */ 364 public inout bool hasAsset(string file) { 365 return exists(this.assets ~ file) && isFile(this.assets ~ file); 366 } 367 368 /** 369 * Reads the content of an asset. 370 * Throws: FileException if the file cannot be found. 371 */ 372 public inout void[] readAsset(string file) { 373 return read(this.assets ~ file); 374 } 375 376 /** 377 * Indicates whether a temp file exists. 378 */ 379 public inout bool hasTemp(string file) { 380 return exists(this.temp ~ temp) && isFile(this.temp ~ file); 381 } 382 383 /** 384 * Reads the content of a temp file. 385 */ 386 public inout void[] readTemp(string file) { 387 return read(this.temp ~ file); 388 } 389 390 /** 391 * Writes buffer to a temp file. 392 */ 393 public inout void writeTemp(string file, const(void)[] buffer) { 394 return write(this.temp ~ file, buffer); 395 } 396 397 } 398 399 //TODO move to selery/lang.d 400 public string bestLanguage(string lang, string[] accepted) { 401 if(accepted.canFind(lang)) return lang; 402 string similar = lang[0..lang.indexOf("_")+1]; 403 foreach(al ; accepted) { 404 if(al.startsWith(similar)) return al; 405 } 406 return accepted.canFind("en_GB") ? "en_GB" : accepted[0]; 407 }