1 /* 2 * Copyright (c) 2017-2019 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: Copyright (c) 2017-2019 sel-project 25 * License: MIT 26 * Authors: Kripth 27 * Source: $(HTTP github.com/sel-project/selery/source/selery/enchantment/enchantment.d, selery/enchantment/enchantment.d) 28 */ 29 module selery.enchantment.enchantment; 30 31 import std.algorithm : min; 32 import std.conv : to; 33 import std.regex : ctRegex, replaceAll; 34 import std..string : toLower, replace, startsWith; 35 36 import roman : fromRoman; 37 38 static import sel.data.enchantment; 39 import sel.data.enchantment : Enchantments; 40 41 /** 42 * Class that represents an enchantment and its level. 43 * Example: 44 * --- 45 * auto e = new Enchantment(Enchantments.sharpness, "V"); 46 * Enchantment.fromString("luck of the sea", 5); 47 * assert(e.bedrock && e.bedrock.id == 9); 48 * assert(e.minecraft.id == 16); 49 * assert(!Enchantment.fromMinecraft(71).pocket); 50 * --- 51 */ 52 final class Enchantment { 53 54 private static const(sel.data.enchantment.Enchantment)[string] strings; 55 private static const(sel.data.enchantment.Enchantment)[ubyte] _java, _bedrock; 56 57 public static this() { 58 foreach(e ; __traits(allMembers, Enchantments)) { 59 mixin("alias ench = Enchantments." ~ e ~ ";"); 60 strings[ench.name.replace(" ", "_")] = ench; 61 if(ench.java) _java[ench.java.id] = ench; 62 if(ench.bedrock) _bedrock[ench.bedrock.id] = ench; 63 } 64 } 65 66 /** 67 * Creates an enchantment from a string. 68 * Example: 69 * --- 70 * Enchantment.fromString("sharpness", 1); 71 * Enchantment.fromString("Fire Protection", 4); 72 * Enchantment.fromString("silk-touch", 1); 73 * Enchantment.fromString("minecraft:protection", 2); 74 * --- 75 */ 76 public static @safe Enchantment fromString(string name, ubyte level) { 77 if(name.startsWith("minecraft:")) name = name[10..$]; 78 auto ret = name.toLower.replaceAll(ctRegex!`[ \-]`, "_") in strings; 79 return ret ? new Enchantment(*ret, level) : null; 80 } 81 82 /** 83 * Creates an enchantment using its Minecraft: Java Edition's id. 84 * Example: 85 * --- 86 * assert(Enchantment.fromJava(9, 1).name == "frost walker"); 87 * --- 88 */ 89 public static @safe Enchantment fromJava(ubyte id, ubyte level) { 90 auto ret = id in _java; 91 return ret ? new Enchantment(*ret, level) : null; 92 } 93 94 /** 95 * Creates an enchantment using its Minecraft's id. 96 * Example: 97 * --- 98 * assert(Enchantment.fromBedrock(9, 2).name == "sharpness"); 99 * --- 100 */ 101 public static @safe Enchantment fromBedrock(ubyte id, ubyte level) { 102 auto ret = id in _bedrock; 103 return ret ? new Enchantment(*ret, level) : null; 104 } 105 106 public const sel.data.enchantment.Enchantment enchantment; 107 public immutable ubyte level; 108 109 public pure nothrow @safe @nogc this(sel.data.enchantment.Enchantment enchantment, ubyte level) { 110 this.enchantment = enchantment; 111 this.level = level == 0 ? ubyte(1) : level; 112 } 113 114 public @safe this(sel.data.enchantment.Enchantment enchantment, string level) { 115 this(enchantment, level.fromRoman & 255); 116 } 117 118 /** 119 * Gets the enchantment's id. SEL currently uses Minecraft's 120 * id to uniquely identify an enchantment. 121 * Example: 122 * --- 123 * auto e = Enchantment.fromString("sharpness", 5); 124 * assert(e.id == e.minecraft.id); 125 * --- 126 */ 127 public pure nothrow @property @safe @nogc ubyte id() { 128 return this.enchantment.java.id; 129 } 130 131 public override bool opEquals(Object o) { 132 auto e = cast(Enchantment)o; 133 return e !is null && this.id == e.id && this.level == e.level; 134 } 135 136 alias enchantment this; 137 138 } 139 140 /** 141 * Exception thrown when an enchantment does not exist 142 * or is used in the wrong way. 143 */ 144 class EnchantmentException : Exception { 145 146 public @safe this(string message, string file=__FILE__, size_t line=__LINE__) { 147 super(message, file, line); 148 } 149 150 }