001package net.tnemc.item.platform; 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.kyori.adventure.text.Component; 022import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; 023import net.tnemc.item.AbstractItemStack; 024import net.tnemc.item.component.SerialComponent; 025import net.tnemc.item.component.helper.effect.ApplyEffectsComponentEffect; 026import net.tnemc.item.component.helper.effect.ComponentEffect; 027import net.tnemc.item.component.helper.effect.PlaySoundComponentEffect; 028import net.tnemc.item.component.helper.effect.RemoveEffectsComponentEffect; 029import net.tnemc.item.component.helper.effect.TeleportRandomlyComponentEffect; 030import net.tnemc.item.persistent.PersistentDataType; 031import net.tnemc.item.persistent.impl.PersistentBool; 032import net.tnemc.item.persistent.impl.PersistentByte; 033import net.tnemc.item.persistent.impl.PersistentByteArray; 034import net.tnemc.item.persistent.impl.PersistentDouble; 035import net.tnemc.item.persistent.impl.PersistentFloat; 036import net.tnemc.item.persistent.impl.PersistentInt; 037import net.tnemc.item.persistent.impl.PersistentIntArray; 038import net.tnemc.item.persistent.impl.PersistentLong; 039import net.tnemc.item.persistent.impl.PersistentLongArray; 040import net.tnemc.item.persistent.impl.PersistentShort; 041import net.tnemc.item.persistent.impl.PersistentString; 042import net.tnemc.item.platform.applier.ItemApplicator; 043import net.tnemc.item.platform.check.ItemCheck; 044import net.tnemc.item.platform.check.LocaleItemCheck; 045import net.tnemc.item.platform.conversion.PlatformConverter; 046import net.tnemc.item.platform.serialize.ItemSerializer; 047import net.tnemc.item.providers.CalculationsProvider; 048import net.tnemc.item.providers.ItemProvider; 049import org.jetbrains.annotations.NotNull; 050import org.json.simple.JSONObject; 051 052import java.util.Arrays; 053import java.util.HashMap; 054import java.util.List; 055import java.util.Map; 056import java.util.Optional; 057import java.util.concurrent.ConcurrentHashMap; 058 059/** 060 * ItemPlatform 061 * 062 * @param <I> The implementation's instance of {@link AbstractItemStack} 063 * @param <S> The implementation's instance of item stacks. 064 * @param <U> The implementation's instace of inventories. 065 * 066 * @author creatorfromhell 067 * @since 0.2.0.0 068 */ 069public abstract class ItemPlatform<I extends AbstractItemStack<S>, S, U> { 070 071 protected final Map<String, Class<? extends PersistentDataType<?>>> classes = new ConcurrentHashMap<>(); 072 073 protected final Map<String, ItemProvider<S>> itemProviders = new ConcurrentHashMap<>(); 074 075 protected final Map<String, ItemCheck<S>> checks = new HashMap<>(); 076 protected final Map<String, LocaleItemCheck<S>> localeChecks = new HashMap<>(); 077 protected final Map<String, ItemApplicator<I, S>> applicators = new HashMap<>(); 078 protected final Map<String, ItemSerializer<I, S>> serializers = new HashMap<>(); 079 080 protected final Map<String, Class<? extends ComponentEffect>> effects = new HashMap<>(); 081 082 protected final PlatformConverter converter; 083 084 public ItemPlatform() { 085 086 this(new PlatformConverter()); 087 } 088 089 public ItemPlatform(final PlatformConverter converter) { 090 091 this.converter = converter; 092 093 addPersistentDataType("bool", PersistentBool.class); 094 addPersistentDataType("byte", PersistentByte.class); 095 addPersistentDataType("byte-array", PersistentByteArray.class); 096 addPersistentDataType("double", PersistentDouble.class); 097 addPersistentDataType("float", PersistentFloat.class); 098 addPersistentDataType("int", PersistentInt.class); 099 addPersistentDataType("int-array", PersistentIntArray.class); 100 addPersistentDataType("long", PersistentLong.class); 101 addPersistentDataType("long-array", PersistentLongArray.class); 102 addPersistentDataType("short", PersistentShort.class); 103 addPersistentDataType("string", PersistentString.class); 104 105 addEffect(new ApplyEffectsComponentEffect()); 106 addEffect(new PlaySoundComponentEffect()); 107 addEffect(new RemoveEffectsComponentEffect()); 108 addEffect(new TeleportRandomlyComponentEffect()); 109 } 110 111 /** 112 * Creates a new stack based on the given material. 113 * 114 * @param material The material used for creating the stack. 115 * @return The newly created stack. 116 * @since 0.2.0.0 117 */ 118 public abstract I createStack(final String material); 119 120 /** 121 * @return the version that is being used currently 122 * @since 0.2.0.0 123 */ 124 public abstract String version(); 125 126 /** 127 * Adds default configurations or settings to be used by the implementing class. 128 * @since 0.2.0.0 129 */ 130 public abstract void addDefaults(); 131 132 /** 133 * Retrieves the platform converter associated with the current item platform. 134 * 135 * @return The {@link PlatformConverter} instance used by the item platform. 136 * @since 0.2.0.0 137 */ 138 public PlatformConverter converter() { 139 140 return converter; 141 } 142 143 /** 144 * Retrieves the default provider for the item stack comparison. 145 * 146 * @return the default provider for the item stack comparison. 147 * @since 0.2.0.0 148 */ 149 public abstract @NotNull ItemProvider<S> defaultProvider(); 150 151 /** 152 * Retrieves the identifier of the default provider for the item stack comparison. 153 * 154 * @return The identifier of the default provider for the item stack comparison. 155 * @since 0.2.0.0 156 */ 157 public abstract @NotNull String defaultProviderIdentifier(); 158 159 /** 160 * Provides access to the calculations provider for performing various platform-specific operations. 161 * 162 * @return An instance of {@link CalculationsProvider} that handles calculations related to the item platform. 163 * @since 0.2.0.0 164 */ 165 public abstract CalculationsProvider<I, S, U> calculations(); 166 167 /** 168 * Checks if any of the registered item providers are applicable to the given serialized item and item. 169 * 170 * @param serialized The serialized item stack to check against. 171 * @param item The item to check for applicability. 172 * @return True if an item provider is found that applies to the serialized item and item, otherwise false. 173 * @since 0.2.0.0 174 */ 175 public boolean providerApplies(final AbstractItemStack<? extends S> serialized, final S item) { 176 177 for(final ItemProvider<S> provider : itemProviders.values()) { 178 179 if(provider.identifier().equalsIgnoreCase(defaultProvider().identifier())) { 180 continue; 181 } 182 183 if(provider.appliesTo(serialized, item)) { 184 return true; 185 } 186 } 187 return false; 188 } 189 190 /** 191 * Retrieves the item provider for the given itemProvider name, or returns the default provider if not found. 192 * 193 * @param itemProvider The name of the ItemProvider to retrieve. 194 * @return The ItemProvider associated with the itemProvider name, or the default provider if not found. 195 * @since 0.2.0.0 196 */ 197 public ItemProvider<S> provider(final String itemProvider) { 198 199 return itemProviders.getOrDefault(itemProvider, defaultProvider()); 200 } 201 202 /** 203 * Adds an ItemProvider to the ItemPlatform. 204 * 205 * @param provider The ItemProvider to add to the platform 206 * @since 0.2.0.0 207 */ 208 public void addItemProvider(final ItemProvider<S> provider) { 209 210 itemProviders.put(provider.identifier(), provider); 211 } 212 213 /** 214 * Adds a persistent data type to the item platform. 215 * 216 * @param identifier The identifier for the persistent data type. 217 * @param type The class representing the persistent data type. 218 * @since 0.2.0.0 219 */ 220 public void addPersistentDataType(final String identifier, @NotNull final Class<? extends PersistentDataType<?>> type) { 221 222 classes.put(identifier, type); 223 } 224 225 public Map<String, Class<? extends PersistentDataType<?>>> getClasses() { 226 227 return classes; 228 } 229 230 /** 231 * Used to add an object that is capable of being dual/tri purpose as a check, applicator and/or 232 * deserializer. 233 * 234 * @param object the object to add. 235 * @since 0.2.0.0 236 */ 237 public void addMulti(@NotNull final Object object) { 238 239 if(object instanceof final ItemCheck<?> check) { 240 241 try { 242 243 if(!check.enabled(version())) { 244 245 return; 246 } 247 248 if(check instanceof final LocaleItemCheck<?> localeItemCheck) { 249 250 localeChecks.put(localeItemCheck.identifier(), (LocaleItemCheck<S>)localeItemCheck); 251 } else { 252 253 checks.put(check.identifier(), (ItemCheck<S>)check); 254 } 255 } catch(final Exception ignore) { 256 //Just in case it passes the instance check, but the Generic is 257 //incorrect for w.e reason, we want to fail safely. 258 } 259 } 260 261 if(object instanceof final ItemApplicator<?, ?> applicator) { 262 263 try { 264 265 if(!applicator.enabled(version())) { 266 267 return; 268 } 269 270 applicators.put(applicator.identifier(), (ItemApplicator<I, S>)applicator); 271 } catch(final Exception ignore) { 272 //Just in case it passes the instance check, but the Generic is 273 //incorrect for w.e reason, we want to fail safely. 274 } 275 } 276 277 if(object instanceof final ItemSerializer<?, ?> serializer) { 278 279 try { 280 281 if(!serializer.enabled(version())) { 282 283 return; 284 } 285 286 serializers.put(serializer.identifier(), (ItemSerializer<I, S>)serializer); 287 } catch(final Exception ignore) { 288 //Just in case it passes the instance check, but the Generic is 289 //incorrect for w.e reason, we want to fail safely. 290 } 291 } 292 } 293 294 /** 295 * Converts the given locale stack to an instance of {@link AbstractItemStack} 296 * 297 * @param locale the locale to convert 298 * @return the converted locale of type I 299 * @since 0.2.0.0 300 */ 301 public abstract I locale(final S locale); 302 303 /** 304 * @param check the {@link ItemCheck check} to add. 305 * @since 0.2.0.0 306 */ 307 public void addCheck(@NotNull final ItemCheck<S> check) { 308 309 checks.put(check.identifier(), check); 310 } 311 312 /** 313 * @param applicator the applicator to add 314 * @since 0.2.0.0 315 */ 316 public void addApplicator(@NotNull final ItemApplicator<I, S> applicator) { 317 318 applicators.put(applicator.identifier(), applicator); 319 } 320 321 /** 322 * @param serializer the deserializer to add 323 * @since 0.2.0.0 324 */ 325 public void addSerializer(@NotNull final ItemSerializer<I, S> serializer) { 326 327 serializers.put(serializer.identifier(), serializer); 328 } 329 330 /** 331 * Adds a ReviveEffect to the reviveEffects map. 332 * 333 * @param effect The ReviveEffect instance to add. Must not be null. 334 * @since 0.2.0.0 335 */ 336 public void addEffect(@NotNull final ComponentEffect effect) { 337 338 // Add the effect's class to the map using its type as the key 339 effects.put(effect.getType(), effect.getClass()); 340 } 341 342 /** 343 * Used to check if two locale stacks are comparable. 344 * How they are performed: 345 * - if a locale check applies, the check result is returned, true is the default return. 346 * 347 * @param original the original stack 348 * @param check the stack to use for the check 349 * @param disabledChecks the {@link ItemCheck#identifier()} check identifiers that should be 350 * disabled for the check. 351 * 352 * @return True if the check passes, otherwise false. 353 * @since 0.2.0.0 354 */ 355 public boolean check(@NotNull final S original, @NotNull final S check, @NotNull final String... disabledChecks) { 356 357 final List<String> disabled = Arrays.asList(disabledChecks); 358 359 for(final LocaleItemCheck<S> localeCheck : localeChecks.values()) { 360 361 if(disabled.contains(localeCheck.identifier())) { 362 continue; 363 } 364 365 if(!localeCheck.enabled(version())) { 366 continue; 367 } 368 369 if(!localeCheck.applies(original, check)) { 370 continue; 371 } 372 return localeCheck.check(original, check); 373 } 374 return true; 375 } 376 377 /** 378 * Used to check if two locale stacks are comparable based on a specific order of checks. 379 * 380 * @param original the original stack 381 * @param check the stack to use for the check 382 * @param order the order of the checks to run for the comparison 383 * 384 * @return True if the check passes, otherwise false. 385 * @since 0.2.0.0 386 */ 387 public boolean checkOrder(@NotNull final S original, @NotNull final S check, @NotNull final String... order) { 388 389 for(final String id : order) { 390 391 if(!checks.containsKey(id)) { 392 continue; 393 } 394 395 396 final LocaleItemCheck<S> localeCheck = localeChecks.get(id); 397 if(!localeCheck.enabled(version())) { 398 continue; 399 } 400 401 if(!localeCheck.applies(original, check)) { 402 continue; 403 } 404 return localeCheck.check(original, check); 405 } 406 return true; 407 } 408 409 /** 410 * Used to check if two serialized stacks are comparable. 411 * 412 * @param original the original stack 413 * @param check the stack to use for the check 414 * @param disabledChecks the {@link ItemCheck#identifier()} check identifiers that should be 415 * disabled for the check. 416 * 417 * @return True if the check passes, otherwise false. 418 * @since 0.2.0.0 419 */ 420 public boolean check(@NotNull final I original, @NotNull final I check, final String... disabledChecks) { 421 422 final List<String> disabled = Arrays.asList(disabledChecks); 423 for(final ItemCheck<S> checkItem : checks.values()) { 424 425 System.out.println("Check: " + checkItem.identifier()); 426 427 if(disabled.contains(checkItem.identifier())) { 428 continue; 429 } 430 431 if(!checkItem.enabled(version())) { 432 continue; 433 } 434 435 if(!checkItem.applies(original, check)) { 436 continue; 437 } 438 439 if(!checkItem.check(original, check)) { 440 441 System.out.println("Failed check: " + checkItem.identifier()); 442 return false; 443 } 444 } 445 return true; 446 } 447 448 /** 449 * Used to check if two serialized stacks are comparable based on a specific order of checks. 450 * 451 * @param original the original stack 452 * @param check the stack to use for the check 453 * @param order the order of the checks to run for the comparison 454 * 455 * @return True if the check passes, otherwise false. 456 * @since 0.2.0.0 457 */ 458 public boolean checkOrder(@NotNull final I original, @NotNull final I check, @NotNull final String... order) { 459 460 for(final String id : order) { 461 462 if(!checks.containsKey(id)) { 463 continue; 464 } 465 466 final ItemCheck<S> checkItem = checks.get(id); 467 468 if(!checkItem.enabled(version())) { 469 continue; 470 } 471 472 if(!checkItem.applies(original, check)) { 473 continue; 474 } 475 476 if(!checkItem.check(original, check)) { 477 return false; 478 } 479 } 480 return true; 481 } 482 483 /** 484 * Applies all enabled applicators to the given item. 485 * 486 * @param serialized the serialized item stack to use 487 * @param item the locale itemstack object to apply the applications to 488 * 489 * @return the updated item stack after applying the applicators 490 * @since 0.2.0.0 491 */ 492 public S apply(@NotNull final I serialized, @NotNull S item) { 493 494 for(final ItemApplicator<I, S> applicator : applicators.values()) { 495 496 System.out.println("Try applicator: " + applicator.identifier()); 497 498 if(applicator.enabled(version())) { 499 500 System.out.println("Applicator ready to apply"); 501 502 item = applicator.apply(serialized, item); 503 } 504 } 505 return item; 506 } 507 508 /** 509 * Applies all enabled serializers to the given item. 510 * 511 * @param item the item that we should use to serialize. 512 * @param serialized the serialized item stack we should use to apply this serializer to 513 * 514 * @return the updated serialized item. 515 * @since 0.2.0.0 516 */ 517 public I serializer(@NotNull final S item, @NotNull I serialized) { 518 519 for(final ItemSerializer<I, S> serializer : serializers.values()) { 520 if(serializer.enabled(version())) { 521 522 System.out.println("Serializer ready to apply: " + serializer.identifier()); 523 524 if(serializer instanceof final SerialComponent<I,S> component) { 525 526 System.out.println("Serializer is component"); 527 if(!component.appliesTo(item)) { 528 529 System.out.println("Serializer doesn't apply"); 530 531 continue; 532 } 533 } 534 535 serialized = serializer.serialize(item, serialized); 536 } 537 } 538 return serialized; 539 } 540 541 /** 542 * Initializes and returns an AbstractItemStack object by deserializing the provided JSON object. 543 * 544 * @param object the JSON object to deserialize 545 * 546 * @return an initialized AbstractItemStack object 547 * @since 0.2.0.0 548 */ 549 public abstract Optional<I> initSerialized(final JSONObject object); 550 551 public static String componentString(@NotNull final Component component) { 552 553 return PlainTextComponentSerializer.plainText().serialize(component); 554 } 555 556 public Map<String, Class<? extends ComponentEffect>> effects() { 557 558 return effects; 559 } 560}