001package net.tnemc.item.component.impl; 002/* 003 * The New Item Library 004 * Copyright (C) 2022 - 2025 Daniel "creatorfromhell" Vidmar 005 * 006 * This program is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 3 of the License, or (at your option) any later version. 010 * 011 * This program is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public License 017 * along with this program; if not, write to the Free Software Foundation, 018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 019 */ 020 021import net.tnemc.item.AbstractItemStack; 022import net.tnemc.item.JSONHelper; 023import net.tnemc.item.component.SerialComponent; 024import net.tnemc.item.component.helper.DamageReduction; 025import net.tnemc.item.component.helper.ItemDamage; 026import net.tnemc.item.platform.ItemPlatform; 027import org.json.simple.JSONArray; 028import org.json.simple.JSONObject; 029 030import java.util.ArrayList; 031import java.util.Arrays; 032import java.util.List; 033import java.util.Objects; 034 035/** 036 * BlocksAttacksComponent - When present, this item can be used like a Shield to block attacks to the 037 * holding player. Added in MC 1.21.5 038 * 039 * @author creatorfromhell 040 * @see <a href="https://minecraft.wiki/w/Data_component_format#blocks_attacks">Reference</a> 041 * <p> 042 * @since 0.2.0.0 043 */ 044public abstract class BlocksAttacksComponent<I extends AbstractItemStack<T>, T> implements SerialComponent<I, T> { 045 046 protected final List<DamageReduction> reductions = new ArrayList<>(); 047 048 protected final List<String> bypassedBy = new ArrayList<>(); 049 050 protected ItemDamage itemDamage = null; 051 052 //The number of seconds that right-click must be held before successfully blocking attacks 053 protected float blockDelay = 0; 054 055 //Multiplier applied to the number of seconds that the item will be on cooldown for when attacked 056 //by a disabling attack (disable_blocking_for_seconds on the weapon component) 057 //If 0, this item can never be disabled by attacks 058 protected float disableCooldownScale = 1; 059 060 protected String blockSound = ""; 061 062 protected String disableSound = ""; 063 064 public BlocksAttacksComponent() { 065 066 } 067 068 /** 069 * @return the type of component this is. 070 * @since 0.2.0.0 071 */ 072 @Override 073 public String identifier() { 074 075 return "blocks_attacks"; 076 } 077 078 /** 079 * Converts the {@link SerialComponent} to a JSON object. 080 * 081 * @return The JSONObject representing this {@link SerialComponent}. 082 * @since 0.2.0.0 083 */ 084 @Override 085 public JSONObject toJSON() { 086 087 final JSONObject json = new JSONObject(); 088 089 //Serialize DamageReductions 090 final JSONArray reductionsArray = new JSONArray(); 091 for(final DamageReduction reduction : reductions) { 092 093 final JSONObject reductionJson = new JSONObject(); 094 reductionJson.put("type", reduction.type()); 095 reductionJson.put("base", reduction.base()); 096 reductionJson.put("factor", reduction.factor()); 097 reductionJson.put("horizontalBlockingAngle", reduction.horizontalBlockingAngle()); 098 reductionsArray.add(reductionJson); 099 } 100 json.put("reductions", reductionsArray); 101 102 103 //Serialize bypassedBy 104 final JSONArray bypassedByArray = new JSONArray(); 105 for(final String bypassedBy : bypassedBy) { 106 107 bypassedByArray.add(bypassedBy); 108 } 109 json.put("bypassedBy", bypassedByArray); 110 111 // Serialize ItemDamage 112 if(itemDamage != null) { 113 114 final JSONObject itemDamageJson = new JSONObject(); 115 116 itemDamageJson.put("threshold", itemDamage.threshold()); 117 itemDamageJson.put("base", itemDamage.base()); 118 itemDamageJson.put("factor", itemDamage.factor()); 119 json.put("item_damage", itemDamageJson); 120 } 121 122 // Serialize other properties 123 json.put("block_delay", blockDelay); 124 json.put("disable_cooldown_scale", disableCooldownScale); 125 json.put("block_sound", blockSound); 126 json.put("disable_sound", disableSound); 127 128 return json; 129 } 130 131 /** 132 * Reads JSON data and converts it back to a {@link SerialComponent} object. 133 * 134 * @param json The JSONHelper instance of the json data. 135 * @since 0.2.0.0 136 */ 137 @Override 138 public void readJSON(final JSONHelper json, final ItemPlatform<I, T, ?> platform) { 139 140 //Deserialize DamageReductions 141 final JSONArray reductionsArray = (JSONArray)json.getObject().get("reductions"); 142 reductions.clear(); 143 144 if(reductionsArray != null) { 145 146 for(final Object obj : reductionsArray) { 147 148 final JSONObject reductionJson = (JSONObject)obj; 149 final String type = reductionJson.get("type").toString(); 150 final float base = Float.parseFloat(reductionJson.get("base").toString()); 151 final float factor = Float.parseFloat(reductionJson.get("factor").toString()); 152 final float horizontalBlockingAngle = Float.parseFloat(reductionJson.get("horizontalBlockingAngle").toString()); 153 reductions.add(new DamageReduction(type, base, factor, horizontalBlockingAngle)); 154 } 155 } 156 157 //Deserialize bypassBy 158 final JSONArray bypassByArray = (JSONArray)json.getObject().get("bypassedBy"); 159 bypassedBy.clear(); 160 161 if(bypassByArray != null) { 162 163 for(final Object obj : bypassByArray) { 164 165 bypassedBy.add(obj.toString()); 166 } 167 } 168 169 //Deserialize ItemDamage 170 final JSONObject itemDamageJson = (JSONObject) json.getObject().get("item_damage"); 171 if(itemDamageJson != null) { 172 173 final float threshold = Float.parseFloat(itemDamageJson.get("threshold").toString()); 174 final float base = Float.parseFloat(itemDamageJson.get("base").toString()); 175 final float factor = Float.parseFloat(itemDamageJson.get("factor").toString()); 176 itemDamage = new ItemDamage(threshold, base, factor); 177 } 178 179 //Deserialize other properties 180 blockDelay = json.getFloat("block_delay"); 181 disableCooldownScale = json.getFloat("disable_cooldown_scale"); 182 blockSound = json.getString("block_sound"); 183 disableSound = json.getString("disable_sound"); 184 } 185 186 /** 187 * Used to determine if some data is equal to this data. This means that it has to be an exact 188 * copy of this data. For instance, book copies will return false when compared to the original. 189 * 190 * @param component The component to compare. 191 * 192 * @return True if similar, otherwise false. 193 * @since 0.2.0.0 194 */ 195 @Override 196 public boolean similar(final SerialComponent<?, ?> component) { 197 198 if(!(component instanceof final BlocksAttacksComponent<?, ?> other)) return false; 199 200 return Objects.equals(this.reductions, other.reductions) && 201 Objects.equals(this.bypassedBy, other.bypassedBy) && 202 Objects.equals(this.itemDamage, other.itemDamage) && 203 Float.compare(this.blockDelay, other.blockDelay) == 0 && 204 Float.compare(this.disableCooldownScale, other.disableCooldownScale) == 0 && 205 Objects.equals(this.blockSound, other.blockSound) && 206 Objects.equals(this.disableSound, other.disableSound); 207 } 208 209 @Override 210 public int hashCode() { 211 212 return Objects.hash(reductions, bypassedBy, itemDamage, blockDelay, disableCooldownScale, blockSound, disableSound); 213 } 214 215 public List<DamageReduction> reductions() { 216 217 return reductions; 218 } 219 220 public void reductions(final List<DamageReduction> reductions) { 221 222 this.reductions.clear(); 223 this.reductions.addAll(reductions); 224 } 225 226 public void reductions(final DamageReduction... reductions) { 227 228 this.reductions.clear(); 229 this.reductions.addAll(Arrays.asList(reductions)); 230 } 231 232 public List<String> bypassedBy() { 233 234 return bypassedBy; 235 } 236 237 public void bypassedBy(final List<String> bypassedBy) { 238 239 this.bypassedBy.clear(); 240 this.bypassedBy.addAll(bypassedBy); 241 } 242 243 public void bypassedBy(final String... bypassedBy) { 244 245 this.bypassedBy.clear(); 246 this.bypassedBy.addAll(Arrays.asList(bypassedBy)); 247 } 248 249 public ItemDamage itemDamage() { 250 251 return itemDamage; 252 } 253 254 public void itemDamage(final ItemDamage itemDamage) { 255 256 this.itemDamage = itemDamage; 257 } 258 259 public float blockDelay() { 260 261 return blockDelay; 262 } 263 264 public void blockDelay(final float blockDelay) { 265 266 this.blockDelay = blockDelay; 267 } 268 269 public float disableCooldownScale() { 270 271 return disableCooldownScale; 272 } 273 274 public void disableCooldownScale(final float disableCooldownScale) { 275 276 this.disableCooldownScale = disableCooldownScale; 277 } 278 279 public String blockSound() { 280 281 return blockSound; 282 } 283 284 public void blockSound(final String blockSound) { 285 286 this.blockSound = blockSound; 287 } 288 289 public String disableSound() { 290 291 return disableSound; 292 } 293 294 public void disableSound(final String disableSound) { 295 296 this.disableSound = disableSound; 297 } 298}