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.effect.ComponentEffect;
025import net.tnemc.item.platform.ItemPlatform;
026import org.json.simple.JSONArray;
027import org.json.simple.JSONObject;
028
029import java.util.ArrayList;
030import java.util.Arrays;
031import java.util.List;
032import java.util.Objects;
033
034/**
035 * ConsumableComponent
036 *
037 * @author creatorfromhell
038 * @see <a href="https://minecraft.wiki/w/Data_component_format#">Reference</a>
039 * <p>
040 * @since 0.2.0.0
041 */
042public abstract class ConsumableComponent<I extends AbstractItemStack<T>, T> implements SerialComponent<I, T> {
043
044  protected float consumeSeconds = 1.6f; // Default to 1.6 seconds
045  protected String animation = "eat"; // Default animation
046  protected String sound = "entity.generic.eat"; // Default sound
047  protected boolean hasConsumeParticles = true; // Default true
048  protected final List<ComponentEffect> effects = new ArrayList<>();
049
050  public ConsumableComponent() {
051
052  }
053  public ConsumableComponent(final List<ComponentEffect> effects) {
054
055    this.effects.addAll(effects);
056  }
057
058  public ConsumableComponent(final float consumeSeconds) {
059
060    this.consumeSeconds = consumeSeconds;
061  }
062
063  public ConsumableComponent(final float consumeSeconds, final String animation) {
064
065    this.consumeSeconds = consumeSeconds;
066    this.animation = animation;
067  }
068
069  public ConsumableComponent(final float consumeSeconds, final String animation, final String sound) {
070
071    this.consumeSeconds = consumeSeconds;
072    this.animation = animation;
073    this.sound = sound;
074  }
075
076  public ConsumableComponent(final float consumeSeconds, final String animation, final String sound, final boolean hasConsumeParticles) {
077
078    this.consumeSeconds = consumeSeconds;
079    this.animation = animation;
080    this.sound = sound;
081    this.hasConsumeParticles = hasConsumeParticles;
082  }
083
084  public ConsumableComponent(final float consumeSeconds, final String animation, final String sound, final boolean hasConsumeParticles, final List<ComponentEffect> effects) {
085
086    this.consumeSeconds = consumeSeconds;
087    this.animation = animation;
088    this.sound = sound;
089    this.hasConsumeParticles = hasConsumeParticles;
090    this.effects.addAll(effects);
091  }
092
093  @Override
094  public String identifier() {
095    return "consumable";
096  }
097
098  @Override
099  public JSONObject toJSON() {
100    final JSONObject json = new JSONObject();
101    json.put("consume_seconds", consumeSeconds);
102    json.put("animation", animation);
103    json.put("sound", sound);
104    json.put("has_consume_particles", hasConsumeParticles);
105
106    final JSONArray effectsArray = new JSONArray();
107    for (final ComponentEffect effect : effects) {
108      effectsArray.add(effect.toJSON());
109    }
110    json.put("on_consume_effects", effectsArray);
111
112    return json;
113  }
114
115  @Override
116  public void readJSON(final JSONHelper json, final ItemPlatform<I, T, ?> platform) {
117    consumeSeconds = json.getFloat("consume_seconds");
118    animation = json.getString("animation");
119    sound = json.getString("sound");
120    hasConsumeParticles = json.getBoolean("has_consume_particles");
121
122    effects.clear();
123    if(json.has("on_consume_effects")) {
124
125      final JSONArray effectsArray = (JSONArray) json.getObject().get("on_consume_effects");
126      for (final Object obj : effectsArray) {
127        final JSONObject effectJson = (JSONObject) obj;
128        final String type = effectJson.get("type").toString();
129
130        // Get the effect class from the platform's reviveEffects map
131        final Class<? extends ComponentEffect> effectClass = platform.effects().get(type);
132
133        if(effectClass != null) {
134          try {
135            // Instantiate the effect dynamically
136            final ComponentEffect effect = effectClass.getDeclaredConstructor().newInstance();
137            effect.readJSON(new JSONHelper(effectJson));
138            effects.add(effect);
139          } catch (final ReflectiveOperationException e) {
140            throw new RuntimeException("Failed to instantiate ComponentEffect for type: " + type, e);
141          }
142        }
143      }
144    }
145  }
146
147  @Override
148  public boolean similar(final SerialComponent<?, ?> component) {
149    if(!(component instanceof final ConsumableComponent<?, ?> other)) return false;
150    return Float.compare(this.consumeSeconds, other.consumeSeconds) == 0 &&
151           Objects.equals(this.animation, other.animation) &&
152           Objects.equals(this.sound, other.sound) &&
153           this.hasConsumeParticles == other.hasConsumeParticles &&
154           Objects.equals(this.effects, other.effects);
155  }
156
157  @Override
158  public int hashCode() {
159    return Objects.hash(consumeSeconds, animation, sound, hasConsumeParticles, effects);
160  }
161
162  public float consumeSeconds() {
163
164    return consumeSeconds;
165  }
166
167  public void consumeSeconds(final float consumeSeconds) {
168
169    this.consumeSeconds = consumeSeconds;
170  }
171
172  public String animation() {
173
174    return animation;
175  }
176
177  public void animation(final String animation) {
178
179    this.animation = animation;
180  }
181
182  public String sound() {
183
184    return sound;
185  }
186
187  public void sound(final String sound) {
188
189    this.sound = sound;
190  }
191
192  public boolean hasConsumeParticles() {
193
194    return hasConsumeParticles;
195  }
196
197  public void hasConsumeParticles(final boolean hasConsumeParticles) {
198
199    this.hasConsumeParticles = hasConsumeParticles;
200  }
201
202  public List<ComponentEffect> effects() {
203
204    return effects;
205  }
206
207  public void effects(final ComponentEffect... effects) {
208    this.effects.addAll(Arrays.asList(effects));
209  }
210
211  public void effects(final List<ComponentEffect> effects) {
212    this.effects.clear();
213    this.effects.addAll(effects);
214  }
215}