Resolve most of simple enough compilation errors

This commit is contained in:
DBotThePony 2024-08-10 01:24:15 +07:00
parent 9b7e424fc5
commit 64780fbda5
Signed by: DBot
GPG Key ID: DCC23B5715498507
326 changed files with 4859 additions and 7139 deletions

View File

@ -109,7 +109,9 @@ tasks.withType(JavaCompile::class.java) {
sourceSets {
create("data") {
compileClasspath += sourceSets["main"].output
compileClasspath += sourceSets["main"].compileClasspath
runtimeClasspath += sourceSets["main"].output
runtimeClasspath += sourceSets["main"].runtimeClasspath
}
this["main"].resources {
@ -189,12 +191,10 @@ dependencies {
}
}
configurations {
getByName("dataImplementation").extendsFrom(getByName("implementation"))
}
minecraft {
//accessTransformer(file("src/main/resources/META-INF/accesstransformer.cfg"))
accessTransformers {
files("src/main/resources/META-INF/accesstransformer.cfg")
}
runs {
configureEach {
@ -243,7 +243,7 @@ minecraft {
mixin {
config("$mod_id.mixins.json")
config("$mod_id.ad_astra.mixins.json")
// config("$mod_id.ad_astra.mixins.json")
}
repositories {

View File

@ -14,7 +14,7 @@ mc_version=1.21
jei_mc_version=1.21
curios_mc_version=1.20.2
forge_gradle_version=[7.0.145,)
forge_gradle_version=7.0.153
forge_version=21.0.54-beta
mixingradle_version=0.7.33
mixin_version=0.8.5

View File

@ -24,14 +24,6 @@ buildscript {
}
}
maven(url = "https://repo.spongepowered.org/repository/maven-public/") {
name = "Spongepowered"
content {
includeGroup("org.spongepowered")
}
}
mavenCentral()
}
@ -43,7 +35,6 @@ buildscript {
classpath(group = "net.neoforged.gradle", name = "userdev", version = forge_gradle_version)
classpath(group = "net.neoforged.gradle", name = "mixin", version = forge_gradle_version)
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlin_version}")
classpath("org.spongepowered:mixingradle:${mixingradle_version}")
classpath(group = "org.gradle.toolchains", name = "foojay-resolver", version = "0.5.0")
}

View File

@ -21,6 +21,8 @@ import net.minecraftforge.eventbus.api.SubscribeEvent
import net.minecraftforge.fml.common.Mod
import net.minecraftforge.data.event.GatherDataEvent
import net.minecraftforge.registries.ForgeRegistries
import net.neoforged.fml.common.EventBusSubscriber
import net.neoforged.fml.common.Mod
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.android.AndroidResearchDataProvider
import ru.dbotthepony.mc.otm.block.*
@ -55,7 +57,7 @@ import kotlin.properties.Delegates
internal fun modLocation(string: String) = ResourceLocation(DataGen.MOD_ID, string)
@Mod.EventBusSubscriber(modid = DataGen.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD)
@EventBusSubscriber(modid = DataGen.MOD_ID, bus = EventBusSubscriber.Bus.MOD)
object DataGen {
const val MOD_ID = OverdriveThatMatters.MOD_ID

View File

@ -30,6 +30,8 @@ fun addTags(tagsProvider: TagsProvider) {
tagsProvider.plates.add("gold", MItems.GOLD_PLATE)
tagsProvider.plates.add("carbon", MItems.CARBON_MESH)
tagsProvider.items.Appender(ItemTags.MEAT).add(MItems.NUTRIENT_PASTE)
tagsProvider.fluids.forge("experience").add(MFluids.LIQUID_XP).add(MFluids.LIQUID_XP_FLOWING)
tagsProvider.fluidTypes.forge("experience").add(MFluids.LIQUID_XP_TYPE)

View File

@ -18,7 +18,7 @@ import net.minecraftforge.common.Tags
import net.minecraftforge.data.event.GatherDataEvent
import net.minecraftforge.registries.ForgeRegistries
import net.minecraftforge.registries.IForgeRegistry
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.capability.MatteryPlayer
import ru.dbotthepony.mc.otm.datagen.DataGen
import java.util.stream.Stream
import net.minecraft.data.tags.TagsProvider as MinecraftTagsProvider
@ -172,7 +172,7 @@ class TagsProvider(private val event: GatherDataEvent) {
val mobEffects = Delegate(ForgeRegistries.MOB_EFFECTS)
val damageTypes = Delegate(Registries.DAMAGE_TYPE)
val androidImmuneEffects = mobEffects.Appender(MatteryPlayerCapability.ANDROID_IMMUNE_EFFECTS)
val androidImmuneEffects = mobEffects.Appender(MatteryPlayer.ANDROID_IMMUNE_EFFECTS)
val requiresShovel = blocks.Appender(BlockTags.MINEABLE_WITH_SHOVEL)
val requiresAxe = blocks.Appender(BlockTags.MINEABLE_WITH_AXE)

View File

@ -3,27 +3,26 @@ package ru.dbotthepony.mc.otm;
import kotlin.KotlinVersion;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.eventbus.api.EventPriority;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.registries.IdMappingEvent;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.bus.api.EventPriority;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.fml.ModContainer;
import net.neoforged.fml.ModList;
import net.neoforged.fml.common.Mod;
import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent;
import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent;
import net.neoforged.fml.loading.FMLLoader;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import ru.dbotthepony.mc.otm.android.AndroidResearchDescription;
import ru.dbotthepony.mc.otm.android.AndroidResearchDescriptions;
import ru.dbotthepony.mc.otm.android.AndroidResearchManager;
import ru.dbotthepony.mc.otm.android.AndroidResearchResult;
import ru.dbotthepony.mc.otm.android.AndroidResearchResults;
import ru.dbotthepony.mc.otm.android.feature.EnderTeleporterFeature;
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity;
import ru.dbotthepony.mc.otm.block.entity.blackhole.ExplosionQueue;
import ru.dbotthepony.mc.otm.block.entity.decorative.DevChestBlockEntity;
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability;
import ru.dbotthepony.mc.otm.capability.MatteryPlayer;
import ru.dbotthepony.mc.otm.capability.drive.DrivePool;
import ru.dbotthepony.mc.otm.client.AndroidAbilityKeyMapping;
import ru.dbotthepony.mc.otm.client.AndroidMenuKeyMapping;
@ -36,8 +35,8 @@ import ru.dbotthepony.mc.otm.client.model.TritaniumArmorModel;
import ru.dbotthepony.mc.otm.client.render.ShockwaveRenderer;
import ru.dbotthepony.mc.otm.client.render.blockentity.BatteryBankRenderer;
import ru.dbotthepony.mc.otm.client.render.blockentity.MatterBatteryBankRenderer;
import ru.dbotthepony.mc.otm.compat.adastra.AdAstraCompatKt;
import ru.dbotthepony.mc.otm.compat.curios.CuriosCompatKt;
import ru.dbotthepony.mc.otm.compat.vanilla.MatteryChestMenu;
import ru.dbotthepony.mc.otm.config.AndroidConfig;
import ru.dbotthepony.mc.otm.config.CablesConfig;
import ru.dbotthepony.mc.otm.config.ClientConfig;
@ -47,22 +46,24 @@ import ru.dbotthepony.mc.otm.config.MachinesConfig;
import ru.dbotthepony.mc.otm.config.ServerCompatConfig;
import ru.dbotthepony.mc.otm.config.ServerConfig;
import ru.dbotthepony.mc.otm.config.ToolsConfig;
import ru.dbotthepony.mc.otm.data.DecimalProvider;
import ru.dbotthepony.mc.otm.item.ChestUpgraderItem;
import ru.dbotthepony.mc.otm.item.tool.ExplosiveHammerItem;
import ru.dbotthepony.mc.otm.item.armor.TritaniumArmorItem;
import ru.dbotthepony.mc.otm.item.QuantumBatteryItem;
import ru.dbotthepony.mc.otm.item.weapon.AbstractWeaponItem;
import ru.dbotthepony.mc.otm.item.PortableCondensationDriveItem;
import ru.dbotthepony.mc.otm.matter.AbstractRegistryAction;
import ru.dbotthepony.mc.otm.matter.IMatterFunction;
import ru.dbotthepony.mc.otm.matter.MatterManager;
import ru.dbotthepony.mc.otm.network.*;
import ru.dbotthepony.mc.otm.registry.*;
import ru.dbotthepony.mc.otm.storage.StorageStack;
import ru.dbotthepony.mc.otm.triggers.KillAsAndroidTrigger;
import top.theillusivec4.curios.api.CuriosApi;
import static net.minecraftforge.common.MinecraftForge.EVENT_BUS;
import static net.neoforged.neoforge.common.NeoForge.EVENT_BUS;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.concurrent.atomic.AtomicInteger;
// The value here should match an entry in the META-INF/mods.toml file
@Mod(OverdriveThatMatters.MOD_ID)
@ -72,21 +73,9 @@ public final class OverdriveThatMatters {
// Directly reference a log4j logger.
public static final String MOD_ID = "overdrive_that_matters";
private static final Logger LOGGER = LogManager.getLogger();
public static final AtomicInteger INGREDIENT_CACHE_INVALIDATION_COUNTER;
static {
try {
var f = Ingredient.class.getDeclaredField("INVALIDATION_COUNTER");
f.setAccessible(true);
INGREDIENT_CACHE_INVALIDATION_COUNTER = (AtomicInteger) f.get(null);
} catch (IllegalAccessException | NoSuchFieldException e) {
throw new RuntimeException(e);
}
}
public static OverdriveThatMatters INSTANCE;
public static ResourceLocation loc(String path) {
return new ResourceLocation(MOD_ID, path);
return ResourceLocation.fromNamespaceAndPath(MOD_ID, path);
}
private static void checkIfKotlinIsInstalled() {
@ -95,9 +84,9 @@ public final class OverdriveThatMatters {
}
}
public OverdriveThatMatters() {
public OverdriveThatMatters(IEventBus bus, Dist dist, ModContainer container) {
if (INSTANCE != null) {
throw new IllegalStateException("yo what the fuck");
throw new IllegalStateException("wei wei wei... hello?");
}
try {
@ -121,35 +110,67 @@ public final class OverdriveThatMatters {
INSTANCE = this;
var modBus = FMLJavaModLoadingContext.get().getModEventBus();
bus.addListener(MRegistry.INSTANCE::register);
MRegistry.INSTANCE.initialize(modBus);
MatterManager.INSTANCE.initialize(modBus);
MBlocks.INSTANCE.register(bus);
MFluids.INSTANCE.register(bus);
MBlockEntities.INSTANCE.register(bus);
MEntityTypes.INSTANCE.register(bus);
MMenus.INSTANCE.register(bus);
MItems.INSTANCE.register(bus);
AndroidFeatures.INSTANCE.register(bus);
MSoundEvents.INSTANCE.register(bus);
LootModifiers.INSTANCE.register(bus);
MItemFunctionTypes.INSTANCE.register(bus);
MLootItemConditions.INSTANCE.register(bus);
MRecipes.INSTANCE.register(bus);
MDataComponentTypes.INSTANCE.register(bus);
MArmorMaterials.INSTANCE.register(bus);
modBus.addListener(EventPriority.HIGHEST, this::setup);
modBus.addListener(EventPriority.NORMAL, this::setupClient);
modBus.addListener(EventPriority.NORMAL, MatteryCapability::register);
StorageStack.Companion.register(bus);
MatteryChestMenu.Companion.register(bus);
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> {
modBus.addListener(EventPriority.NORMAL, AndroidMenuKeyMapping.INSTANCE::register);
modBus.addListener(EventPriority.NORMAL, AndroidAbilityKeyMapping.INSTANCE::register);
modBus.addListener(EventPriority.NORMAL, TritaniumArmorModel::register);
modBus.addListener(EventPriority.NORMAL, GravitationStabilizerModel::register);
modBus.addListener(EventPriority.NORMAL, MCreativeTabs.INSTANCE::register);
MCreativeTabs.INSTANCE.initialize(bus);
modBus.addListener(EventPriority.NORMAL, BatteryBankRenderer.Companion::onRegisterAdditionalModels);
modBus.addListener(EventPriority.NORMAL, MatterBatteryBankRenderer.Companion::onRegisterAdditionalModels);
});
bus.addListener(NetworkPacketsKt::registerNetworkPackets);
ClientConfig.INSTANCE.register();
ServerConfig.INSTANCE.register();
CablesConfig.INSTANCE.register();
ServerCompatConfig.INSTANCE.register();
AndroidConfig.INSTANCE.register();
ExopackConfig.INSTANCE.register();
ItemsConfig.INSTANCE.register();
MachinesConfig.INSTANCE.register();
ToolsConfig.INSTANCE.register();
DecimalProvider.Companion.register(bus);
AndroidResearchDescription.Companion.register(bus);
AndroidResearchDescriptions.INSTANCE.register(bus);
AndroidResearchResult.Companion.register(bus);
AndroidResearchResults.INSTANCE.register(bus);
AbstractRegistryAction.Companion.register(bus);
IMatterFunction.Companion.register(bus);
MRegistry.INSTANCE.initialize(bus);
MatterManager.INSTANCE.initialize(bus);
bus.addListener(EventPriority.HIGHEST, this::setup);
bus.addListener(EventPriority.NORMAL, this::setupClient);
if (FMLLoader.getDist() == Dist.CLIENT) {
bus.addListener(EventPriority.NORMAL, AndroidMenuKeyMapping.INSTANCE::register);
bus.addListener(EventPriority.NORMAL, AndroidAbilityKeyMapping.INSTANCE::register);
bus.addListener(EventPriority.NORMAL, TritaniumArmorModel::register);
bus.addListener(EventPriority.NORMAL, GravitationStabilizerModel::register);
bus.addListener(EventPriority.NORMAL, MCreativeTabs.INSTANCE::register);
bus.addListener(EventPriority.NORMAL, BatteryBankRenderer.Companion::onRegisterAdditionalModels);
bus.addListener(EventPriority.NORMAL, MatterBatteryBankRenderer.Companion::onRegisterAdditionalModels);
MBlockColors.INSTANCE.register(bus);
}
ClientConfig.INSTANCE.register(container);
ServerConfig.INSTANCE.register(container);
CablesConfig.INSTANCE.register(container);
ServerCompatConfig.INSTANCE.register(container);
AndroidConfig.INSTANCE.register(container);
ExopackConfig.INSTANCE.register(container);
ItemsConfig.INSTANCE.register(container);
MachinesConfig.INSTANCE.register(container);
ToolsConfig.INSTANCE.register(container);
}
private void setup(final FMLCommonSetupEvent event) {
@ -158,23 +179,22 @@ public final class OverdriveThatMatters {
EVENT_BUS.addListener(EventPriority.HIGHEST, GlobalEventHandlerKt::onServerStopped);
EVENT_BUS.addListener(EventPriority.HIGHEST, GlobalEventHandlerKt::onServerStopping);
EVENT_BUS.addListener(EventPriority.HIGHEST, GlobalEventHandlerKt::onServerStarting);
EVENT_BUS.addListener(EventPriority.LOWEST, GlobalEventHandlerKt::onLevelTick);
EVENT_BUS.addListener(EventPriority.LOWEST, GlobalEventHandlerKt::onServerTick);
EVENT_BUS.addListener(EventPriority.HIGH, GlobalEventHandlerKt::onLevelTickPre);
EVENT_BUS.addListener(EventPriority.LOWEST, GlobalEventHandlerKt::onLevelTickPost);
EVENT_BUS.addListener(EventPriority.HIGH, GlobalEventHandlerKt::onServerTickPre);
EVENT_BUS.addListener(EventPriority.LOWEST, GlobalEventHandlerKt::onServerTickPost);
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryPlayerCapability.Companion::onPlayerTick);
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryPlayerCapability.Companion::isMobEffectApplicable);
EVENT_BUS.addListener(EventPriority.LOW, MatteryPlayerCapability.Companion::onHurtEvent);
EVENT_BUS.addListener(EventPriority.HIGH, MatteryPlayerCapability.Companion::onAttackEvent);
EVENT_BUS.addGenericListener(Entity.class, EventPriority.NORMAL, MatteryPlayerCapability.Companion::onAttachCapabilityEvent);
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryPlayerCapability.Companion::onPlayerChangeDimensionEvent);
EVENT_BUS.addListener(EventPriority.LOWEST, MatteryPlayerCapability.Companion::onPlayerDeath);
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryPlayerCapability.Companion::onPlayerCloneEvent);
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryPlayerCapability.Companion::onStartTracking);
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryPlayerCapability.Companion::onStopTracking);
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryPlayerCapability.Companion::addCommands);
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryPlayer.Companion::onPlayerTickPre);
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryPlayer.Companion::onPlayerTickPost);
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryPlayer.Companion::isMobEffectApplicable);
EVENT_BUS.addListener(EventPriority.LOW, MatteryPlayer.Companion::onHurtEvent);
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryPlayer.Companion::onPlayerChangeDimensionEvent);
EVENT_BUS.addListener(EventPriority.LOWEST, MatteryPlayer.Companion::onPlayerDeath);
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryPlayer.Companion::onPlayerCloneEvent);
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryPlayer.Companion::onStartTracking);
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryPlayer.Companion::onStopTracking);
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryPlayer.Companion::addCommands);
EVENT_BUS.addListener(EventPriority.NORMAL, ExplosionQueue.Companion::onWorldTick);
EVENT_BUS.addListener(EventPriority.NORMAL, AbstractWeaponItem.Companion::tick);
EVENT_BUS.addListener(EventPriority.NORMAL, QuantumBatteryItem.Companion::tick);
EVENT_BUS.addListener(EventPriority.LOWEST, PortableCondensationDriveItem.Companion::onPickupEvent);
@ -191,6 +211,7 @@ public final class OverdriveThatMatters {
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryBlockEntity.Companion::onWatch);
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryBlockEntity.Companion::onForget);
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryBlockEntity.Companion::playerDisconnected);
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryBlockEntity.Companion::postLevelTick);
EVENT_BUS.addListener(EventPriority.LOWEST, KillAsAndroidTrigger.INSTANCE::onKill);
@ -203,29 +224,14 @@ public final class OverdriveThatMatters {
EVENT_BUS.addListener(EventPriority.NORMAL, DevChestBlockEntity.Companion::mappingsChanged);
MatteryPlayerNetworkChannel.INSTANCE.register();
MenuNetworkChannel.INSTANCE.register();
WeaponNetworkChannel.INSTANCE.register();
GenericNetworkChannel.INSTANCE.register();
if (ModList.get().isLoaded(CuriosApi.MODID)) {
EVENT_BUS.addListener(EventPriority.NORMAL, CuriosCompatKt::onCuriosSlotModifiersUpdated);
}
if (AdAstraCompatKt.isAdAstraLoaded()) {
EVENT_BUS.addListener(EventPriority.NORMAL, AdAstraCompatKt::onDamageEvent);
EVENT_BUS.addListener(EventPriority.NORMAL, AdAstraCompatKt::onMatteryTick);
}
}
private void setupClient(final FMLClientSetupEvent event) {
EVENT_BUS.addListener(EventPriority.NORMAL, MatterManager.INSTANCE::tooltipEvent);
EVENT_BUS.addListener(EventPriority.NORMAL, AbstractWeaponItem.Companion::playerRenderHook);
EVENT_BUS.addListener(EventPriority.NORMAL, AbstractWeaponItem.Companion::fovHook);
EVENT_BUS.addListener(EventPriority.NORMAL, AbstractWeaponItem.Companion::clickHook);
EVENT_BUS.addListener(EventPriority.NORMAL, AbstractWeaponItem.Companion::renderViewModel);
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryGUI.INSTANCE::onScreenRender);
EVENT_BUS.addListener(EventPriority.LOWEST, MatteryGUI.INSTANCE::onOpenGUIEvent);
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryGUI.INSTANCE::onRenderGuiEvent);

View File

@ -1,9 +1,12 @@
package ru.dbotthepony.mc.otm.capability;
import net.minecraftforge.common.capabilities.CapabilityManager;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityToken;
import net.minecraft.core.Direction;
import net.minecraft.resources.ResourceLocation;
import net.neoforged.neoforge.capabilities.BlockCapability;
import net.neoforged.neoforge.capabilities.ItemCapability;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import ru.dbotthepony.mc.otm.OverdriveThatMatters;
import ru.dbotthepony.mc.otm.block.entity.cable.EnergyCableBlockEntity;
import ru.dbotthepony.mc.otm.capability.drive.IMatteryDrive;
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage;
@ -12,57 +15,56 @@ import ru.dbotthepony.mc.otm.capability.matter.IReplicationTaskProvider;
import ru.dbotthepony.mc.otm.capability.matter.IPatternStorage;
import ru.dbotthepony.mc.otm.graph.matter.MatterNode;
import ru.dbotthepony.mc.otm.graph.storage.StorageNode;
import top.theillusivec4.curios.api.type.capability.ICurio;
import top.theillusivec4.curios.api.type.capability.ICuriosItemHandler;
import javax.annotation.Nonnull;
public class MatteryCapability {
@Nonnull
@NotNull
public static final Capability<IMatteryEnergyStorage> ENERGY = CapabilityManager.get(new CapabilityToken<>() {});
public static final BlockCapability<IMatteryEnergyStorage, @Nullable Direction> BLOCK_ENERGY = BlockCapability.createSided(ResourceLocation.fromNamespaceAndPath(OverdriveThatMatters.MOD_ID, "energy"), IMatteryEnergyStorage.class);
@Nonnull
@NotNull
public static final Capability<MatteryPlayerCapability> MATTERY_PLAYER = CapabilityManager.get(new CapabilityToken<>() {});
public static final ItemCapability<IMatteryEnergyStorage, Void> ITEM_ENERGY = ItemCapability.createVoid(ResourceLocation.fromNamespaceAndPath(OverdriveThatMatters.MOD_ID, "energy"), IMatteryEnergyStorage.class);
@Nonnull
@NotNull
public static final Capability<IMatterStorage> MATTER = CapabilityManager.get(new CapabilityToken<>() {});
public static final ItemCapability<IMatterStorage, Void> MATTER_ITEM = ItemCapability.createVoid(ResourceLocation.fromNamespaceAndPath(OverdriveThatMatters.MOD_ID, "matter"), IMatterStorage.class);
@Nonnull
@NotNull
public static final Capability<MatterNode> MATTER_NODE = CapabilityManager.get(new CapabilityToken<>() {});
public static final BlockCapability<IMatterStorage, @Nullable Direction> MATTER_BLOCK = BlockCapability.createSided(ResourceLocation.fromNamespaceAndPath(OverdriveThatMatters.MOD_ID, "matter"), IMatterStorage.class);
@Nonnull
@NotNull
public static final Capability<IPatternStorage> PATTERN = CapabilityManager.get(new CapabilityToken<>() {});
public static final BlockCapability<MatterNode, @Nullable Direction> MATTER_NODE = BlockCapability.createSided(ResourceLocation.fromNamespaceAndPath(OverdriveThatMatters.MOD_ID, "matter_node"), MatterNode.class);
@Nonnull
@NotNull
public static final Capability<IReplicationTaskProvider> TASK = CapabilityManager.get(new CapabilityToken<>() {});
public static final ItemCapability<IPatternStorage, Void> PATTERN_ITEM = ItemCapability.createVoid(ResourceLocation.fromNamespaceAndPath(OverdriveThatMatters.MOD_ID, "pattern"), IPatternStorage.class);
@Nonnull
@NotNull
public static final Capability<IMatteryDrive<?>> DRIVE = CapabilityManager.get(new CapabilityToken<>() {});
public static final BlockCapability<IPatternStorage, @Nullable Direction> PATTERN_BLOCK = BlockCapability.createSided(ResourceLocation.fromNamespaceAndPath(OverdriveThatMatters.MOD_ID, "pattern"), IPatternStorage.class);
@Nonnull
@NotNull
public static final Capability<StorageNode> STORAGE_NODE = CapabilityManager.get(new CapabilityToken<>() {});
public static final BlockCapability<IReplicationTaskProvider, Void> REPLICATION_TASK = BlockCapability.createVoid(ResourceLocation.fromNamespaceAndPath(OverdriveThatMatters.MOD_ID, "replication_task"), IReplicationTaskProvider.class);
@Nonnull
@NotNull
public static final Capability<EnergyCableBlockEntity.Node> ENERGY_CABLE_NODE = CapabilityManager.get(new CapabilityToken<>() {});
public static final ItemCapability<IMatteryDrive, Void> CONDENSATION_DRIVE = ItemCapability.createVoid(ResourceLocation.fromNamespaceAndPath(OverdriveThatMatters.MOD_ID, "condensation_drive"), IMatteryDrive.class);
@Nonnull
@NotNull
public static final Capability<ICuriosItemHandler> CURIOS_INVENTORY = CapabilityManager.get(new CapabilityToken<>() {});
public static final BlockCapability<StorageNode, @Nullable Direction> STORAGE_NODE = BlockCapability.createSided(ResourceLocation.fromNamespaceAndPath(OverdriveThatMatters.MOD_ID, "storage_node"), StorageNode.class);
// TODO: remove this
@Nonnull
@NotNull
public static final BlockCapability<EnergyCableBlockEntity.Node, Void> ENERGY_CABLE_NODE = BlockCapability.createVoid(ResourceLocation.fromNamespaceAndPath(OverdriveThatMatters.MOD_ID, "energy_cable_node"), EnergyCableBlockEntity.Node.class);
@Nonnull
@NotNull
public static final Capability<ICurio> CURIOS_ITEM = CapabilityManager.get(new CapabilityToken<>() {});
@Nonnull
@NotNull
public static final Capability<IMatteryUpgrade> UPGRADE = CapabilityManager.get(new CapabilityToken<>() {});
public static final ItemCapability<IMatteryUpgrade, Void> UPGRADE = ItemCapability.createVoid(ResourceLocation.fromNamespaceAndPath(OverdriveThatMatters.MOD_ID, "machine_upgrade"), IMatteryUpgrade.class);
}

View File

@ -1,9 +1,7 @@
package ru.dbotthepony.mc.otm.client.model;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
import net.minecraft.client.Minecraft;
import net.minecraft.client.model.HumanoidModel;
import net.minecraft.client.model.PlayerModel;
import net.minecraft.client.model.geom.PartPose;
@ -21,11 +19,8 @@ import net.minecraft.client.renderer.entity.layers.RenderLayer;
import net.minecraft.client.renderer.entity.player.PlayerRenderer;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.client.event.RenderPlayerEvent;
import org.joml.Vector3f;
import org.joml.Vector4f;
import ru.dbotthepony.mc.otm.OverdriveThatMatters;
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
import ru.dbotthepony.mc.otm.network.SmokeParticlesPacket;
import javax.annotation.Nonnull;
import java.util.Set;

View File

@ -18,7 +18,7 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability;
import ru.dbotthepony.mc.otm.capability.MatteryPlayer;
import java.util.function.Predicate;
@ -61,7 +61,7 @@ public class MixinInventory {
at = @At("TAIL")
)
private void dropAll(CallbackInfo ci) {
MatteryPlayerCapability.inventoryDropAll((Inventory)(Object)this);
MatteryPlayer.inventoryDropAll((Inventory)(Object)this);
}
@Inject(
@ -69,7 +69,7 @@ public class MixinInventory {
at = @At("TAIL")
)
private void clearContent(CallbackInfo ci) {
MatteryPlayerCapability.inventoryClearContent((Inventory)(Object)this);
MatteryPlayer.inventoryClearContent((Inventory)(Object)this);
}
@Inject(

View File

@ -5,10 +5,8 @@ import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability;
import ru.dbotthepony.mc.otm.capability.MatteryPlayer;
@Mixin(Minecraft.class)
public class MixinMinecraft {
@ -22,7 +20,7 @@ public class MixinMinecraft {
private int pickBlock(Inventory inventory, ItemStack itemStack) {
int i = inventory.findSlotMatchingItem(itemStack);
MatteryPlayerCapability.pickBlockHook(i, itemStack);
MatteryPlayer.pickBlockHook(i, itemStack);
return i;
}

View File

@ -1,30 +0,0 @@
package ru.dbotthepony.mc.otm.mixin;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability;
@Mixin(Player.class)
public class MixinPatchProjectileFinder {
@Inject(
method = "getProjectile(Lnet/minecraft/world/item/ItemStack;)Lnet/minecraft/world/item/ItemStack;",
at = @At(
value = "INVOKE",
target = "net.minecraftforge.common.ForgeHooks.getProjectile(Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/item/ItemStack;)Lnet/minecraft/world/item/ItemStack;",
ordinal = 2,
shift = At.Shift.BEFORE,
remap = false
),
cancellable = true)
private void exosuitGetProjectileHook(ItemStack weaponItem, CallbackInfoReturnable<ItemStack> hook) {
ItemStack result = MatteryPlayerCapability.getProjectileHook((Player) ((Object) this), weaponItem);
if (result != null) {
hook.setReturnValue(result);
}
}
}

View File

@ -1,19 +1,85 @@
package ru.dbotthepony.mc.otm.mixin;
import com.mojang.authlib.GameProfile;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import ru.dbotthepony.mc.otm.capability.IMatteryPlayer;
import ru.dbotthepony.mc.otm.capability.MatteryPlayer;
import java.util.Objects;
@Mixin(Player.class)
public class MixinPlayer {
public class MixinPlayer implements IMatteryPlayer {
private Player otmSelf() {
return (Player) (Object) this;
}
@Inject(
method = "getProjectile(Lnet/minecraft/world/item/ItemStack;)Lnet/minecraft/world/item/ItemStack;",
at = @At(
value = "INVOKE",
target = "net.minecraftforge.common.ForgeHooks.getProjectile(Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/item/ItemStack;)Lnet/minecraft/world/item/ItemStack;",
ordinal = 2,
shift = At.Shift.BEFORE,
remap = false
),
cancellable = true)
private void exosuitGetProjectileHook(ItemStack weaponItem, CallbackInfoReturnable<ItemStack> hook) {
ItemStack result = MatteryPlayer.getProjectileHook(otmSelf(), weaponItem);
if (result != null) {
hook.setReturnValue(result);
}
}
@Inject(
method = "destroyVanishingCursedItems()V",
at = @At("TAIL")
)
private void destroyVanishingCursedItems(CallbackInfo ci) {
MatteryPlayerCapability.playerDestroyVanishingCursedItems((Player)(Object)this);
MatteryPlayer.playerDestroyVanishingCursedItems(otmSelf());
}
private MatteryPlayer otmPlayer;
@Inject(
method = "<init>(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;FLcom/mojang/authlib/GameProfile;)V",
at = @At("TAIL")
)
private void constructOtmPlayer(Level p_250508_, BlockPos p_250289_, float p_251702_, GameProfile p_252153_, CallbackInfo ci) {
otmPlayer = new MatteryPlayer(otmSelf());
}
@NotNull
@Override
public MatteryPlayer getOtmPlayer() {
return Objects.requireNonNull(otmPlayer, "Something went horribly wrong, otmPlayer is null");
}
@Inject(
method = "addAdditionalSaveData(Lnet/minecraft/nbt/CompoundTag;)V",
at = @At("TAIL")
)
private void addAdditionalSaveData(CompoundTag data, CallbackInfo ci) {
data.put("overdrive_that_matters_player", otmPlayer.serializeNBT(otmSelf().registryAccess()));
}
@Inject(
method = "readAdditionalSaveData(Lnet/minecraft/nbt/CompoundTag;)V",
at = @At("TAIL")
)
private void readAdditionalSaveData(CompoundTag data, CallbackInfo ci) {
otmPlayer.deserializeNBT(data.getCompound("overdrive_that_matters_player"), otmSelf().registryAccess());
}
}

View File

@ -1,31 +0,0 @@
package ru.dbotthepony.mc.otm.mixin.compat.ad_astra;
import earth.terrarium.ad_astra.common.entity.system.EntityOxygenSystem;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
import ru.dbotthepony.mc.otm.config.ServerCompatConfig;
@Mixin(EntityOxygenSystem.class)
public class EntityOxygenSystemMixin {
@Inject(
method = "oxygenTick(Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/server/level/ServerLevel;)V",
at = @At("HEAD"),
cancellable = true,
remap = false
)
private static void oxygenTick(LivingEntity entity, ServerLevel level, CallbackInfo hook) {
if (entity instanceof Player && ServerCompatConfig.AdAstra.INSTANCE.getANDROIDS_DO_NOT_NEED_OXYGEN()) {
entity.getCapability(MatteryCapability.MATTERY_PLAYER).ifPresent(it -> {
if (it.isAndroid()) {
hook.cancel();
}
});
}
}
}

View File

@ -1,27 +0,0 @@
package ru.dbotthepony.mc.otm.mixin.compat.ad_astra;
import earth.terrarium.ad_astra.common.entity.system.EntityTemperatureSystem;
import earth.terrarium.ad_astra.common.util.ModUtils;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.LivingEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import ru.dbotthepony.mc.otm.config.ServerCompatConfig;
// STAHP!
@Mixin(EntityTemperatureSystem.class)
public class EntityTemperatureSystemMixin {
@Inject(
method = "temperatureTick(Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/server/level/ServerLevel;)V",
at = @At("HEAD"),
cancellable = true,
remap = false
)
private static void temperatureTick(LivingEntity entity, ServerLevel level, CallbackInfo hook) {
if (ServerCompatConfig.AdAstra.INSTANCE.getWHATS_UP_WITH_TEMPERATURE() && !ModUtils.planetHasAtmosphere(level)) {
hook.cancel();
}
}
}

View File

@ -1,31 +0,0 @@
package ru.dbotthepony.mc.otm.mixin.compat.ad_astra;
import earth.terrarium.ad_astra.common.util.OxygenUtils;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
import ru.dbotthepony.mc.otm.config.ServerCompatConfig;
@Mixin(OxygenUtils.class)
public class OxygenUtilsMixin {
@Inject(
method = "entityHasOxygen(Lnet/minecraft/world/level/Level;Lnet/minecraft/world/entity/LivingEntity;)Z",
at = @At("HEAD"),
cancellable = true,
remap = false
)
private static void entityHasOxygen(Level level, LivingEntity entity, CallbackInfoReturnable<Boolean> hook) {
if (entity instanceof Player && ServerCompatConfig.AdAstra.INSTANCE.getANDROIDS_DO_NOT_NEED_OXYGEN()) {
entity.getCapability(MatteryCapability.MATTERY_PLAYER).ifPresent(it -> {
if (it.isAndroid()) {
hook.setReturnValue(true);
}
});
}
}
}

View File

@ -4,16 +4,19 @@
package ru.dbotthepony.mc.otm
import net.minecraft.client.server.IntegratedServer
import net.minecraft.core.HolderLookup
import net.minecraft.server.MinecraftServer
import net.minecraft.world.level.Level
import net.minecraftforge.api.distmarker.Dist
import net.minecraftforge.event.TickEvent
import net.minecraftforge.event.TickEvent.ServerTickEvent
import net.minecraftforge.event.TickEvent.LevelTickEvent
import net.minecraftforge.event.server.ServerAboutToStartEvent
import net.minecraftforge.event.server.ServerStoppedEvent
import net.minecraftforge.event.server.ServerStoppingEvent
import net.minecraftforge.fml.loading.FMLLoader
import net.neoforged.api.distmarker.Dist
import net.neoforged.bus.api.EventPriority
import net.neoforged.bus.api.SubscribeEvent
import net.neoforged.fml.common.EventBusSubscriber
import net.neoforged.fml.loading.FMLLoader
import net.neoforged.neoforge.event.server.ServerAboutToStartEvent
import net.neoforged.neoforge.event.server.ServerStoppedEvent
import net.neoforged.neoforge.event.server.ServerStoppingEvent
import net.neoforged.neoforge.event.tick.LevelTickEvent
import net.neoforged.neoforge.event.tick.ServerTickEvent
import org.apache.logging.log4j.LogManager
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
import ru.dbotthepony.mc.otm.capability.AbstractProfiledStorage
@ -24,7 +27,6 @@ import ru.dbotthepony.mc.otm.core.util.IConditionalTickable
import ru.dbotthepony.mc.otm.core.util.ITickable
import ru.dbotthepony.mc.otm.core.util.TickList
import ru.dbotthepony.mc.otm.graph.GraphNodeList
import ru.dbotthepony.mc.otm.network.MatteryNetworkChannel
import java.util.*
import java.util.concurrent.atomic.AtomicInteger
@ -43,6 +45,15 @@ val isClient: Boolean by lazy { FMLLoader.getDist() == Dist.CLIENT }
val UNIVERSE_TICKS get() = postServerTick.ticks
val Level.ticksPassed get() = postWorldTick.computeIfAbsent(this) { TickList() }.ticks
@Deprecated("Use when absolutely necessary, like context-less methods/properties")
val Registries: HolderLookup.Provider get() {
if (isClient) {
return NULLABLE_MINECRAFT_SERVER?.registryAccess() ?: minecraft.level?.registryAccess() ?: throw IllegalStateException("Not in game")
} else {
return NULLABLE_MINECRAFT_SERVER?.registryAccess() ?: throw IllegalStateException("Not in game")
}
}
fun <V> lazyPerServer(fn: (MinecraftServer) -> V): Lazy<V> {
return AtomicallyInvalidatedLazy(serverCounter) {
if (!SERVER_IS_LIVE)
@ -169,31 +180,30 @@ var SERVER_IS_LIVE = false
private val LOGGER = LogManager.getLogger()
fun onServerTick(event: ServerTickEvent) {
if (event.phase === TickEvent.Phase.START) {
fun onServerTickPre(event: ServerTickEvent.Pre) {
preServerTick.tick()
serverThreads.add(Thread.currentThread())
} else {
}
fun onServerTickPost(event: ServerTickEvent.Post) {
postServerTick.tick()
// чтоб не плодить кучу подписчиков, вызовем напрямую отсюда
GraphNodeList.tick()
AbstractProfiledStorage.onServerPostTick()
}
}
fun onLevelTick(event: LevelTickEvent) {
if (event.phase === TickEvent.Phase.START) {
fun onLevelTickPre(event: LevelTickEvent.Pre) {
preWorldTick[event.level]?.tick()
if (event.side.isClient) {
if (event.level.isClientSide) {
clientThreads.add(Thread.currentThread())
} else if (event.side.isServer) {
} else {
serverThreads.add(Thread.currentThread())
}
} else {
postWorldTick[event.level]?.tick()
MatteryBlockEntity.postLevelTick(event)
}
fun onLevelTickPost(event: LevelTickEvent.Post) {
postWorldTick[event.level]?.tick()
}
fun onceServerPre(ticker: ITickable) {

View File

@ -1,13 +1,13 @@
package ru.dbotthepony.mc.otm
import it.unimi.dsi.fastutil.ints.IntArrayList
import net.minecraft.core.Registry
import net.minecraft.resources.ResourceLocation
import net.minecraftforge.common.ForgeConfigSpec
import net.minecraftforge.registries.IForgeRegistry
import net.neoforged.neoforge.common.ModConfigSpec
import ru.dbotthepony.mc.otm.config.getValue
import java.util.LinkedList
abstract class ObservedConfigList<V : Any>(val parent: ForgeConfigSpec.ConfigValue<MutableList<String>>, private val allowNulls: Boolean = false) : AbstractMutableList<V>(), RandomAccess {
abstract class ObservedConfigList<V : Any>(val parent: ModConfigSpec.ConfigValue<MutableList<String>>, private val allowNulls: Boolean = false) : AbstractMutableList<V>(), RandomAccess {
private val rawValue: MutableList<String> by parent
private val observedValue = LinkedList<String>()
private val parsedView: ArrayList<V> = ArrayList()
@ -140,33 +140,3 @@ abstract class ObservedConfigList<V : Any>(val parent: ForgeConfigSpec.ConfigVal
return parsedView[index]
}
}
fun <T : Any> ForgeConfigSpec.Builder.defineObjectList(
name: String,
defaultValues: () -> List<T>,
write: (value: T) -> Pair<String, T>?,
read: (value: String) -> T?
): ObservedConfigList<T> {
val parent = defineListAllowEmpty(name.split('.'), { defaultValues.invoke().mapNotNull { write.invoke(it)?.first }.toMutableList()}, { it is String }) as ForgeConfigSpec.ConfigValue<MutableList<String>>
return object : ObservedConfigList<T>(parent) {
override fun toString(value: T): Pair<String, T>? {
return write.invoke(value)
}
override fun fromString(value: String): T? {
return read.invoke(value)
}
}
}
@Deprecated("Obviously better use tags")
fun <T : Any> ForgeConfigSpec.Builder.defineForgeObjectList(
name: String,
defaultValues: () -> List<T>,
registry: IForgeRegistry<T>
): ObservedConfigList<T> {
return defineObjectList(name, defaultValues,
write = { (registry.getKey(it)?.toString() ?: return@defineObjectList null) to it },
read = { registry.getValue(ResourceLocation(it)) })
}

View File

@ -2,10 +2,10 @@ package ru.dbotthepony.mc.otm.android
import com.mojang.blaze3d.vertex.PoseStack
import net.minecraft.client.Camera
import net.minecraftforge.client.event.RenderLevelStageEvent
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import net.neoforged.neoforge.client.event.RenderLevelStageEvent
import ru.dbotthepony.mc.otm.capability.MatteryPlayer
abstract class AndroidActiveFeature(type: AndroidFeatureType<*>, android: MatteryPlayerCapability) : AndroidSwitchableFeature(type, android) {
abstract class AndroidActiveFeature(type: AndroidFeatureType<*>, android: MatteryPlayer) : AndroidSwitchableFeature(type, android) {
/**
* return true to send packet to server if [isClient] is true
*

View File

@ -1,18 +1,18 @@
package ru.dbotthepony.mc.otm.android
import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream
import net.minecraft.core.HolderLookup
import net.minecraft.nbt.CompoundTag
import net.minecraftforge.common.util.INBTSerializable
import net.minecraftforge.event.entity.living.LivingAttackEvent
import net.minecraftforge.event.entity.living.LivingHurtEvent
import net.neoforged.neoforge.common.util.INBTSerializable
import net.neoforged.neoforge.event.entity.living.LivingIncomingDamageEvent
import ru.dbotthepony.kommons.io.DelegateSyncher
import ru.dbotthepony.kommons.util.getValue
import ru.dbotthepony.kommons.util.setValue
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.capability.MatteryPlayer
import ru.dbotthepony.mc.otm.core.nbt.set
import java.io.InputStream
abstract class AndroidFeature(val type: AndroidFeatureType<*>, val android: MatteryPlayerCapability) : INBTSerializable<CompoundTag> {
abstract class AndroidFeature(val type: AndroidFeatureType<*>, val android: MatteryPlayer) : INBTSerializable<CompoundTag> {
val ply get() = android.ply
val syncher = DelegateSyncher()
val syncherRemote = syncher.Remote()
@ -37,8 +37,7 @@ abstract class AndroidFeature(val type: AndroidFeatureType<*>, val android: Matt
open fun applyModifiers() {}
open fun removeModifiers() {}
open fun onHurt(event: LivingHurtEvent) {}
open fun onAttack(event: LivingAttackEvent) {}
open fun onHurt(event: LivingIncomingDamageEvent) {}
open fun collectNetworkPayload(): FastByteArrayOutputStream? {
syncher.observe()
@ -49,23 +48,23 @@ abstract class AndroidFeature(val type: AndroidFeatureType<*>, val android: Matt
syncher.read(stream)
}
override fun serializeNBT(): CompoundTag {
override fun serializeNBT(registry: HolderLookup.Provider): CompoundTag {
return CompoundTag().also {
it["level"] = level
}
}
override fun deserializeNBT(nbt: CompoundTag) {
override fun deserializeNBT(registry: HolderLookup.Provider, nbt: CompoundTag) {
level = nbt.getInt("level")
}
}
class DummyAndroidFeature(type: AndroidFeatureType<*>, android: MatteryPlayerCapability) : AndroidFeature(type, android) {
override fun serializeNBT(): CompoundTag {
class DummyAndroidFeature(type: AndroidFeatureType<*>, android: MatteryPlayer) : AndroidFeature(type, android) {
override fun serializeNBT(registry: HolderLookup.Provider): CompoundTag {
return CompoundTag()
}
override fun deserializeNBT(nbt: CompoundTag) {
override fun deserializeNBT(registry: HolderLookup.Provider, nbt: CompoundTag) {
}
}

View File

@ -4,26 +4,26 @@ import net.minecraft.network.chat.Component
import net.minecraft.network.chat.ComponentContents
import net.minecraft.network.chat.MutableComponent
import net.minecraft.network.chat.contents.TranslatableContents
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.capability.MatteryPlayer
import ru.dbotthepony.mc.otm.core.getKeyNullable
import ru.dbotthepony.mc.otm.registry.MRegistry
open class AndroidFeatureType<T : AndroidFeature> {
protected val factory: (AndroidFeatureType<T>, MatteryPlayerCapability) -> T
protected val factory: (AndroidFeatureType<T>, MatteryPlayer) -> T
constructor(factory: (MatteryPlayerCapability) -> T) : super() {
constructor(factory: (MatteryPlayer) -> T) : super() {
this.factory = { _, capability -> factory.invoke(capability) }
}
constructor(factory: (AndroidFeatureType<T>, MatteryPlayerCapability) -> T) : super() {
constructor(factory: (AndroidFeatureType<T>, MatteryPlayer) -> T) : super() {
this.factory = factory
}
fun create(android: MatteryPlayerCapability): T {
fun create(android: MatteryPlayer): T {
return factory.invoke(this, android)
}
open fun isApplicable(android: MatteryPlayerCapability) = true
open fun isApplicable(android: MatteryPlayer) = true
val registryName by lazy {
MRegistry.ANDROID_FEATURES.getKeyNullable(this)

View File

@ -2,19 +2,19 @@ package ru.dbotthepony.mc.otm.android
import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream
import net.minecraft.ChatFormatting
import net.minecraft.core.HolderLookup
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.chat.Component
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.player.Player
import net.minecraftforge.common.MinecraftForge
import net.minecraftforge.common.util.INBTSerializable
import net.minecraftforge.eventbus.api.Event
import net.minecraftforge.eventbus.api.Event.HasResult
import net.neoforged.bus.api.Event
import net.neoforged.neoforge.common.NeoForge
import net.neoforged.neoforge.common.util.INBTSerializable
import ru.dbotthepony.kommons.io.DelegateSyncher
import ru.dbotthepony.kommons.util.getValue
import ru.dbotthepony.kommons.util.setValue
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.capability.MatteryPlayer
import ru.dbotthepony.mc.otm.capability.awareItemsStream
import ru.dbotthepony.mc.otm.core.TextComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
@ -25,33 +25,27 @@ import ru.dbotthepony.mc.otm.triggers.AndroidResearchTrigger
import java.io.InputStream
import kotlin.math.absoluteValue
class AndroidResearch(val type: AndroidResearchType, val capability: MatteryPlayerCapability) : INBTSerializable<CompoundTag> {
class AndroidResearch(val type: AndroidResearchType, val capability: MatteryPlayer) : INBTSerializable<CompoundTag> {
/**
* Fired on main event bus [MinecraftForge.EVENT_BUS]
* Fired on main event bus [NeoForge.EVENT_BUS]
*/
data class OnResearched(val research: AndroidResearch) : Event()
/**
* Fired on main event bus [MinecraftForge.EVENT_BUS]
* Fired on main event bus [NeoForge.EVENT_BUS]
*/
data class OnUnResearched(val research: AndroidResearch) : Event()
/**
* Fired on main event bus [MinecraftForge.EVENT_BUS]
* Fired on main event bus [NeoForge.EVENT_BUS]
*/
data class OnRefunded(val research: AndroidResearch) : Event()
/**
* Fired on main event bus [MinecraftForge.EVENT_BUS]
* Fired on main event bus [NeoForge.EVENT_BUS]
*/
data class GatherTooltipsEvent(val research: AndroidResearch, val tooltips: MutableList<Component>) : Event()
/**
* Fired on main event bus [MinecraftForge.EVENT_BUS]
*/
@HasResult
data class ConsumeResearchCost(val research: AndroidResearch, val isSimulating: Boolean) : Event()
val ply: Player get() = capability.ply
val syncher = DelegateSyncher()
@ -84,7 +78,7 @@ class AndroidResearch(val type: AndroidResearchType, val capability: MatteryPlay
result.onUnResearched(this)
}
MinecraftForge.EVENT_BUS.post(OnUnResearched(this))
NeoForge.EVENT_BUS.post(OnUnResearched(this))
}
fun onResearched() {
@ -92,7 +86,7 @@ class AndroidResearch(val type: AndroidResearchType, val capability: MatteryPlay
result.onResearched(this)
}
MinecraftForge.EVENT_BUS.post(OnResearched(this))
NeoForge.EVENT_BUS.post(OnResearched(this))
}
/**
@ -108,15 +102,6 @@ class AndroidResearch(val type: AndroidResearchType, val capability: MatteryPlay
return true
}
val event = ConsumeResearchCost(this, simulate)
MinecraftForge.EVENT_BUS.post(event)
if (event.result == Event.Result.ALLOW) {
return true
} else if (event.result == Event.Result.DENY) {
return false
}
if (!simulate && !consumeResearchCost(true)) {
return false
}
@ -183,7 +168,7 @@ class AndroidResearch(val type: AndroidResearchType, val capability: MatteryPlay
}
}
MinecraftForge.EVENT_BUS.post(OnRefunded(this))
NeoForge.EVENT_BUS.post(OnRefunded(this))
return true
}
@ -300,7 +285,7 @@ class AndroidResearch(val type: AndroidResearchType, val capability: MatteryPlay
line.addLines(this, lines)
}
MinecraftForge.EVENT_BUS.post(GatherTooltipsEvent(this, lines))
NeoForge.EVENT_BUS.post(GatherTooltipsEvent(this, lines))
return lines
}
@ -382,14 +367,14 @@ class AndroidResearch(val type: AndroidResearchType, val capability: MatteryPlay
*/
val screenTooltipHeader: Component get() = type.displayName
override fun serializeNBT(): CompoundTag {
override fun serializeNBT(registry: HolderLookup.Provider): CompoundTag {
return CompoundTag().also {
it["researched"] = isResearched
it["tag"] = tag
}
}
override fun deserializeNBT(nbt: CompoundTag) {
override fun deserializeNBT(registry: HolderLookup.Provider, nbt: CompoundTag) {
isResearched = nbt.getBoolean("researched")
tag = nbt.getCompound("tag")
}

View File

@ -6,8 +6,7 @@ import net.minecraft.data.CachedOutput
import net.minecraft.data.DataProvider
import net.minecraft.data.PackOutput
import net.minecraft.resources.ResourceLocation
import net.minecraftforge.data.event.GatherDataEvent
import ru.dbotthepony.mc.otm.core.toJson
import net.neoforged.neoforge.data.event.GatherDataEvent
import ru.dbotthepony.mc.otm.core.toJsonStrict
import ru.dbotthepony.mc.otm.core.util.WriteOnce
import java.util.Collections

View File

@ -2,11 +2,12 @@ package ru.dbotthepony.mc.otm.android
import com.mojang.datafixers.util.Either
import com.mojang.serialization.Codec
import com.mojang.serialization.MapCodec
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.ChatFormatting
import net.minecraft.network.chat.Component
import net.minecraftforge.eventbus.api.IEventBus
import net.minecraftforge.registries.DeferredRegister
import net.minecraft.network.chat.ComponentSerialization
import net.neoforged.bus.api.IEventBus
import ru.dbotthepony.kommons.util.getValue
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.client.ShiftPressedCond
@ -15,19 +16,19 @@ import ru.dbotthepony.mc.otm.core.TextComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.getValue
import ru.dbotthepony.mc.otm.core.util.formatPower
import ru.dbotthepony.mc.otm.data.ComponentCodec
import ru.dbotthepony.mc.otm.data.SingletonCodec
import ru.dbotthepony.mc.otm.data.simpleCodec
import ru.dbotthepony.mc.otm.registry.MDeferredRegister
import ru.dbotthepony.mc.otm.registry.RegistryDelegate
object AndroidResearchDescriptions {
private val registrar = DeferredRegister.create(AndroidResearchDescription.registryKey, OverdriveThatMatters.MOD_ID)
private val registrar = MDeferredRegister(AndroidResearchDescription.registryKey, OverdriveThatMatters.MOD_ID)
init {
registrar.register("plain") { PlainAndroidResearchDescription }
}
internal fun register(bus: IEventBus) {
fun register(bus: IEventBus) {
registrar.register(bus)
}
@ -73,11 +74,11 @@ interface AndroidResearchDescription {
* Type, representing raw description populator in registry
*/
interface Type<T : AndroidResearchDescription> {
val codec: Codec<T>
val codec: MapCodec<T>
}
abstract class Singleton : AndroidResearchDescription, Type<Singleton> {
override val codec = SingletonCodec(this)
override val codec: MapCodec<Singleton> = MapCodec.unit(this)
override val type: Type<*>
get() = this
}
@ -92,8 +93,8 @@ interface AndroidResearchDescription {
get() = this@Leveled
}
override val codec: Codec<Instance> by lazy {
RecordCodecBuilder.create {
override val codec: MapCodec<Instance> by lazy {
RecordCodecBuilder.mapCodec {
it.group(Codec.INT.fieldOf("level").forGetter(Instance::level)).apply(it, ::Instance)
}
}
@ -103,18 +104,16 @@ interface AndroidResearchDescription {
val type: Type<*>
companion object {
private val delegate = RegistryDelegate<Type<*>>("android_research_description") {
disableSaving()
}
private val delegate = RegistryDelegate<Type<*>>("android_research_description") {}
val registry by delegate
val registryKey get() = delegate.key
val CODEC: Codec<AndroidResearchDescription> by lazy {
registry.codec.dispatch({ it.type }, { it.codec })
registry.byNameCodec().dispatch({ it.type }, { it.codec })
}
internal fun register(bus: IEventBus) {
fun register(bus: IEventBus) {
bus.addListener(delegate::build)
}
@ -140,9 +139,11 @@ object PlainAndroidResearchDescription : AndroidResearchDescription.Type<PlainAn
fun make(line: Component) = Instance(line)
override val codec: Codec<Instance> by lazy {
Codec
.either(ComponentCodec, simpleCodec(::Instance, Instance::line, ComponentCodec))
.xmap({ c -> c.map({ Instance(it) }, { it }) }, { c -> Either.left(c.line) })
override val codec: MapCodec<Instance> by lazy {
RecordCodecBuilder.mapCodec {
it.group(
ComponentSerialization.CODEC.fieldOf("line").forGetter { it.line }
).apply(it, ::Instance)
}
}
}

View File

@ -7,28 +7,31 @@ import com.google.gson.JsonObject
import com.google.gson.JsonSyntaxException
import net.minecraft.client.server.IntegratedServer
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.network.codec.StreamCodec
import net.minecraft.network.protocol.common.custom.CustomPacketPayload
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.server.packs.resources.ResourceManager
import net.minecraft.server.packs.resources.SimpleJsonResourceReloadListener
import net.minecraft.util.profiling.ProfilerFiller
import net.minecraftforge.event.AddReloadListenerEvent
import net.minecraftforge.event.OnDatapackSyncEvent
import net.minecraftforge.network.PacketDistributor
import net.neoforged.neoforge.event.AddReloadListenerEvent
import net.neoforged.neoforge.event.OnDatapackSyncEvent
import net.neoforged.neoforge.network.PacketDistributor
import net.neoforged.neoforge.network.handling.IPayloadContext
import org.apache.logging.log4j.LogManager
import ru.dbotthepony.mc.otm.MINECRAFT_SERVER
import ru.dbotthepony.mc.otm.NULLABLE_MINECRAFT_SERVER
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.SERVER_IS_LIVE
import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.core.ResourceLocation
import ru.dbotthepony.mc.otm.core.fromJsonStrict
import ru.dbotthepony.mc.otm.core.fromNetwork
import ru.dbotthepony.mc.otm.core.set
import ru.dbotthepony.mc.otm.core.toNetwork
import ru.dbotthepony.mc.otm.network.GenericNetworkChannel
import ru.dbotthepony.mc.otm.network.MNetworkContext
import ru.dbotthepony.mc.otm.network.MatteryPacket
import ru.dbotthepony.mc.otm.onceServer
import java.util.LinkedList
import java.util.*
object AndroidResearchManager : SimpleJsonResourceReloadListener(GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(), "otm_android_research"), Iterable<AndroidResearchType> {
const val DIRECTORY = "otm_android_research"
@ -85,7 +88,7 @@ object AndroidResearchManager : SimpleJsonResourceReloadListener(GsonBuilder().s
if (SERVER_IS_LIVE) {
onceServer {
for (ply in MINECRAFT_SERVER.playerList.players) {
ply.matteryPlayer?.reloadResearch()
ply.matteryPlayer.reloadResearch()
}
}
}
@ -99,21 +102,22 @@ object AndroidResearchManager : SimpleJsonResourceReloadListener(GsonBuilder().s
val packet = SyncPacket(researchMap.values)
if (event.player != null) {
GenericNetworkChannel.send(event.player!!, packet)
PacketDistributor.sendToPlayer(event.player as ServerPlayer, packet)
} else {
GenericNetworkChannel.send(PacketDistributor.ALL.noArg(), packet)
PacketDistributor.sendToAllPlayers(packet)
}
}
class SyncPacket(val collection: Collection<AndroidResearchType>) : MatteryPacket {
override fun write(buff: FriendlyByteBuf) {
val SYNC_TYPE = CustomPacketPayload.Type<SyncPacket>(ResourceLocation(OverdriveThatMatters.MOD_ID, "research_sync"))
val SYNC_CODEC: StreamCodec<FriendlyByteBuf, SyncPacket> = StreamCodec.ofMember(SyncPacket::write, ::readSyncPacket)
class SyncPacket(val collection: Collection<AndroidResearchType>) : CustomPacketPayload {
fun write(buff: FriendlyByteBuf) {
buff.writeCollection(collection) { a, b -> AndroidResearchType.CODEC.toNetwork(a, b) }
LOGGER.debug("Constructed android research registry packet, ${buff.writerIndex()} bytes in size")
}
override fun play(context: MNetworkContext) {
context.packetHandled = true
fun play(context: IPayloadContext) {
if (NULLABLE_MINECRAFT_SERVER is IntegratedServer)
return
@ -133,6 +137,10 @@ object AndroidResearchManager : SimpleJsonResourceReloadListener(GsonBuilder().s
minecraft.player?.matteryPlayer?.reloadResearch()
}
}
override fun type(): CustomPacketPayload.Type<out CustomPacketPayload> {
return SYNC_TYPE
}
}
fun readSyncPacket(buff: FriendlyByteBuf): SyncPacket {

View File

@ -2,21 +2,22 @@ package ru.dbotthepony.mc.otm.android
import com.mojang.datafixers.util.Either
import com.mojang.serialization.Codec
import com.mojang.serialization.MapCodec
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.resources.ResourceLocation
import net.minecraftforge.eventbus.api.IEventBus
import net.minecraftforge.registries.DeferredRegister
import net.neoforged.bus.api.IEventBus
import org.apache.logging.log4j.LogManager
import ru.dbotthepony.kommons.util.getValue
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.core.getValue
import ru.dbotthepony.mc.otm.data.SingletonCodec
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
import ru.dbotthepony.mc.otm.registry.MDeferredRegister
import ru.dbotthepony.mc.otm.registry.MRegistry
import ru.dbotthepony.mc.otm.registry.RegistryDelegate
object AndroidResearchResults {
private val registrar = DeferredRegister.create(AndroidResearchResult.registryKey, OverdriveThatMatters.MOD_ID)
private val registrar = MDeferredRegister(AndroidResearchResult.registryKey, OverdriveThatMatters.MOD_ID)
init {
registrar.register("feature") { AndroidResearchResult.Feature.Companion }
@ -24,7 +25,7 @@ object AndroidResearchResults {
}
private object NanobotsArmorStrength : AndroidResearchResult.Singleton<NanobotsArmorStrength> {
override val codec: Codec<NanobotsArmorStrength> = SingletonCodec(this)
override val codec: MapCodec<NanobotsArmorStrength> = MapCodec.unit(this)
override val type: AndroidResearchResult.Type<*>
get() = this
@ -40,7 +41,7 @@ object AndroidResearchResults {
}
private object NanobotsArmorSpeed : AndroidResearchResult.Singleton<NanobotsArmorSpeed> {
override val codec: Codec<NanobotsArmorSpeed> = SingletonCodec(this)
override val codec: MapCodec<NanobotsArmorSpeed> = MapCodec.unit(this)
override val type: AndroidResearchResult.Type<*>
get() = this
@ -58,14 +59,14 @@ object AndroidResearchResults {
val NANOBOTS_ARMOR_STRENGTH: AndroidResearchResult.Singleton<*> by registrar.register("nanobots_armor_strength") { NanobotsArmorStrength }
val NANOBOTS_ARMOR_SPEED: AndroidResearchResult.Singleton<*> by registrar.register("nanobots_armor_speed") { NanobotsArmorSpeed }
internal fun register(bus: IEventBus) {
fun register(bus: IEventBus) {
registrar.register(bus)
}
}
interface AndroidResearchResult {
interface Type<T : AndroidResearchResult> {
val codec: Codec<T>
val codec: MapCodec<T>
}
interface Singleton<T : Singleton<T>> : Type<T>, AndroidResearchResult
@ -74,7 +75,7 @@ interface AndroidResearchResult {
* Adds specific android feature [id] to target, does nothing if target already has specified feature
*/
class Feature(val id: ResourceLocation, val optional: Boolean = false) : AndroidResearchResult {
val feature = MRegistry.ANDROID_FEATURES.getValue(id) ?: if (optional) null else throw NoSuchElementException("Unknown android feature $id")
val feature = MRegistry.ANDROID_FEATURES.get(id) ?: if (optional) null else throw NoSuchElementException("Unknown android feature $id")
override val type: Type<*>
get() = Companion
@ -108,7 +109,7 @@ interface AndroidResearchResult {
* Increases level of specific android feature [id] by specified amount [levels]
*/
class FeatureLevel(val id: ResourceLocation, val optional: Boolean = false, val levels: Int = 1) : AndroidResearchResult {
val feature = MRegistry.ANDROID_FEATURES.getValue(id) ?: if (optional) null else throw NoSuchElementException("Unknown android feature $id")
val feature = MRegistry.ANDROID_FEATURES.get(id) ?: if (optional) null else throw NoSuchElementException("Unknown android feature $id")
override val type: Type<*>
get() = Companion
@ -165,18 +166,16 @@ interface AndroidResearchResult {
companion object {
private val LOGGER = LogManager.getLogger()
private val delegate = RegistryDelegate<Type<*>>("android_research_result") {
disableSaving()
}
private val delegate = RegistryDelegate<Type<*>>("android_research_result") {}
val registry by delegate
val registryKey get() = delegate.key
val CODEC: Codec<AndroidResearchResult> by lazy {
registry.codec.dispatch({ it.type }, { it.codec })
registry.byNameCodec().dispatch({ it.type }, { it.codec })
}
internal fun register(bus: IEventBus) {
fun register(bus: IEventBus) {
bus.addListener(delegate::build)
}
}

View File

@ -8,8 +8,10 @@ import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.ListCodec
import com.mojang.serialization.codecs.RecordCodecBuilder
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.ComponentContents
import net.minecraft.network.chat.ComponentSerialization
import net.minecraft.network.chat.MutableComponent
import net.minecraft.network.chat.contents.TranslatableContents
import net.minecraft.resources.ResourceLocation
@ -18,13 +20,10 @@ import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.crafting.Ingredient
import net.minecraft.world.level.ItemLike
import net.minecraftforge.registries.ForgeRegistries
import ru.dbotthepony.mc.otm.client.render.sprites.AbstractMatterySprite
import ru.dbotthepony.mc.otm.client.render.sprites.SpriteType
import ru.dbotthepony.mc.otm.core.collect.ListSet
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.isActuallyEmpty
import ru.dbotthepony.mc.otm.data.ComponentCodec
import ru.dbotthepony.mc.otm.data.JsonElementCodec
import ru.dbotthepony.mc.otm.isClient
import java.util.Optional
@ -181,7 +180,7 @@ class AndroidResearchType(
private val definedItems: List<Pair<Ingredient, Int>> = ImmutableList.copyOf(items)
val results: ImmutableList<AndroidResearchResult> = ImmutableList.copyOf(results)
val items: Stream<out Pair<Ingredient, Int>> get() = definedItems.stream().filter { !it.first.isActuallyEmpty }
val items: Stream<out Pair<Ingredient, Int>> get() = definedItems.stream().filter { !it.first.hasNoItems() }
val description: ImmutableList<AndroidResearchDescription> = ImmutableList.copyOf(description)
/**
@ -387,9 +386,9 @@ class AndroidResearchType(
RecordCodecBuilder.create {
it.group(
ResourceLocation.CODEC.fieldOf("id").forGetter(AndroidResearchType::id),
ListCodec(Reference.CODEC).fieldOf("prerequisites").forGetter(AndroidResearchType::prerequisites),
ListCodec(Reference.CODEC).fieldOf("blockedBy").forGetter(AndroidResearchType::blockedBy),
ListCodec(
Codec.list(Reference.CODEC).fieldOf("prerequisites").forGetter(AndroidResearchType::prerequisites),
Codec.list(Reference.CODEC).fieldOf("blockedBy").forGetter(AndroidResearchType::blockedBy),
Codec.list(
RecordCodecBuilder.create<Pair<Ingredient, Int>> {
it.group(
Ingredient.CODEC.fieldOf("item").forGetter { it.first },
@ -397,13 +396,13 @@ class AndroidResearchType(
).apply(it, ::Pair)
}
).fieldOf("items").forGetter { it.definedItems },
ListCodec(AndroidResearchResult.CODEC).fieldOf("results").forGetter(AndroidResearchType::results),
ListCodec(AndroidResearchDescription.CODEC).fieldOf("description").forGetter(AndroidResearchType::description),
Codec.list(AndroidResearchResult.CODEC).fieldOf("results").forGetter(AndroidResearchType::results),
Codec.list(AndroidResearchDescription.CODEC).fieldOf("description").forGetter(AndroidResearchType::description),
Codec.intRange(0, Int.MAX_VALUE).fieldOf("experienceLevels").forGetter(AndroidResearchType::experienceLevels),
ComponentCodec.optionalFieldOf("customName").forGetter { Optional.ofNullable(it.customName) },
ComponentSerialization.CODEC.optionalFieldOf("customName").forGetter { Optional.ofNullable(it.customName) },
JsonElementCodec.xmap({ it as? JsonObject ?: throw JsonSyntaxException("Not a json object: $it") }, { it }).optionalFieldOf("skinIcon").forGetter { Optional.ofNullable(it.skinIcon) },
ForgeRegistries.ITEMS.codec.optionalFieldOf("itemIcon").forGetter { Optional.ofNullable(it.itemIcon) },
ComponentCodec.optionalFieldOf("iconTextValue").forGetter { Optional.ofNullable(it.iconTextValue) },
BuiltInRegistries.ITEM.byNameCodec().optionalFieldOf("itemIcon").forGetter { Optional.ofNullable(it.itemIcon) },
ComponentSerialization.CODEC.optionalFieldOf("iconTextValue").forGetter { Optional.ofNullable(it.iconTextValue) },
).apply(it, ::AndroidResearchType)
}
}

View File

@ -1,17 +1,18 @@
package ru.dbotthepony.mc.otm.android
import net.minecraft.client.multiplayer.ClientLevel
import net.minecraft.core.HolderLookup
import net.minecraft.nbt.CompoundTag
import net.minecraft.server.level.ServerPlayer
import ru.dbotthepony.kommons.math.RGBAColor
import ru.dbotthepony.kommons.util.getValue
import ru.dbotthepony.kommons.util.setValue
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.capability.MatteryPlayer
import ru.dbotthepony.mc.otm.client.render.MGUIGraphics
import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.core.nbt.set
abstract class AndroidSwitchableFeature(type: AndroidFeatureType<*>, android: MatteryPlayerCapability) : AndroidFeature(type, android) {
abstract class AndroidSwitchableFeature(type: AndroidFeatureType<*>, android: MatteryPlayer) : AndroidFeature(type, android) {
var isActive by syncher.boolean(setter = setter@{ access, value ->
if (value != access.get()) {
access.accept(value)
@ -52,15 +53,15 @@ abstract class AndroidSwitchableFeature(type: AndroidFeatureType<*>, android: Ma
// but it doesn't seem to cause issues?
abstract fun renderIcon(graphics: MGUIGraphics, x: Float, y: Float, width: Float, height: Float, color: RGBAColor = RGBAColor.WHITE)
override fun serializeNBT(): CompoundTag {
return super.serializeNBT().also {
override fun serializeNBT(registry: HolderLookup.Provider): CompoundTag {
return super.serializeNBT(registry).also {
it["isActive"] = isActive
it["cooldown"] = cooldown
}
}
override fun deserializeNBT(nbt: CompoundTag) {
super.deserializeNBT(nbt)
override fun deserializeNBT(registry: HolderLookup.Provider, nbt: CompoundTag) {
super.deserializeNBT(registry, nbt)
isActive = nbt.getBoolean("isActive")
cooldown = nbt.getInt("cooldown")
}

View File

@ -3,11 +3,11 @@ package ru.dbotthepony.mc.otm.android.feature
import net.minecraft.world.entity.ai.attributes.AttributeModifier
import net.minecraft.world.entity.ai.attributes.Attributes
import ru.dbotthepony.mc.otm.android.AndroidFeature
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.capability.MatteryPlayer
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
import java.util.*
class AttackBoostFeature(android: MatteryPlayerCapability) : AndroidFeature(AndroidFeatures.ATTACK_BOOST, android) {
class AttackBoostFeature(android: MatteryPlayer) : AndroidFeature(AndroidFeatures.ATTACK_BOOST, android) {
override fun applyModifiers() {
val modifier = ply.getAttribute(Attributes.ATTACK_DAMAGE)

View File

@ -20,22 +20,23 @@ import net.minecraft.world.phys.HitResult
import net.minecraft.world.phys.shapes.BooleanOp
import net.minecraft.world.phys.shapes.CollisionContext
import net.minecraft.world.phys.shapes.Shapes
import net.minecraftforge.client.event.RenderLevelStageEvent
import net.minecraftforge.event.ForgeEventFactory
import net.minecraftforge.event.entity.living.LivingDeathEvent
import net.neoforged.neoforge.client.event.RenderLevelStageEvent
import net.neoforged.neoforge.event.EventHooks
import net.neoforged.neoforge.event.entity.living.LivingDeathEvent
import ru.dbotthepony.kommons.math.RGBAColor
import ru.dbotthepony.mc.otm.NULLABLE_MINECRAFT_SERVER
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.android.AndroidActiveFeature
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.capability.MatteryPlayer
import ru.dbotthepony.mc.otm.capability.energy.extractEnergyExact
import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.client.render.MGUIGraphics
import ru.dbotthepony.mc.otm.client.render.DynamicBufferSource
import ru.dbotthepony.mc.otm.client.render.MGUIGraphics
import ru.dbotthepony.mc.otm.client.render.ResearchIcons
import ru.dbotthepony.mc.otm.client.render.linesIgnoreZRenderType
import ru.dbotthepony.mc.otm.client.render.sprites.sprite
import ru.dbotthepony.mc.otm.config.AndroidConfig
import ru.dbotthepony.mc.otm.core.ResourceLocation
import ru.dbotthepony.mc.otm.core.genericPositions
import ru.dbotthepony.mc.otm.core.holder
import ru.dbotthepony.mc.otm.core.isFall
@ -55,7 +56,7 @@ import ru.dbotthepony.mc.otm.triggers.EnderTeleporterFallDeathTrigger
import java.util.*
import kotlin.math.sin
class EnderTeleporterFeature(capability: MatteryPlayerCapability) : AndroidActiveFeature(AndroidFeatures.ENDER_TELEPORTER, capability) {
class EnderTeleporterFeature(capability: MatteryPlayer) : AndroidActiveFeature(AndroidFeatures.ENDER_TELEPORTER, capability) {
var lastTeleport = 0
private set
@ -299,7 +300,7 @@ class EnderTeleporterFeature(capability: MatteryPlayerCapability) : AndroidActiv
val (blockPos) = trace()
blockPos ?: return false
val event = ForgeEventFactory.onEnderTeleport(ply, blockPos.x + 0.5, blockPos.y.toDouble(), blockPos.z + 0.5)
val event = EventHooks.onEnderTeleport(ply, blockPos.x + 0.5, blockPos.y.toDouble(), blockPos.z + 0.5)
if (event.isCanceled) {
(ply as ServerPlayer).connection.send(ClientboundSoundEntityPacket(SoundEvents.ITEM_BREAK.holder, SoundSource.PLAYERS, ply, 0.3f, 0.5f, ply.level().random.nextLong()))

View File

@ -1,31 +1,26 @@
package ru.dbotthepony.mc.otm.android.feature
import net.minecraft.world.entity.ai.attributes.AttributeModifier
import net.minecraftforge.common.ForgeMod
import net.minecraft.world.entity.ai.attributes.Attributes
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.android.AndroidFeature
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.capability.MatteryPlayer
import ru.dbotthepony.mc.otm.core.ResourceLocation
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
import java.util.*
class ExtendedReachFeature(android: MatteryPlayerCapability) : AndroidFeature(AndroidFeatures.EXTENDED_REACH, android) {
class ExtendedReachFeature(android: MatteryPlayer) : AndroidFeature(AndroidFeatures.EXTENDED_REACH, android) {
override fun applyModifiers() {
if (!ForgeMod.BLOCK_REACH.isPresent)
return
val reach = ply.getAttribute(Attributes.BLOCK_INTERACTION_RANGE) ?: return
val reach = ply.getAttribute(ForgeMod.BLOCK_REACH.get()) ?: return
reach.removePermanentModifier(MODIFIER_ID)
reach.addPermanentModifier(AttributeModifier(MODIFIER_ID, type.displayName.toString(), level + 1.0, AttributeModifier.Operation.ADDITION))
reach.removeModifier(MODIFIER_ID)
reach.addPermanentModifier(AttributeModifier(MODIFIER_ID, level + 1.0, AttributeModifier.Operation.ADD_VALUE))
}
override fun removeModifiers() {
if (!ForgeMod.BLOCK_REACH.isPresent)
return
ply.getAttribute(ForgeMod.BLOCK_REACH.get())?.removePermanentModifier(MODIFIER_ID)
ply.getAttribute(Attributes.BLOCK_INTERACTION_RANGE)?.removeModifier(MODIFIER_ID)
}
companion object {
private val MODIFIER_ID = UUID.fromString("4a3fae46-47a8-a03f-857d-f5c2b2c8f2f2")
private val MODIFIER_ID = ResourceLocation(OverdriveThatMatters.MOD_ID, "android_extended_reach")
}
}

View File

@ -1,24 +1,16 @@
package ru.dbotthepony.mc.otm.android.feature
import net.minecraft.ChatFormatting
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraftforge.event.entity.living.LivingAttackEvent
import net.minecraftforge.event.entity.living.LivingHurtEvent
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import net.neoforged.neoforge.event.entity.living.LivingIncomingDamageEvent
import ru.dbotthepony.mc.otm.android.AndroidFeature
import ru.dbotthepony.mc.otm.android.AndroidResearchManager
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.capability.MatteryPlayer
import ru.dbotthepony.mc.otm.config.AndroidConfig
import ru.dbotthepony.mc.otm.core.TextComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.isFall
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
import ru.dbotthepony.mc.otm.registry.MNames
import ru.dbotthepony.mc.otm.triggers.FallDampenersSaveTrigger
class FallDampenersFeature(capability: MatteryPlayerCapability) : AndroidFeature(AndroidFeatures.FALL_DAMPENERS, capability) {
override fun onHurt(event: LivingHurtEvent) {
class FallDampenersFeature(capability: MatteryPlayer) : AndroidFeature(AndroidFeatures.FALL_DAMPENERS, capability) {
override fun onHurt(event: LivingIncomingDamageEvent) {
if (event.source.isFall) {
val reduction = (AndroidConfig.FALL_DAMAGE_REDUCTION_PER_LEVEL_P * (level + 1)).toFloat().coerceIn(0f, 1f)
val flat = (AndroidConfig.FALL_DAMAGE_REDUCTION_PER_LEVEL_F * (level + 1)).toFloat().coerceIn(0f, Float.MAX_VALUE)
@ -35,15 +27,4 @@ class FallDampenersFeature(capability: MatteryPlayerCapability) : AndroidFeature
}
}
}
override fun onAttack(event: LivingAttackEvent) {
if (event.source.isFall) {
val reduction = (AndroidConfig.FALL_DAMAGE_REDUCTION_PER_LEVEL_P * (level + 1)).toFloat().coerceIn(0f, 1f)
val flat = (AndroidConfig.FALL_DAMAGE_REDUCTION_PER_LEVEL_F * (level + 1)).toFloat().coerceIn(0f, Float.MAX_VALUE)
if (reduction >= 1f || event.amount <= flat) {
event.isCanceled = true
}
}
}
}

View File

@ -2,25 +2,29 @@ package ru.dbotthepony.mc.otm.android.feature
import net.minecraft.client.multiplayer.ClientLevel
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.network.codec.StreamCodec
import net.minecraft.network.protocol.common.custom.CustomPacketPayload
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.item.ItemEntity
import net.neoforged.neoforge.network.PacketDistributor
import net.neoforged.neoforge.network.handling.IPayloadContext
import ru.dbotthepony.kommons.math.RGBAColor
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.config.AndroidConfig
import ru.dbotthepony.mc.otm.android.AndroidSwitchableFeature
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.capability.MatteryPlayer
import ru.dbotthepony.mc.otm.capability.energy.extractEnergyExact
import ru.dbotthepony.mc.otm.client.render.MGUIGraphics
import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.client.render.ResearchIcons
import ru.dbotthepony.mc.otm.core.ResourceLocation
import ru.dbotthepony.mc.otm.core.math.Vector
import ru.dbotthepony.mc.otm.core.getEntitiesInEllipsoid
import ru.dbotthepony.mc.otm.core.math.minus
import ru.dbotthepony.mc.otm.core.math.plus
import ru.dbotthepony.mc.otm.core.position
import ru.dbotthepony.mc.otm.core.math.times
import ru.dbotthepony.mc.otm.network.GenericNetworkChannel
import ru.dbotthepony.mc.otm.network.MNetworkContext
import ru.dbotthepony.mc.otm.network.MatteryPacket
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
import java.util.UUID
import java.util.WeakHashMap
@ -34,8 +38,8 @@ private data class SharedItemEntityData(val owner: UUID? = null, val age: Int =
private val datatable = WeakHashMap<ItemEntity, SharedItemEntityData>()
class ItemEntityDataPacket(val itemUUID: Int, val owner: UUID? = null, val age: Int = 0, val lifespan: Int = 0, val hasPickupDelay: Boolean = true) : MatteryPacket {
override fun write(buff: FriendlyByteBuf) {
class ItemEntityDataPacket(val itemUUID: Int, val owner: UUID? = null, val age: Int = 0, val lifespan: Int = 0, val hasPickupDelay: Boolean = true) : CustomPacketPayload {
fun write(buff: FriendlyByteBuf) {
buff.writeVarInt(itemUUID)
buff.writeBoolean(owner != null)
if (owner != null) buff.writeUUID(owner)
@ -44,20 +48,27 @@ class ItemEntityDataPacket(val itemUUID: Int, val owner: UUID? = null, val age:
buff.writeBoolean(hasPickupDelay)
}
override fun play(context: MNetworkContext) {
fun play(context: IPayloadContext) {
val level = minecraft.player?.level() as ClientLevel? ?: return
val entity = level.getEntity(itemUUID) as ItemEntity? ?: return
datatable[entity] = SharedItemEntityData(owner, age, lifespan, hasPickupDelay)
}
override fun type(): CustomPacketPayload.Type<out CustomPacketPayload> {
return TYPE
}
companion object {
val TYPE = CustomPacketPayload.Type<ItemEntityDataPacket>(ResourceLocation(OverdriveThatMatters.MOD_ID, "item_entity_data"))
val CODEC: StreamCodec<FriendlyByteBuf, ItemEntityDataPacket> = StreamCodec.ofMember(ItemEntityDataPacket::write, ::read)
fun read(buff: FriendlyByteBuf): ItemEntityDataPacket {
return ItemEntityDataPacket(buff.readVarInt(), if (buff.readBoolean()) buff.readUUID() else null, buff.readVarInt(), buff.readVarInt(), buff.readBoolean())
}
}
}
class ItemMagnetFeature(capability: MatteryPlayerCapability) : AndroidSwitchableFeature(AndroidFeatures.ITEM_MAGNET, capability) {
class ItemMagnetFeature(capability: MatteryPlayer) : AndroidSwitchableFeature(AndroidFeatures.ITEM_MAGNET, capability) {
private data class ItemPos(var position: Vector, var ticksSinceActivity: Int)
private val rememberPositions = WeakHashMap<ItemEntity, ItemPos>()
@ -79,7 +90,7 @@ class ItemMagnetFeature(capability: MatteryPlayerCapability) : AndroidSwitchable
ent as ItemEntity
if (server) {
GenericNetworkChannel.send(ply, ItemEntityDataPacket(ent.id, ent.owner?.uuid, ent.age, ent.lifespan, ent.hasPickUpDelay()))
PacketDistributor.sendToPlayer(ply as ServerPlayer, ItemEntityDataPacket(ent.id, ent.owner?.uuid, ent.age, ent.lifespan, ent.hasPickUpDelay()))
if (!serverPredicate.test(ent)) {
continue

View File

@ -1,57 +1,26 @@
package ru.dbotthepony.mc.otm.android.feature
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.server.level.ServerPlayer
import net.minecraft.sounds.SoundSource
import net.neoforged.neoforge.network.PacketDistributor
import ru.dbotthepony.kommons.math.RGBAColor
import ru.dbotthepony.kommons.util.getValue
import ru.dbotthepony.kommons.util.setValue
import ru.dbotthepony.mc.otm.android.AndroidSwitchableFeature
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.capability.MatteryPlayer
import ru.dbotthepony.mc.otm.capability.energy.extractEnergyExact
import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.client.render.MGUIGraphics
import ru.dbotthepony.mc.otm.client.render.ResearchIcons
import ru.dbotthepony.mc.otm.config.AndroidConfig
import ru.dbotthepony.mc.otm.config.ClientConfig
import ru.dbotthepony.mc.otm.core.math.Vector
import ru.dbotthepony.mc.otm.core.math.plus
import ru.dbotthepony.mc.otm.network.GenericNetworkChannel
import ru.dbotthepony.mc.otm.network.MNetworkContext
import ru.dbotthepony.mc.otm.network.MatteryPacket
import ru.dbotthepony.mc.otm.network.MatteryPlayerNetworkChannel
import ru.dbotthepony.mc.otm.network.SmokeParticlesPacket
import ru.dbotthepony.mc.otm.network.TriggerJumpBoostPacket
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
import ru.dbotthepony.mc.otm.registry.MSoundEvents
object TriggerJumpBoostPacket : MatteryPacket {
override fun write(buff: FriendlyByteBuf) {
// no op
}
override fun play(context: MNetworkContext) {
val mattery = context.sender?.matteryPlayer ?: return
if (!mattery.isAndroid)
return
val feature = mattery.getFeature(AndroidFeatures.JUMP_BOOST) ?: return
if (feature.isActive && feature.cooldown <= 4 && mattery.androidEnergy.extractEnergyExact(AndroidConfig.JumpBoost.ENERGY_COST, false)) {
feature.putOnCooldown()
context.sender.level().playSound(
context.sender, context.sender,
MSoundEvents.ANDROID_JUMP_BOOST, SoundSource.PLAYERS,
1f, 1f
)
GenericNetworkChannel.makeSmoke(context.sender, context.sender.x, context.sender.y, context.sender.z)
}
}
}
class JumpBoostFeature(capability: MatteryPlayerCapability) : AndroidSwitchableFeature(AndroidFeatures.JUMP_BOOST, capability) {
class JumpBoostFeature(capability: MatteryPlayer) : AndroidSwitchableFeature(AndroidFeatures.JUMP_BOOST, capability) {
private var tickCooldownClient = false
override val maxCooldown: Int
@ -80,7 +49,7 @@ class JumpBoostFeature(capability: MatteryPlayerCapability) : AndroidSwitchableF
if (isActive && cooldown <= 0 && old != lastGround && !lastGround && isJumping && isShifting && ply.xRot <= ClientConfig.JUMP_BOOST_LOOK_ANGLE && android.androidEnergy.extractEnergyExact(AndroidConfig.JumpBoost.ENERGY_COST, true)) {
ply.deltaMovement += Vector(0.0, AndroidConfig.JumpBoost.POWER * (level + 1) / 20.0, 0.0)
putOnCooldown()
MatteryPlayerNetworkChannel.sendToServer(TriggerJumpBoostPacket)
PacketDistributor.sendToServer(TriggerJumpBoostPacket)
ply.level().playSound(
ply, ply,

View File

@ -4,36 +4,38 @@ import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.attributes.AttributeModifier
import net.minecraft.world.entity.ai.attributes.Attributes
import net.minecraft.world.entity.player.Player
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.android.AndroidFeature
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.capability.MatteryPlayer
import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.core.ResourceLocation
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
import java.util.*
class LimbOverclockingFeature(android: MatteryPlayerCapability) : AndroidFeature(AndroidFeatures.LIMB_OVERCLOCKING, android) {
class LimbOverclockingFeature(android: MatteryPlayer) : AndroidFeature(AndroidFeatures.LIMB_OVERCLOCKING, android) {
override fun applyModifiers() {
val speed = ply.getAttribute(Attributes.MOVEMENT_SPEED)
if (speed != null) {
speed.removePermanentModifier(MODIFIER_ID)
speed.addPermanentModifier(AttributeModifier(MODIFIER_ID, type.displayName.toString(), (level + 1) * 0.08, AttributeModifier.Operation.MULTIPLY_TOTAL))
speed.removeModifier(MODIFIER_ID)
speed.addPermanentModifier(AttributeModifier(MODIFIER_ID,(level + 1) * 0.08, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL))
}
val attackSpeed = ply.getAttribute(Attributes.ATTACK_SPEED)
if (attackSpeed != null) {
attackSpeed.removePermanentModifier(MODIFIER_ID)
attackSpeed.addPermanentModifier(AttributeModifier(MODIFIER_ID, type.displayName.toString(), (level + 1) * 0.06, AttributeModifier.Operation.MULTIPLY_TOTAL))
attackSpeed.removeModifier(MODIFIER_ID)
attackSpeed.addPermanentModifier(AttributeModifier(MODIFIER_ID, (level + 1) * 0.06, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL))
}
}
override fun removeModifiers() {
ply.getAttribute(Attributes.MOVEMENT_SPEED)?.removePermanentModifier(MODIFIER_ID)
ply.getAttribute(Attributes.ATTACK_SPEED)?.removePermanentModifier(MODIFIER_ID)
ply.getAttribute(Attributes.MOVEMENT_SPEED)?.removeModifier(MODIFIER_ID)
ply.getAttribute(Attributes.ATTACK_SPEED)?.removeModifier(MODIFIER_ID)
}
companion object {
private val MODIFIER_ID = UUID.fromString("4a3fae46-e57b-4e20-857d-f5c2b2c8f2f2")
private val MODIFIER_ID = ResourceLocation(OverdriveThatMatters.MOD_ID, "limb_overclocking")
@JvmStatic
fun getBrushCooldown(entity: LivingEntity): Int {

View File

@ -1,12 +1,13 @@
package ru.dbotthepony.mc.otm.android.feature
import net.minecraft.core.HolderLookup
import net.minecraft.nbt.CompoundTag
import net.minecraft.server.level.ServerPlayer
import net.minecraftforge.event.entity.living.LivingHurtEvent
import net.neoforged.neoforge.event.entity.living.LivingIncomingDamageEvent
import ru.dbotthepony.kommons.util.getValue
import ru.dbotthepony.kommons.util.setValue
import ru.dbotthepony.mc.otm.android.AndroidFeature
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.capability.MatteryPlayer
import ru.dbotthepony.mc.otm.capability.energy.extractEnergyExact
import ru.dbotthepony.mc.otm.core.isBypassArmor
import ru.dbotthepony.mc.otm.core.math.Decimal
@ -17,7 +18,7 @@ import ru.dbotthepony.mc.otm.onceServer
import ru.dbotthepony.mc.otm.triggers.NanobotsArmorTrigger
import kotlin.math.roundToInt
class NanobotsArmorFeature(android: MatteryPlayerCapability) : AndroidFeature(AndroidFeatures.NANOBOTS_ARMOR, android) {
class NanobotsArmorFeature(android: MatteryPlayer) : AndroidFeature(AndroidFeatures.NANOBOTS_ARMOR, android) {
var strength by syncher.int(
setter = setter@{ access, value -> access.accept(value.coerceIn(0 .. 3)) }
)
@ -42,7 +43,7 @@ class NanobotsArmorFeature(android: MatteryPlayerCapability) : AndroidFeature(An
}
}
override fun onHurt(event: LivingHurtEvent) {
override fun onHurt(event: LivingIncomingDamageEvent) {
ticksPassed = 0
if (!event.source.isBypassArmor && layers > 0) {
@ -69,8 +70,8 @@ class NanobotsArmorFeature(android: MatteryPlayerCapability) : AndroidFeature(An
}
}
override fun serializeNBT(): CompoundTag {
return super.serializeNBT().also {
override fun serializeNBT(registry: HolderLookup.Provider): CompoundTag {
return super.serializeNBT(registry).also {
it["ticksPassed"] = ticksPassed
it["layers"] = layers
it["strength"] = strength
@ -78,8 +79,8 @@ class NanobotsArmorFeature(android: MatteryPlayerCapability) : AndroidFeature(An
}
}
override fun deserializeNBT(nbt: CompoundTag) {
super.deserializeNBT(nbt)
override fun deserializeNBT(registry: HolderLookup.Provider, nbt: CompoundTag) {
super.deserializeNBT(registry, nbt)
ticksPassed = nbt.getInt("ticksPassed")
layers = nbt.getInt("layers")
strength = nbt.getInt("strength")

View File

@ -1,18 +1,19 @@
package ru.dbotthepony.mc.otm.android.feature
import net.minecraft.core.HolderLookup
import net.minecraft.nbt.CompoundTag
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.level.GameRules
import net.minecraftforge.event.entity.living.LivingHurtEvent
import net.neoforged.neoforge.event.entity.living.LivingIncomingDamageEvent
import ru.dbotthepony.mc.otm.config.AndroidConfig
import ru.dbotthepony.mc.otm.android.AndroidFeature
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.capability.MatteryPlayer
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
import ru.dbotthepony.mc.otm.registry.StatNames
import ru.dbotthepony.mc.otm.core.nbt.set
import kotlin.math.roundToInt
class NanobotsRegenerationFeature(android: MatteryPlayerCapability) : AndroidFeature(AndroidFeatures.NANOBOTS_REGENERATION, android) {
class NanobotsRegenerationFeature(android: MatteryPlayer) : AndroidFeature(AndroidFeatures.NANOBOTS_REGENERATION, android) {
private var ticksPassed = 0
private var healTicks = 0
@ -41,22 +42,22 @@ class NanobotsRegenerationFeature(android: MatteryPlayerCapability) : AndroidFea
}
}
override fun onHurt(event: LivingHurtEvent) {
override fun onHurt(event: LivingIncomingDamageEvent) {
if (event.amount > 0f) {
ticksPassed = 0
healTicks = 0
}
}
override fun serializeNBT(): CompoundTag {
return super.serializeNBT().also {
override fun serializeNBT(registry: HolderLookup.Provider): CompoundTag {
return super.serializeNBT(registry).also {
it["ticksPassed"] = ticksPassed
it["healTicks"] = healTicks
}
}
override fun deserializeNBT(nbt: CompoundTag) {
super.deserializeNBT(nbt)
override fun deserializeNBT(registry: HolderLookup.Provider, nbt: CompoundTag) {
super.deserializeNBT(registry, nbt)
ticksPassed = nbt.getInt("ticksPassed")
healTicks = nbt.getInt("healTicks")
}

View File

@ -4,14 +4,14 @@ import net.minecraft.world.effect.MobEffectInstance
import net.minecraft.world.effect.MobEffects
import ru.dbotthepony.kommons.math.RGBAColor
import ru.dbotthepony.mc.otm.android.AndroidSwitchableFeature
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.capability.MatteryPlayer
import ru.dbotthepony.mc.otm.capability.energy.extractEnergyExact
import ru.dbotthepony.mc.otm.client.render.MGUIGraphics
import ru.dbotthepony.mc.otm.client.render.ResearchIcons
import ru.dbotthepony.mc.otm.config.AndroidConfig
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
class NightVisionFeature(android: MatteryPlayerCapability) : AndroidSwitchableFeature(AndroidFeatures.NIGHT_VISION, android) {
class NightVisionFeature(android: MatteryPlayer) : AndroidSwitchableFeature(AndroidFeatures.NIGHT_VISION, android) {
override val allowToSwitchByPlayerWhileSpectator: Boolean
get() = true

View File

@ -2,13 +2,16 @@ package ru.dbotthepony.mc.otm.android.feature
import it.unimi.dsi.fastutil.objects.ReferenceArraySet
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.network.protocol.common.custom.CustomPacketPayload
import net.minecraft.server.level.ServerPlayer
import net.minecraft.sounds.SoundSource
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.monster.warden.Warden
import net.neoforged.neoforge.network.PacketDistributor
import net.neoforged.neoforge.network.handling.IPayloadContext
import ru.dbotthepony.mc.otm.android.AndroidSwitchableFeature
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.capability.MatteryPlayer
import ru.dbotthepony.mc.otm.capability.energy.extractEnergyExact
import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.client.render.MGUIGraphics
@ -25,11 +28,8 @@ import ru.dbotthepony.mc.otm.core.math.plus
import ru.dbotthepony.mc.otm.core.math.roundToIntVector
import ru.dbotthepony.mc.otm.core.math.times
import ru.dbotthepony.mc.otm.core.position
import ru.dbotthepony.mc.otm.network.MNetworkContext
import ru.dbotthepony.mc.otm.network.MatteryPacket
import ru.dbotthepony.mc.otm.network.MatteryPlayerNetworkChannel
import ru.dbotthepony.mc.otm.network.ShockwaveEffectPacket
import ru.dbotthepony.mc.otm.onceServer
import ru.dbotthepony.mc.otm.network.TriggerShockwavePacket
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
import ru.dbotthepony.mc.otm.registry.MDamageTypes
import ru.dbotthepony.mc.otm.registry.MSoundEvents
@ -39,23 +39,7 @@ import ru.dbotthepony.mc.otm.triggers.ShockwaveTrigger
import kotlin.math.pow
import kotlin.math.roundToInt
object TriggerShockwavePacket : MatteryPacket {
override fun write(buff: FriendlyByteBuf) {
// no op
}
override fun play(context: MNetworkContext) {
val shockwave = context.sender?.matteryPlayer?.getFeature(AndroidFeatures.SHOCKWAVE) ?: return
if (!shockwave.isOnCooldown && shockwave.isActive && shockwave.airTicks > 0) {
onceServer { // delay by one tick so player update its position as well
shockwave.shockwave()
}
}
}
}
class ShockwaveFeature(capability: MatteryPlayerCapability) : AndroidSwitchableFeature(AndroidFeatures.SHOCKWAVE, capability) {
class ShockwaveFeature(capability: MatteryPlayer) : AndroidSwitchableFeature(AndroidFeatures.SHOCKWAVE, capability) {
override val maxCooldown: Int
get() = AndroidConfig.Shockwave.COOLDOWN
@ -91,7 +75,7 @@ class ShockwaveFeature(capability: MatteryPlayerCapability) : AndroidSwitchableF
if (ply is ServerPlayer) {
ShockwaveTrigger.trigger(ply as ServerPlayer)
MatteryPlayerNetworkChannel.sendTrackingAndSelf(ply, ShockwaveEffectPacket(ply.position))
PacketDistributor.sendToPlayersTrackingEntityAndSelf(ply, ShockwaveEffectPacket(ply.position))
ply.level().playSound(
null,
@ -204,7 +188,7 @@ class ShockwaveFeature(capability: MatteryPlayerCapability) : AndroidSwitchableF
// I HATE SELF-UPDATING PLAYERS
// fix "bug" where shockwave doesn't trigger even when player is falling faster than orbiting satellite
putOnCooldown()
MatteryPlayerNetworkChannel.sendToServer(TriggerShockwavePacket)
PacketDistributor.sendToServer(TriggerShockwavePacket)
} else {
shockwave()
}

View File

@ -1,31 +1,29 @@
package ru.dbotthepony.mc.otm.android.feature
import net.minecraft.world.entity.ai.attributes.AttributeModifier
import net.minecraftforge.common.ForgeMod
import net.minecraft.world.entity.ai.attributes.Attributes
import ru.dbotthepony.mc.otm.android.AndroidSwitchableFeature
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.capability.MatteryPlayer
import ru.dbotthepony.mc.otm.client.render.MGUIGraphics
import ru.dbotthepony.mc.otm.client.render.ResearchIcons
import ru.dbotthepony.kommons.math.RGBAColor
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.core.ResourceLocation
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
import java.util.*
class StepAssistFeature(android: MatteryPlayerCapability) : AndroidSwitchableFeature(AndroidFeatures.STEP_ASSIST, android) {
class StepAssistFeature(android: MatteryPlayer) : AndroidSwitchableFeature(AndroidFeatures.STEP_ASSIST, android) {
override fun applyModifiers() {
if (!ForgeMod.STEP_HEIGHT_ADDITION.isPresent || !isActive)
if (!isActive)
return
val reach = ply.getAttribute(ForgeMod.STEP_HEIGHT_ADDITION.get()) ?: return
val reach = ply.getAttribute(Attributes.STEP_HEIGHT) ?: return
reach.removeModifier(MODIFIER_ID)
reach.addPermanentModifier(AttributeModifier(MODIFIER_ID, type.displayName.toString(), (level + 1) * 0.5, AttributeModifier.Operation.ADDITION))
reach.addPermanentModifier(AttributeModifier(MODIFIER_ID, (level + 1) * 0.5, AttributeModifier.Operation.ADD_VALUE))
}
override fun removeModifiers() {
if (!ForgeMod.STEP_HEIGHT_ADDITION.isPresent)
return
ply.getAttribute(ForgeMod.STEP_HEIGHT_ADDITION.get())?.removeModifier(MODIFIER_ID)
ply.getAttribute(Attributes.STEP_HEIGHT)?.removeModifier(MODIFIER_ID)
}
private var isShiftKeyDown = false
@ -59,6 +57,6 @@ class StepAssistFeature(android: MatteryPlayerCapability) : AndroidSwitchableFea
}
companion object {
private val MODIFIER_ID = UUID.fromString("4a3fae46-47a8-a03f-857d-f5c2b2c8f2f4")
private val MODIFIER_ID = ResourceLocation(OverdriveThatMatters.MOD_ID, "step_assist_feature")
}
}

View File

@ -1,32 +1,30 @@
package ru.dbotthepony.mc.otm.android.feature
import net.minecraft.world.entity.ai.attributes.AttributeModifier
import net.minecraftforge.common.ForgeMod
import net.neoforged.neoforge.common.NeoForgeMod
import ru.dbotthepony.mc.otm.android.AndroidSwitchableFeature
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.capability.MatteryPlayer
import ru.dbotthepony.mc.otm.client.render.MGUIGraphics
import ru.dbotthepony.mc.otm.client.render.ResearchIcons
import ru.dbotthepony.mc.otm.config.AndroidConfig
import ru.dbotthepony.kommons.math.RGBAColor
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.core.ResourceLocation
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
import java.util.*
class SwimBoostersFeature(android: MatteryPlayerCapability) : AndroidSwitchableFeature(AndroidFeatures.SWIM_BOOSTERS, android) {
class SwimBoostersFeature(android: MatteryPlayer) : AndroidSwitchableFeature(AndroidFeatures.SWIM_BOOSTERS, android) {
override fun applyModifiers() {
if (!ForgeMod.SWIM_SPEED.isPresent || !isActive)
if (!isActive)
return
val attr = ply.getAttribute(ForgeMod.SWIM_SPEED.get()) ?: return
val attr = ply.getAttribute(NeoForgeMod.SWIM_SPEED) ?: return
attr.removeModifier(MODIFIER_ID)
attr.addPermanentModifier(AttributeModifier(MODIFIER_ID, type.displayName.toString(), (level + 1) * AndroidConfig.SWIM_BOOSTERS, AttributeModifier.Operation.ADDITION))
attr.addPermanentModifier(AttributeModifier(MODIFIER_ID, (level + 1) * AndroidConfig.SWIM_BOOSTERS, AttributeModifier.Operation.ADD_VALUE))
}
override fun removeModifiers() {
if (!ForgeMod.SWIM_SPEED.isPresent)
return
ply.getAttribute(ForgeMod.SWIM_SPEED.get())?.removeModifier(MODIFIER_ID)
ply.getAttribute(NeoForgeMod.SWIM_SPEED)?.removeModifier(MODIFIER_ID)
}
override fun renderIcon(graphics: MGUIGraphics, x: Float, y: Float, width: Float, height: Float, color: RGBAColor) {
@ -34,6 +32,6 @@ class SwimBoostersFeature(android: MatteryPlayerCapability) : AndroidSwitchableF
}
companion object {
private val MODIFIER_ID = UUID.fromString("4a3ffa46-47a8-a03f-857d-f5c2b2c8f2f6")
private val MODIFIER_ID = ResourceLocation(OverdriveThatMatters.MOD_ID, "swim_boosters_feature")
}
}

View File

@ -17,6 +17,7 @@ import net.minecraft.world.InteractionResult
import net.minecraft.world.MenuProvider
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.TooltipFlag
import net.minecraft.world.level.BlockGetter
@ -42,7 +43,6 @@ import ru.dbotthepony.mc.otm.core.math.BlockRotationFreedom
import ru.dbotthepony.mc.otm.core.math.component1
import ru.dbotthepony.mc.otm.core.math.component2
import ru.dbotthepony.mc.otm.core.math.component3
import ru.dbotthepony.mc.otm.core.tagNotNull
import ru.dbotthepony.mc.otm.once
import java.util.concurrent.Callable
import java.util.function.Function
@ -117,13 +117,11 @@ open class MatteryBlock(properties: Properties = DEFAULT_PROPERTIES) : Block(pro
return getShapeForEachState(ArrayList(stateDefinition.properties), mapper)
}
@Suppress("OVERRIDE_DEPRECATION")
override fun use(
override fun useWithoutItem(
blockState: BlockState,
level: Level,
blockPos: BlockPos,
ply: Player,
hand: InteractionHand,
blockHitResult: BlockHitResult
): InteractionResult {
if (this is EntityBlock && !level.isClientSide) {
@ -138,8 +136,7 @@ open class MatteryBlock(properties: Properties = DEFAULT_PROPERTIES) : Block(pro
if (this is EntityBlock && level.isClientSide)
return InteractionResult.SUCCESS
@Suppress("DEPRECATION")
return super.use(blockState, level, blockPos, ply, hand, blockHitResult)
return super.useWithoutItem(blockState, level, blockPos, ply, blockHitResult)
}
override fun animateTick(blockState: BlockState, level: Level, blockPos: BlockPos, random: RandomSource) {
@ -261,9 +258,14 @@ open class MatteryBlock(properties: Properties = DEFAULT_PROPERTIES) : Block(pro
}
}
override fun appendHoverText(itemStack: ItemStack, blockAccessor: BlockGetter?, components: MutableList<Component>, tooltipType: TooltipFlag) {
super.appendHoverText(itemStack, blockAccessor, components, tooltipType)
tooltips.assemble(itemStack, components)
override fun appendHoverText(
itemStack: ItemStack,
p_339606_: Item.TooltipContext,
components: MutableList<Component>,
tooltipType: TooltipFlag
) {
super.appendHoverText(itemStack, p_339606_, components, tooltipType)
tooltips.assemble(itemStack, p_339606_, components)
}
companion object {

View File

@ -14,7 +14,7 @@ import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.phys.BlockHitResult
import net.minecraft.world.phys.shapes.CollisionContext
import net.minecraft.world.phys.shapes.VoxelShape
import net.minecraftforge.fluids.FluidUtil
import net.neoforged.neoforge.fluids.FluidUtil
import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock
import ru.dbotthepony.mc.otm.block.entity.decorative.FluidTankBlockEntity
import ru.dbotthepony.mc.otm.block.getShapeForEachState
@ -54,12 +54,11 @@ class FluidTankBlock : RotatableMatteryBlock(DEFAULT_MACHINE_PROPERTIES), Entity
return shapes[state]!!
}
override fun getLightEmission(state: BlockState?, level: BlockGetter?, pos: BlockPos?): Int {
override fun getLightEmission(state: BlockState, level: BlockGetter, pos: BlockPos): Int {
if (pos == BlockPos.ZERO) return 15
val lightLevel = super.getLightEmission(state, level, pos)
val tile = level?.getExistingBlockEntity(pos) ?: lightLevel
val tile = level.getBlockEntity(pos)
if (tile is FluidTankBlockEntity) {
val fluid = tile.fluid.fluid

View File

@ -3,7 +3,9 @@ package ru.dbotthepony.mc.otm.block.decorative
import net.minecraft.core.BlockPos
import net.minecraft.world.InteractionHand
import net.minecraft.world.InteractionResult
import net.minecraft.world.ItemInteractionResult
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.EntityBlock
import net.minecraft.world.level.block.entity.BlockEntity
@ -13,7 +15,7 @@ import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.material.MapColor
import net.minecraft.world.level.material.PushReaction
import net.minecraft.world.phys.BlockHitResult
import net.minecraftforge.fluids.FluidUtil
import net.neoforged.neoforge.fluids.FluidUtil
import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock
import ru.dbotthepony.mc.otm.block.entity.decorative.InfiniteWaterSourceBlockEntity
@ -22,13 +24,20 @@ class InfiniteWaterSourceBlock : RotatableMatteryBlock(Properties.of().destroyTi
return InfiniteWaterSourceBlockEntity(p_153215_, p_153216_)
}
@Suppress("OVERRIDE_DEPRECATION")
override fun use(blockState: BlockState, level: Level, blockPos: BlockPos, ply: Player, hand: InteractionHand, blockHitResult: BlockHitResult): InteractionResult {
if (FluidUtil.interactWithFluidHandler(ply, hand, level, blockPos, blockHitResult.direction)) {
return InteractionResult.sidedSuccess(level.isClientSide)
override fun useItemOn(
p_316304_: ItemStack,
p_316362_: BlockState,
p_316459_: Level,
p_316366_: BlockPos,
p_316132_: Player,
p_316595_: InteractionHand,
p_316140_: BlockHitResult
): ItemInteractionResult {
if (FluidUtil.interactWithFluidHandler(p_316132_, p_316595_, p_316459_, p_316366_, p_316140_.direction)) {
return ItemInteractionResult.sidedSuccess(p_316459_.isClientSide)
}
return super.use(blockState, level, blockPos, ply, hand, blockHitResult)
return super.useItemOn(p_316304_, p_316362_, p_316459_, p_316366_, p_316132_, p_316595_, p_316140_)
}
override fun <T : BlockEntity> getTicker(p_153212_: Level, p_153213_: BlockState, p_153214_: BlockEntityType<T>): BlockEntityTicker<T>? {

View File

@ -3,6 +3,7 @@ package ru.dbotthepony.mc.otm.block.decorative
import net.minecraft.ChatFormatting
import net.minecraft.core.BlockPos
import net.minecraft.network.chat.Component
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import net.minecraft.world.item.TooltipFlag
@ -122,11 +123,11 @@ class LaboratoryLamp(val invertRedstone: Boolean) : Block(Properties.of().mapCol
override fun appendHoverText(
p_49816_: ItemStack,
p_49817_: BlockGetter?,
p_339606_: Item.TooltipContext,
p_49818_: MutableList<Component>,
p_49819_: TooltipFlag
) {
super.appendHoverText(p_49816_, p_49817_, p_49818_, p_49819_)
super.appendHoverText(p_49816_, p_339606_, p_49818_, p_49819_)
p_49818_.add(TranslatableComponent("${MBlocks.LABORATORY_LAMP.descriptionId}.description").withStyle(ChatFormatting.GRAY))
}

View File

@ -3,7 +3,9 @@ package ru.dbotthepony.mc.otm.block.decorative
import net.minecraft.core.BlockPos
import net.minecraft.world.InteractionHand
import net.minecraft.world.InteractionResult
import net.minecraft.world.ItemInteractionResult
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.EntityBlock
import net.minecraft.world.level.block.entity.BlockEntity
@ -11,7 +13,7 @@ import net.minecraft.world.level.block.entity.BlockEntityTicker
import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.phys.BlockHitResult
import net.minecraftforge.fluids.FluidUtil
import net.neoforged.neoforge.fluids.FluidUtil
import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock
import ru.dbotthepony.mc.otm.block.entity.decorative.PainterBlockEntity
@ -20,13 +22,20 @@ class PainterBlock : RotatableMatteryBlock(DEFAULT_MACHINE_PROPERTIES), EntityBl
return PainterBlockEntity(p_153215_, p_153216_)
}
@Suppress("OVERRIDE_DEPRECATION")
override fun use(blockState: BlockState, level: Level, blockPos: BlockPos, ply: Player, hand: InteractionHand, blockHitResult: BlockHitResult): InteractionResult {
override fun useItemOn(
p_316304_: ItemStack,
blockState: BlockState,
level: Level,
blockPos: BlockPos,
ply: Player,
hand: InteractionHand,
blockHitResult: BlockHitResult
): ItemInteractionResult {
if (FluidUtil.interactWithFluidHandler(ply, hand, level, blockPos, blockHitResult.direction)) {
return InteractionResult.sidedSuccess(level.isClientSide)
return ItemInteractionResult.sidedSuccess(level.isClientSide)
}
return super.use(blockState, level, blockPos, ply, hand, blockHitResult)
return super.useItemOn(p_316304_, blockState, level, blockPos, ply, hand, blockHitResult)
}
override fun <T : BlockEntity?> getTicker(p_153212_: Level, p_153213_: BlockState, p_153214_: BlockEntityType<T>): BlockEntityTicker<T>? {

View File

@ -1,13 +1,14 @@
package ru.dbotthepony.mc.otm.block.decorative
import com.mojang.serialization.MapCodec
import net.minecraft.ChatFormatting
import net.minecraft.core.BlockPos
import net.minecraft.network.chat.Component
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.item.DyeColor
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.TooltipFlag
import net.minecraft.world.level.BlockGetter
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.BasePressurePlateBlock
import net.minecraft.world.level.block.Block
@ -18,7 +19,6 @@ import net.minecraft.world.level.block.state.properties.BlockSetType
import net.minecraft.world.level.block.state.properties.BlockStateProperties
import ru.dbotthepony.mc.otm.core.TooltipList
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.collect.iteratorOf
import ru.dbotthepony.mc.otm.core.get
class TritaniumPressurePlate(color: DyeColor?) : BasePressurePlateBlock(Properties.of().mapColor(color ?: DyeColor.LIGHT_BLUE).sound(SoundType.METAL).explosionResistance(80f).noOcclusion().destroyTime(3f).requiresCorrectToolForDrops().forceSolidOn().noCollission(), BlockSetType.IRON) {
@ -26,12 +26,12 @@ class TritaniumPressurePlate(color: DyeColor?) : BasePressurePlateBlock(Properti
override fun appendHoverText(
itemStack: ItemStack,
level: BlockGetter?,
context: Item.TooltipContext,
lines: MutableList<Component>,
tooltipType: TooltipFlag
) {
super.appendHoverText(itemStack, level, lines, tooltipType)
tooltips.assemble(itemStack, lines)
super.appendHoverText(itemStack, context, lines, tooltipType)
tooltips.assemble(itemStack, context, lines)
}
init {

View File

@ -2,6 +2,7 @@ package ru.dbotthepony.mc.otm.block.entity
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.core.HolderLookup
import net.minecraft.nbt.DoubleTag
import net.minecraft.server.level.ServerLevel
import net.minecraft.server.level.ServerPlayer
@ -10,9 +11,9 @@ import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.util.INBTSerializable
import net.minecraftforge.fluids.FluidStack
import net.minecraftforge.fluids.capability.IFluidHandler
import net.neoforged.neoforge.common.util.INBTSerializable
import net.neoforged.neoforge.fluids.FluidStack
import net.neoforged.neoforge.fluids.capability.IFluidHandler
import ru.dbotthepony.mc.otm.block.INeighbourChangeListener
import ru.dbotthepony.mc.otm.block.entity.tech.EssenceStorageBlockEntity
import ru.dbotthepony.mc.otm.core.math.plus
@ -98,11 +99,11 @@ class ExperienceStorage(val maxExperience: DoubleSupplier = DoubleSupplier { Dou
}
}
override fun serializeNBT(): DoubleTag {
override fun serializeNBT(registry: HolderLookup.Provider): DoubleTag {
return DoubleTag.valueOf(experience)
}
override fun deserializeNBT(nbt: DoubleTag?) {
override fun deserializeNBT(registry: HolderLookup.Provider, nbt: DoubleTag?) {
experience = (nbt?.asDouble ?: 0.0).coerceAtLeast(0.0)
}

View File

@ -3,10 +3,11 @@ package ru.dbotthepony.mc.otm.block.entity
import com.mojang.datafixers.Products
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.core.HolderLookup
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.NbtOps
import net.minecraft.world.item.ItemStack
import net.minecraftforge.common.util.INBTSerializable
import net.neoforged.neoforge.common.util.INBTSerializable
import org.apache.logging.log4j.LogManager
import ru.dbotthepony.mc.otm.capability.IMatteryUpgrade
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
@ -17,7 +18,6 @@ import ru.dbotthepony.mc.otm.core.math.weakGreaterThan
import ru.dbotthepony.mc.otm.core.math.weakLessThan
import ru.dbotthepony.mc.otm.core.nbt.set
import ru.dbotthepony.mc.otm.data.DecimalCodec
import ru.dbotthepony.mc.otm.data.minRange
private fun isReason(status: Any?, reason: Any) = status == null || status == reason
private val LOGGER = LogManager.getLogger()
@ -325,12 +325,12 @@ abstract class MachineJobEventLoop<JobType : IJob>(val codec: Codec<JobType>) :
OBSERVING
}
override fun serializeNBT(): CompoundTag {
override fun serializeNBT(registry: HolderLookup.Provider): CompoundTag {
return CompoundTag().also { nbt ->
nbt["WorkTicks"] = workTicks
currentJob?.let {
codec.encode(it, NbtOps.INSTANCE, NbtOps.INSTANCE.empty()).get().map(
codec.encode(it, NbtOps.INSTANCE, NbtOps.INSTANCE.empty()).mapOrElse(
{
nbt["Job"] = it
},
@ -342,14 +342,14 @@ abstract class MachineJobEventLoop<JobType : IJob>(val codec: Codec<JobType>) :
}
}
override fun deserializeNBT(nbt: CompoundTag?) {
override fun deserializeNBT(registry: HolderLookup.Provider, nbt: CompoundTag?) {
nbt ?: return
workTicks = nbt.getDouble("WorkTicks")
currentJob = null
if ("Job" in nbt) {
codec.decode(NbtOps.INSTANCE, nbt["Job"]!!).get().map(
codec.decode(NbtOps.INSTANCE, nbt["Job"]!!).mapOrElse(
{
currentJob = it.first
},

View File

@ -10,6 +10,7 @@ import it.unimi.dsi.fastutil.objects.Reference2IntArrayMap
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.core.HolderLookup.Provider
import net.minecraft.core.SectionPos
import net.minecraft.core.Vec3i
import net.minecraft.nbt.CompoundTag
@ -26,15 +27,15 @@ import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.chunk.LevelChunk
import net.minecraft.world.phys.Vec3
import net.minecraftforge.common.capabilities.Capability
import net.minecraftforge.common.capabilities.ForgeCapabilities
import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.energy.IEnergyStorage
import net.minecraftforge.event.TickEvent.LevelTickEvent
import net.minecraftforge.event.entity.player.PlayerEvent
import net.minecraftforge.event.level.ChunkWatchEvent
import net.minecraftforge.event.level.LevelEvent
import net.minecraftforge.event.server.ServerStoppingEvent
import net.neoforged.neoforge.capabilities.BlockCapability
import net.neoforged.neoforge.capabilities.BlockCapabilityCache
import net.neoforged.neoforge.capabilities.Capabilities
import net.neoforged.neoforge.event.entity.player.PlayerEvent
import net.neoforged.neoforge.event.level.ChunkWatchEvent
import net.neoforged.neoforge.event.level.LevelEvent
import net.neoforged.neoforge.event.server.ServerStoppingEvent
import net.neoforged.neoforge.event.tick.LevelTickEvent
import net.neoforged.neoforge.network.PacketDistributor
import org.apache.logging.log4j.LogManager
import ru.dbotthepony.kommons.io.DelegateSyncher
import ru.dbotthepony.kommons.util.Listenable
@ -45,21 +46,20 @@ import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
import ru.dbotthepony.mc.otm.core.collect.WeakHashSet
import ru.dbotthepony.mc.otm.core.get
import ru.dbotthepony.mc.otm.core.immutableList
import ru.dbotthepony.mc.otm.core.math.BlockRotation
import ru.dbotthepony.mc.otm.core.math.RelativeSide
import ru.dbotthepony.mc.otm.core.math.minus
import ru.dbotthepony.mc.otm.core.math.plus
import ru.dbotthepony.mc.otm.core.util.IntCounter
import ru.dbotthepony.mc.otm.core.util.Savetables
import ru.dbotthepony.mc.otm.core.util.TickList
import ru.dbotthepony.mc.otm.core.util.countingLazy
import ru.dbotthepony.mc.otm.network.BlockEntitySyncPacket
import ru.dbotthepony.mc.otm.network.GenericNetworkChannel
import ru.dbotthepony.mc.otm.once
import ru.dbotthepony.mc.otm.onceServer
import ru.dbotthepony.mc.otm.sometimeServer
import java.lang.ref.WeakReference
import java.util.*
import java.util.function.BooleanSupplier
import java.util.function.Consumer
import java.util.function.Predicate
import java.util.function.Supplier
@ -74,7 +74,11 @@ import kotlin.reflect.KProperty
abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: BlockPos, p_155230_: BlockState) : BlockEntity(p_155228_, p_155229_, p_155230_), INeighbourChangeListener {
private var isSynchronizing = false
private val sidelessCaps = Reference2ObjectOpenHashMap<Capability<*>, SidelessCap<*>>()
private val sidelessCaps = Reference2ObjectOpenHashMap<BlockCapability<*, *>, Any>()
private val sidedCaps = Array(RelativeSide.entries.size) {
Reference2ObjectOpenHashMap<BlockCapability<*, *>, Any>()
}
protected val tickList = TickList()
protected val blockStateChangesCounter = IntCounter()
protected val dirtyListeners = Listenable.Impl<Unit>()
@ -85,9 +89,6 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
val droppableContainers: Set<Container> = Collections.unmodifiableSet(_droppableContainers)
val neighbourChangeListeners: Set<INeighbourChangeListener> = Collections.unmodifiableSet(_neighbourChangeListeners)
private val _sides = EnumMap<RelativeSide, Side>(RelativeSide::class.java)
val sides: Map<RelativeSide, Side> = Collections.unmodifiableMap(_sides)
/**
* Shared savetables, written both to level storage and to item tag
*/
@ -121,10 +122,6 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
open fun beforeDroppingItems(oldBlockState: BlockState, level: Level, blockPos: BlockPos, newBlockState: BlockState, movedByPiston: Boolean) {}
open fun beforeDestroyedByPlayer(level: Level, blockPos: BlockPos, blockState: BlockState, player: Player) {}
fun side(side: RelativeSide) = sides[side]!!
private data class SidelessCap<T : Any>(val cap: T, var optional: LazyOptional<T>)
open fun tick() {
tickList.tick()
}
@ -132,40 +129,45 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
/**
* exposes capability when no side is specified
*/
protected fun <T : Any> exposeSideless(capability: Capability<T>, value: T) {
protected fun <T : Any> exposeSideless(capability: BlockCapability<T, *>, value: T) {
check(!sidelessCaps.containsKey(capability)) { "Already has globally exposed $capability!" }
sidelessCaps[capability] = SidelessCap(value, LazyOptional.of { value })
sidelessCaps[capability] = value
setChanged()
level?.invalidateCapabilities(blockPos)
}
protected fun <T : Any> exposeSided(side: RelativeSide, capability: BlockCapability<T, *>, value: T) {
val map = sidedCaps[side.ordinal]
check(!map.containsKey(capability)) { "Already has exposed $capability on $side!" }
map[capability] = value
setChanged()
level?.invalidateCapabilities(blockPos)
}
/**
* Exposes capability unconditionally, on all sides and sideless
*/
protected fun <T : Any> exposeGlobally(capability: Capability<T>, value: T, predicate: Predicate<RelativeSide> = Predicate { true }) {
protected fun <T : Any> exposeGlobally(capability: BlockCapability<T, *>, value: T, predicate: Predicate<RelativeSide> = Predicate { true }) {
exposeSideless(capability, value)
for (side in _sides.values)
if (predicate.test(side.side))
side.Cap(capability, value)
}
protected fun exposeEnergyGlobally(value: IMatteryEnergyStorage, predicate: Predicate<RelativeSide> = Predicate { true }) {
exposeGlobally(ForgeCapabilities.ENERGY, value, predicate)
exposeGlobally(MatteryCapability.ENERGY, value, predicate)
for (side in RelativeSide.entries)
if (predicate.test(side))
exposeSided(side, capability, value)
}
protected fun exposeEnergySideless(value: IMatteryEnergyStorage) {
exposeSideless(ForgeCapabilities.ENERGY, value)
exposeSideless(MatteryCapability.ENERGY, value)
exposeSideless(Capabilities.EnergyStorage.BLOCK, value)
exposeSideless(MatteryCapability.BLOCK_ENERGY, value)
}
protected fun exposeEnergy(side: RelativeSide, value: IMatteryEnergyStorage): ImmutableList<Side.Cap<*>> {
return immutableList {
val thisSide = _sides[side]!!
accept(thisSide.Cap(ForgeCapabilities.ENERGY, value))
accept(thisSide.Cap(MatteryCapability.ENERGY, value))
protected fun exposeEnergyGlobally(value: IMatteryEnergyStorage) {
exposeGlobally(Capabilities.EnergyStorage.BLOCK, value)
exposeGlobally(MatteryCapability.BLOCK_ENERGY, value)
}
protected fun exposeEnergySided(side: RelativeSide, value: IMatteryEnergyStorage) {
exposeSided(side, Capabilities.EnergyStorage.BLOCK, value)
exposeSided(side, MatteryCapability.BLOCK_ENERGY, value)
}
protected fun waitForServerLevel(lambda: () -> Unit) {
@ -176,266 +178,38 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
}
}
interface SideListener<T> : Supplier<LazyOptional<T>>, Listenable<LazyOptional<T>>
inner class Side(val side: RelativeSide) {
init {
check(!_sides.containsKey(side)) { "dafuq are you trying to do" }
_sides[side] = this
}
private val caps = Reference2ObjectOpenHashMap<Capability<*>, Cap<*>>()
private val subscriptions = Reference2ObjectOpenHashMap<Capability<*>, SubRef<*>>()
private val knownLOs = WeakHashSet<LazyOptional<*>>()
private inner class SubRef<T>(value: LazyOptional<T>) : SideListener<T> {
var value: LazyOptional<T> = value
set(value) {
if (value !== field) {
field = value
listeners.accept(value)
}
}
private val listeners = Listenable.Impl<LazyOptional<T>>()
override fun addListener(listener: Consumer<LazyOptional<T>>): Listenable.L {
val l = listeners.addListener(listener)
if (level is ServerLevel) listener.accept(value)
return l
}
override fun get(): LazyOptional<T> {
return value
}
fun unset() {
value = LazyOptional.empty()
}
}
fun <T> track(capability: Capability<T>): SideListener<T> {
var subref = subscriptions[capability] as SideListener<T>?
if (subref == null) {
subref = SubRef(LazyOptional.empty<Any?>()) as SubRef<T>
subscriptions[capability] = subref
level?.once { updateTracked(capability) }
}
return subref
}
fun trackEnergy(): SideListener<IEnergyStorage> {
return track(ForgeCapabilities.ENERGY)
}
fun updateTracked() {
for (key in subscriptions.keys) {
// Concurrent Modification safety:
// we do not add nor remove keys from map, we only update values
updateTracked(key)
}
}
private fun updateTracked(capability: Capability<*>) {
if (isRemoved || !SERVER_IS_LIVE) return
val dir = blockRotation.side2Dir(side)
val targetPos = blockPos + dir.normal
val chunk = level
?.chunkSource
?.getChunkNow(SectionPos.blockToSectionCoord(targetPos.x), SectionPos.blockToSectionCoord(targetPos.z))
val subref = subscriptions[capability] as SubRef<Any?>
if (chunk == null) {
subref.unset()
level?.once { updateTracked(capability) }
return
}
val entity = chunk.getBlockEntity(targetPos)
if (entity == null) {
subref.unset()
return
}
val new = entity.getCapability(capability, dir.opposite)
if (!new.isPresent) {
subref.unset()
return
}
if (subref.value !== new) {
if (knownLOs.add(new)) {
val ref = WeakReference(this)
new.addListener {
ref.get()?.updateTracked(capability)
}
}
subref.value = new as LazyOptional<Any?>
}
}
operator fun <T : Any> get(capability: Capability<T>): Cap<T>? {
return caps[capability] as Cap<T>?
}
fun invalidate() {
for (cap in caps.values)
cap.invalidate()
}
fun revive() {
for (cap in caps.values)
cap.revive()
}
inner class Cap<T : Any>(val type: Capability<in T>, val capability: T) {
init {
check(!caps.containsKey(type)) { "Already has capability $type on side $side" }
caps[type] = this
}
var isExposed = true
private set
var isValid = true
private set
var isRemoved = false
private set
var optional: LazyOptional<T> by object : ReadWriteProperty<Any?, LazyOptional<T>> {
private var value: LazyOptional<T>? = null
override fun getValue(thisRef: Any?, property: KProperty<*>): LazyOptional<T> {
if (value == null) {
value = LazyOptional.of { capability }
}
return value!!
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: LazyOptional<T>) {
this.value = value
}
}
private set
fun remove() {
if (!isRemoved) {
isRemoved = true
val removed = caps.remove(type)
check(removed == this) { "$removed != $this" }
optional.invalidate()
}
}
fun close() {
if (!isRemoved && isExposed) {
isExposed = false
optional.invalidate()
if (SERVER_IS_LIVE)
level?.once { if (!this@MatteryBlockEntity.isRemoved) setChanged() }
}
}
fun expose() {
if (!isRemoved && !isExposed) {
isExposed = true
if (isValid) {
optional = LazyOptional.of { capability }
if (SERVER_IS_LIVE)
level?.once { if (!this@MatteryBlockEntity.isRemoved) setChanged() }
}
}
}
fun invalidate() {
if (!isRemoved && isValid) {
isValid = false
optional.invalidate()
if (SERVER_IS_LIVE)
level?.once { if (!this@MatteryBlockEntity.isRemoved) setChanged() }
}
}
fun revive() {
if (!isRemoved && !isValid) {
isValid = true
if (isExposed) {
optional = LazyOptional.of { capability }
if (SERVER_IS_LIVE)
level?.once { if (!this@MatteryBlockEntity.isRemoved) setChanged() }
}
}
}
}
}
val front = Side(RelativeSide.FRONT)
val back = Side(RelativeSide.BACK)
val left = Side(RelativeSide.LEFT)
val right = Side(RelativeSide.RIGHT)
val top = Side(RelativeSide.TOP)
val bottom = Side(RelativeSide.BOTTOM)
override fun <T : Any> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
fun <T : Any> getCapability(cap: BlockCapability<T, *>, side: Direction?): T? {
if (side != null) {
return _sides[blockRotation.dir2Side(side)]!![cap]?.optional ?: super.getCapability(cap, side)
return sidedCaps[blockRotation.dir2Side(side).ordinal][cap] as T?
}
return sidelessCaps[cap]?.optional?.cast() ?: super.getCapability(cap, side)
return sidelessCaps[cap] as T?
}
override fun invalidateCaps() {
super.invalidateCaps()
for (side in sides.values)
side.invalidate()
}
override fun reviveCaps() {
super.reviveCaps()
for (side in sides.values)
side.revive()
}
final override fun saveAdditional(nbt: CompoundTag) {
super.saveAdditional(nbt)
saveShared(nbt)
saveLevel(nbt)
final override fun saveAdditional(nbt: CompoundTag, registry: Provider) {
super.saveAdditional(nbt, registry)
saveShared(nbt, registry)
saveLevel(nbt, registry)
}
/**
* Saved both to item dropped, and to level storage
*/
open fun saveShared(nbt: CompoundTag) {
savetables.serializeNBT(nbt)
open fun saveShared(nbt: CompoundTag, registry: Provider) {
savetables.serializeNBT(nbt, registry)
}
/**
* Only saved to level storage, discarded when dropped as item
*/
open fun saveLevel(nbt: CompoundTag) {
savetablesLevel.serializeNBT(nbt)
open fun saveLevel(nbt: CompoundTag, registry: Provider) {
savetablesLevel.serializeNBT(nbt, registry)
}
override fun load(nbt: CompoundTag) {
super.load(nbt)
savetables.deserializeNBT(nbt)
savetablesLevel.deserializeNBT(nbt)
override fun loadAdditional(nbt: CompoundTag, registry: Provider) {
super.loadAdditional(nbt, registry)
savetables.deserializeNBT(registry, nbt)
savetablesLevel.deserializeNBT(registry, nbt)
}
@Suppress("OVERRIDE_DEPRECATION")
@ -447,21 +221,13 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
val new = blockRotation
if (old != new) {
for (side in _sides.values) {
side.updateTracked()
side.invalidate()
}
}
for (side in _sides.values) {
side.revive()
level?.invalidateCapabilities(blockPos)
capabilityCaches.forEach { it.rebuildCache() }
}
}
override fun neighborChanged(state: BlockState, level: Level, pos: BlockPos, neighbour: Block, neighbourPos: BlockPos, movedByPiston: Boolean) {
_neighbourChangeListeners.forEach { it.neighborChanged(state, level, pos, neighbour, neighbourPos, movedByPiston) }
val dir = vec2Dir[vecKey(neighbourPos - blockPos)] ?: return
_sides[blockRotation.dir2Side(dir)]!!.updateTracked()
}
override fun setChanged() {
@ -483,6 +249,51 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
dirtyListeners.accept(Unit)
}
private val capabilityCaches = ArrayList<CapabilityCache<*>>()
inner class CapabilityCache<T : Any>(val side: RelativeSide, val capability: BlockCapability<T, in Direction?>) : Supplier<T?>, Listenable<T?> {
private var currentVersion = 0
private var cache: BlockCapabilityCache<T, in Direction?>? = null
private val listeners = Listenable.Impl<T?>()
override fun addListener(listener: Consumer<T?>): Listenable.L {
return listeners.addListener(listener)
}
init {
capabilityCaches.add(this)
}
override fun get(): T? {
return cache?.capability
}
val isPresent: Boolean
get() = cache?.capability != null
val isEmpty: Boolean
get() = cache?.capability == null
fun rebuildCache() {
val level = level as? ServerLevel
if (level == null) {
cache = null
return
}
val creationVersion = ++currentVersion
cache = BlockCapabilityCache.create(
capability, level, blockPos,
blockRotation.side2Dir(side),
{ !isRemoved || creationVersion != currentVersion },
// IllegalStateException("Do not call getCapability on an invalid cache or from the invalidation listener!")
// what a shame.
{ onceServer { if (!isRemoved && creationVersion == currentVersion) listeners.accept(cache?.capability) } })
}
}
val syncher = DelegateSyncher()
private val synchers = Object2ObjectArrayMap<ServerPlayer, DelegateSyncher.Remote>()
@ -494,30 +305,11 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
if (!level.isClientSide) {
subscribe()
if (old != null) {
for (side in _sides.values) {
side.updateTracked()
side.invalidate()
}
for (side in _sides.values) {
side.revive()
}
} else {
level.once {
if (!isRemoved) {
for (side in _sides.values) {
side.updateTracked()
}
}
}
}
waitForServerLevel.forEach { it.invoke() }
capabilityCaches.forEach { it.rebuildCache() }
waitForServerLevel.clear()
} else {
waitForServerLevel.clear()
BlockEntitySyncPacket.applyBacklog(this)
}
}
@ -718,7 +510,7 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
/**
* Returns stream of players watching (tracking) specified [chunk]
*/
fun watchingPlayers(chunk: LevelChunk) = watchingPlayers(chunk.pos, chunk.level)
fun watchingPlayers(chunk: LevelChunk) = watchingPlayers(chunk.pos, chunk.level!!)
private fun vecKey(value: Vec3i): Int {
if (value.x !in -1 .. 1) return -1
@ -759,7 +551,7 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
val payload = data.write()
if (payload != null) {
GenericNetworkChannel.send(player, BlockEntitySyncPacket(be.blockPos, payload.array, payload.length))
PacketDistributor.sendToPlayer(player, BlockEntitySyncPacket(be.blockPos, payload.array, payload.length))
}
}
}

View File

@ -1,8 +1,11 @@
package ru.dbotthepony.mc.otm.block.entity
import com.google.common.collect.ImmutableSet
import com.google.gson.JsonParser
import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.core.HolderLookup
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.MenuProvider
import net.minecraft.world.entity.player.Inventory
@ -12,10 +15,12 @@ import net.minecraft.nbt.CompoundTag
import net.minecraft.network.chat.Component
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.Level
import net.minecraftforge.common.capabilities.ForgeCapabilities
import net.minecraftforge.fluids.FluidStack
import net.minecraftforge.fluids.capability.IFluidHandler
import net.minecraftforge.items.IItemHandler
import net.minecraft.world.level.block.entity.BlockEntity
import net.neoforged.neoforge.capabilities.Capabilities
import net.neoforged.neoforge.capabilities.ICapabilityProvider
import net.neoforged.neoforge.fluids.FluidStack
import net.neoforged.neoforge.fluids.capability.IFluidHandler
import net.neoforged.neoforge.items.IItemHandler
import ru.dbotthepony.kommons.util.getValue
import ru.dbotthepony.kommons.util.setValue
import ru.dbotthepony.mc.otm.capability.item.CombinedItemHandler
@ -28,7 +33,6 @@ import ru.dbotthepony.mc.otm.capability.moveEnergy
import ru.dbotthepony.mc.otm.capability.moveFluid
import ru.dbotthepony.mc.otm.core.TextComponent
import ru.dbotthepony.mc.otm.core.getValue
import ru.dbotthepony.mc.otm.core.ifPresentK
import ru.dbotthepony.mc.otm.core.immutableMap
import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.math.RelativeSide
@ -67,16 +71,16 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
protected open fun redstoneStatusUpdated(newBlocked: Boolean, oldBlocked: Boolean) {}
override fun saveShared(nbt: CompoundTag) {
super.saveShared(nbt)
override fun saveShared(nbt: CompoundTag, registry: HolderLookup.Provider) {
super.saveShared(nbt, registry)
if (customDisplayName != null)
nbt.putJson("Name", Component.Serializer.toJsonTree(customDisplayName!!))
nbt.putJson("Name", JsonParser.parseString(Component.Serializer.toJson(customDisplayName!!, registry)))
}
override fun load(nbt: CompoundTag) {
super.load(nbt)
customDisplayName = nbt.getJson("Name")?.let(Component.Serializer::fromJson)
override fun loadAdditional(nbt: CompoundTag, registry: HolderLookup.Provider) {
super.loadAdditional(nbt, registry)
customDisplayName = nbt.getJson("Name")?.let { Component.Serializer.fromJson(it, registry) }
}
override fun setLevel(level: Level) {
@ -102,7 +106,7 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
val bottomDefault: FlowDirection = possibleModes,
) {
init {
exposeSideless(ForgeCapabilities.FLUID_HANDLER, capability)
exposeSideless(Capabilities.FluidHandler.BLOCK, capability)
}
val front = Piece(RelativeSide.FRONT).also { it.flow = frontDefault }
@ -132,11 +136,18 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
inner class Piece(val side: RelativeSide) : IFluidHandler, ITickable {
private val ticker = tickList.Ticker(this)
private val controller = side(side).Cap(ForgeCapabilities.FLUID_HANDLER, this)
private val neighbour = side(side).track(ForgeCapabilities.FLUID_HANDLER)
private val neighbour = CapabilityCache(side, Capabilities.FluidHandler.BLOCK)
init {
exposeSided(side, Capabilities.FluidHandler.BLOCK, this)
}
private fun updateTickerState() {
ticker.isEnabled = (automatePull || automatePush) && flow != FlowDirection.NONE && !redstoneControl.isBlockedByRedstone && neighbour.get().isPresent
ticker.isEnabled =
(automatePull || automatePush) &&
flow != FlowDirection.NONE &&
!redstoneControl.isBlockedByRedstone &&
neighbour.isPresent
}
init {
@ -152,15 +163,8 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
if (access.get() != value) {
access.accept(value)
markDirtyFast()
if (value == FlowDirection.NONE) {
controller.close()
} else {
controller.close()
controller.expose()
}
updateTickerState()
level?.invalidateCapabilities(blockPos)
}
})
@ -193,7 +197,8 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
if (flow == FlowDirection.NONE || !automatePull && !automatePush || redstoneControl.isBlockedByRedstone)
return
neighbour.get().ifPresentK {
val it = neighbour.get() ?: return
if (flow.input && automatePull) {
moveFluid(source = it, destination = capability)
}
@ -202,7 +207,6 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
moveFluid(source = capability, destination = it)
}
}
}
override fun getTanks(): Int {
if (flow == FlowDirection.NONE) {
@ -334,15 +338,12 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
put(RelativeSide.BOTTOM, bottomDefault)
}
fun invalidate(force: Boolean = false) {
for (piece in pieces.values) {
piece.invalidate(force)
}
}
inner class Piece(val side: RelativeSide, val possibleModes: FlowDirection) : IMatteryEnergyStorage, ITickable {
private val capControllers = exposeEnergy(side, this@Piece)
private val neighbour = side(side).trackEnergy()
private val neighbour = CapabilityCache(side, Capabilities.EnergyStorage.BLOCK)
init {
exposeEnergySided(side, this)
}
override var batteryLevel: Decimal by energy::batteryLevel
override val maxBatteryLevel: Decimal by energy::maxBatteryLevel
@ -356,7 +357,7 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
ticker.isEnabled = (automatePull || automatePush) &&
energyFlow != FlowDirection.NONE &&
!redstoneControl.isBlockedByRedstone &&
neighbour.get().isPresent &&
neighbour.isPresent &&
(volatileEnergyValues || energy.batteryLevel.isPositive)
}
@ -424,7 +425,8 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
}
override fun tick() {
neighbour.get().ifPresentK {
val it = neighbour.get() ?: return
if (energyFlow.input && automatePull) {
moveEnergy(source = it, destination = energy, simulate = false)
}
@ -433,7 +435,6 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
moveEnergy(source = energy, destination = it, simulate = false)
}
}
}
override var energyFlow by syncher.enum(possibleModes, setter = { access, value ->
require(possibleModes.isSupertype(value)) { "Energy mode $value is not allowed (allowed modes: ${possibleModes.family})" }
@ -441,42 +442,10 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
if (access.get() != value) {
access.accept(value)
markDirtyFast()
if (value == FlowDirection.NONE) {
for (controller in capControllers)
controller.close()
} else {
for (controller in capControllers) {
controller.close()
controller.expose()
}
}
updateTickerState()
level?.invalidateCapabilities(blockPos)
}
}).delegate
fun invalidate(force: Boolean = false) {
if (force) {
for (controller in capControllers) {
controller.close()
controller.expose()
}
if (energyFlow == FlowDirection.NONE) {
for (controller in capControllers) {
controller.close()
}
}
} else {
if (energyFlow != FlowDirection.NONE) {
for (controller in capControllers) {
controller.close()
controller.expose()
}
}
}
}
}
}
@ -550,7 +519,7 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
if (battery != null) caps.add(battery)
sideless = UnmodifiableItemHandler(CombinedItemHandler(caps))
exposeSideless(ForgeCapabilities.ITEM_HANDLER, sideless)
exposeSideless(Capabilities.ItemHandler.BLOCK, sideless)
}
val front = Piece(RelativeSide.FRONT).also { it.mode = frontDefault }
@ -585,10 +554,13 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
updateTickerState()
}
private val capController = side(side).Cap(ForgeCapabilities.ITEM_HANDLER, this)
private val neighbour = side(side).track(ForgeCapabilities.ITEM_HANDLER)
private val neighbour = CapabilityCache(side, Capabilities.ItemHandler.BLOCK)
private val ticker = tickList.Ticker(this)
init {
exposeSided(side, Capabilities.ItemHandler.BLOCK, this)
}
private var innerSlotPull = 0
private var outerSlotPull = 0
@ -596,11 +568,12 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
private var outerSlotPush = 0
private fun updateTickerState() {
ticker.isEnabled = (automatePull || automatePush) && mode != ItemHandlerMode.DISABLED && !redstoneControl.isBlockedByRedstone && currentHandler.slots != 0 && neighbour.get().isPresent
}
init {
capController.close()
ticker.isEnabled =
(automatePull || automatePush) &&
mode != ItemHandlerMode.DISABLED &&
!redstoneControl.isBlockedByRedstone &&
currentHandler.slots != 0 &&
neighbour.isPresent
}
var mode by syncher.enum(ItemHandlerMode.DISABLED, setter = { access, value ->
@ -610,13 +583,6 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
access.accept(value)
markDirtyFast()
if (value == ItemHandlerMode.DISABLED) {
capController.close()
} else {
capController.close()
capController.expose()
}
currentHandler = when (value) {
ItemHandlerMode.DISABLED -> EmptyItemHandler
ItemHandlerMode.INPUT -> input!!
@ -624,6 +590,8 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
ItemHandlerMode.INPUT_OUTPUT -> inputOutput!!
ItemHandlerMode.BATTERY -> battery!!
}
level?.invalidateCapabilities(blockPos)
}
}).delegate
@ -674,7 +642,8 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
if (mode == ItemHandlerMode.DISABLED || !automatePull && !automatePush || redstoneControl.isBlockedByRedstone || currentHandler.slots == 0)
return
neighbour.get().ifPresentK {
val it = neighbour.get() ?: return
if (it.slots == 0)
return
@ -702,7 +671,6 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
this.outerSlotPush = outerSlotPush
}
}
}
override fun getSlots(): Int {
return currentHandler.slots

View File

@ -3,12 +3,11 @@ package ru.dbotthepony.mc.otm.block.entity
import net.minecraft.core.BlockPos
import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.capabilities.ForgeCapabilities
import ru.dbotthepony.mc.otm.capability.energy
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
import ru.dbotthepony.mc.otm.capability.extractEnergy
import ru.dbotthepony.mc.otm.container.HandlerFilter
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.core.ifPresentK
import ru.dbotthepony.mc.otm.core.math.Decimal
abstract class MatteryPoweredBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: BlockPos, p_155230_: BlockState) : MatteryDeviceBlockEntity(p_155228_, p_155229_, p_155230_) {
@ -31,7 +30,7 @@ abstract class MatteryPoweredBlockEntity(p_155228_: BlockEntityType<*>, p_155229
if (demand.isZero) return
for (stack in batteryContainer) {
stack.getCapability(ForgeCapabilities.ENERGY).ifPresentK {
stack.energy?.let {
val diff = it.extractEnergy(demand, false)
energy.receiveEnergy(diff, false)
demand -= diff

View File

@ -3,6 +3,7 @@ package ru.dbotthepony.mc.otm.block.entity
import com.google.common.collect.ImmutableList
import com.mojang.serialization.Codec
import net.minecraft.core.BlockPos
import net.minecraft.core.HolderLookup
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag
import net.minecraft.network.chat.Component
@ -75,26 +76,26 @@ abstract class MatteryWorkerBlockEntity<JobType : IJob>(
protected open fun onJobTick(status: JobStatus<JobType>, id: Int) {}
override fun saveShared(nbt: CompoundTag) {
super.saveShared(nbt)
override fun saveShared(nbt: CompoundTag, registry: HolderLookup.Provider) {
super.saveShared(nbt, registry)
nbt["jobs"] = ListTag().also {
for ((i, job) in jobEventLoops.withIndex()) {
it.add(job.serializeNBT().also {
it.add(job.serializeNBT(registry).also {
it["_id"] = i
})
}
}
}
override fun load(nbt: CompoundTag) {
super.load(nbt)
override fun loadAdditional(nbt: CompoundTag, registry: HolderLookup.Provider) {
super.loadAdditional(nbt, registry)
for (v in nbt.getCompoundList("jobs")) {
if ("_id" in v) {
val id = v.getInt("_id")
if (id in jobEventLoops.indices) {
jobEventLoops[id].deserializeNBT(v)
jobEventLoops[id].deserializeNBT(registry, v)
}
}
}

View File

@ -1,7 +1,8 @@
package ru.dbotthepony.mc.otm.block.entity
import net.minecraft.core.HolderLookup
import net.minecraft.nbt.CompoundTag
import net.minecraftforge.common.util.INBTSerializable
import net.neoforged.neoforge.common.util.INBTSerializable
import ru.dbotthepony.kommons.io.DelegateSyncher
import ru.dbotthepony.kommons.util.Listenable
import ru.dbotthepony.kommons.util.getValue
@ -25,14 +26,14 @@ abstract class AbstractRedstoneControl : INBTSerializable<CompoundTag?>, Listena
return listeners.addListener(listener)
}
override fun serializeNBT(): CompoundTag {
override fun serializeNBT(registry: HolderLookup.Provider): CompoundTag {
return CompoundTag().also {
it[SETTING_KEY] = redstoneSetting.toString()
it[SIGNAL_KEY] = redstoneSignal
}
}
override fun deserializeNBT(nbt: CompoundTag?) {
override fun deserializeNBT(registry: HolderLookup.Provider, nbt: CompoundTag?) {
if (nbt == null) {
redstoneSetting = RedstoneSetting.LOW
redstoneSignal = 0

View File

@ -3,6 +3,7 @@ package ru.dbotthepony.mc.otm.block.entity.blackhole
import it.unimi.dsi.fastutil.objects.ObjectArraySet
import net.minecraft.client.Minecraft
import net.minecraft.core.BlockPos
import net.minecraft.core.HolderLookup
import net.minecraft.nbt.CompoundTag
import net.minecraft.server.level.ServerLevel
import net.minecraft.server.level.ServerPlayer
@ -18,13 +19,12 @@ import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.levelgen.structure.BoundingBox
import net.minecraft.world.phys.AABB
import net.minecraft.world.phys.Vec3
import net.minecraftforge.common.Tags
import net.neoforged.neoforge.common.Tags
import ru.dbotthepony.kommons.util.getValue
import ru.dbotthepony.kommons.util.setValue
import ru.dbotthepony.mc.otm.block.BlackHoleBlock
import ru.dbotthepony.mc.otm.block.entity.tech.GravitationStabilizerBlockEntity
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
import ru.dbotthepony.mc.otm.block.entity.blackhole.ExplosionQueue.Companion.queueForLevel
import ru.dbotthepony.mc.otm.config.ServerConfig
import ru.dbotthepony.mc.otm.core.damageType
import ru.dbotthepony.mc.otm.core.getExplosionResistance
@ -101,37 +101,6 @@ class BlackHoleBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mattery
val level = level as? ServerLevel ?: return
level.setBlock(blockPos, Blocks.AIR.defaultBlockState(), Block.UPDATE_ALL)
if (gravitationStrength > 0.25) {
val x0 = blockPos.x + 0.5
val y0 = blockPos.y + 0.5
val z0 = blockPos.z + 0.5
val queue = queueForLevel(level)
var radius = 0
while (radius < Math.ceil(gravitationStrength * 4)) {
queue.explodeRing(
x0,
y0,
z0,
radius.toDouble(), Math.min(20.0, Math.max(1.0, (gravitationStrength * 4 - radius) * 20)).toFloat()
)
radius++
}
} else {
level.explode(
null,
MatteryDamageSource(level.registryAccess().damageType(MDamageTypes.HAWKING_RADIATION)),
null,
blockPos.x + 0.5,
blockPos.y + 0.5,
blockPos.z + 0.5,
gravitationStrength.toFloat() * 60,
false,
Level.ExplosionInteraction.BLOCK // TODO: 1.19.3
)
}
}
private fun updateGravStrength() {
@ -162,19 +131,14 @@ class BlackHoleBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mattery
affectedBoundsAABB = AABB.of(affectedBounds)
}
override fun getRenderBoundingBox(): AABB {
return AABB(blockPos.offset(-GravitationStabilizerBlockEntity.RANGE, -GravitationStabilizerBlockEntity.RANGE, -GravitationStabilizerBlockEntity.RANGE), blockPos.offset(
GravitationStabilizerBlockEntity.RANGE, GravitationStabilizerBlockEntity.RANGE, GravitationStabilizerBlockEntity.RANGE))
}
override fun saveLevel(nbt: CompoundTag) {
super.saveLevel(nbt)
override fun saveLevel(nbt: CompoundTag, registry: HolderLookup.Provider) {
super.saveLevel(nbt, registry)
nbt["mass"] = mass.serializeNBT()
nbt["spin_direction"] = spinDirection
}
override fun load(nbt: CompoundTag) {
super.load(nbt)
override fun loadAdditional(nbt: CompoundTag, registry: HolderLookup.Provider) {
super.loadAdditional(nbt, registry)
mass = nbt.map("mass", Decimal::deserializeNBT) ?: BASELINE_MASS
spinDirection = nbt.getBoolean("spin_direction")
}

View File

@ -1,49 +0,0 @@
package ru.dbotthepony.mc.otm.block.entity.blackhole
import net.minecraft.core.BlockPos
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.Blocks
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.phys.Vec3
import ru.dbotthepony.mc.otm.core.math.plus
import ru.dbotthepony.mc.otm.core.math.times
import ru.dbotthepony.mc.otm.registry.MBlockEntities
class BlockEntityExplosionDebugger(p_155229_: BlockPos, p_155230_: BlockState) : BlockEntity(MBlockEntities.DEBUG_EXPLOSION_SMALL, p_155229_, p_155230_) {
private var hive: ExplosionRayHive? = null
fun tick() {
if (hive == null) {
val hive = ExplosionRayHive(level as ServerLevel)
this.hive = hive
val tx = blockPos.x.toDouble() + 0.5
val ty = blockPos.y.toDouble() + 0.5
val tz = blockPos.z.toDouble() + 0.5
val tpos = Vec3(tx, ty, tz)
for (normal in ExplosionRayHive.evenlyDistributedPoints(1000)) {
hive.addRay(normal + tpos, normal, 200.0)
}
}
hive!!.step()
}
}
class BlockEntitySphereDebugger(p_155229_: BlockPos, p_155230_: BlockState) : BlockEntity(MBlockEntities.DEBUG_SPHERE_POINTS, p_155229_, p_155230_) {
private var placed = false
fun tick() {
if (!placed) {
placed = true
for (normal in ExplosionRayHive.evenlyDistributedPoints(400)) {
val multiplied = normal * 20.0
level!!.setBlock(blockPos + BlockPos(multiplied.x.toInt(), multiplied.y.toInt(), multiplied.z.toInt()), Blocks.COAL_BLOCK.defaultBlockState(), Block.UPDATE_ALL)
}
}
}
}

View File

@ -1,687 +0,0 @@
package ru.dbotthepony.mc.otm.block.entity.blackhole
import net.minecraft.core.BlockPos
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.DoubleTag
import net.minecraft.nbt.ListTag
import net.minecraft.nbt.Tag
import net.minecraft.server.level.ServerLevel
import net.minecraft.util.datafix.DataFixTypes
import net.minecraft.world.level.BlockGetter
import net.minecraft.world.level.Explosion
import net.minecraft.world.level.ExplosionDamageCalculator
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.Blocks
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.material.FluidState
import net.minecraft.world.level.saveddata.SavedData
import net.minecraft.world.phys.Vec3
import net.minecraftforge.event.TickEvent
import net.minecraftforge.eventbus.api.SubscribeEvent
import org.apache.logging.log4j.LogManager
import ru.dbotthepony.mc.otm.block.BlockExplosionDebugger
import ru.dbotthepony.mc.otm.core.*
import ru.dbotthepony.mc.otm.core.math.Vector
import ru.dbotthepony.mc.otm.core.math.component1
import ru.dbotthepony.mc.otm.core.math.component2
import ru.dbotthepony.mc.otm.core.math.component3
import ru.dbotthepony.mc.otm.core.math.left
import ru.dbotthepony.mc.otm.core.math.plus
import ru.dbotthepony.mc.otm.core.math.rotateAroundAxis
import ru.dbotthepony.mc.otm.core.math.up
import ru.dbotthepony.mc.otm.core.nbt.set
import ru.dbotthepony.mc.otm.registry.MDamageTypes
import ru.dbotthepony.mc.otm.registry.MRegistry
import ru.dbotthepony.mc.otm.registry.MatteryDamageSource
import java.util.*
import kotlin.collections.ArrayList
import kotlin.collections.HashMap
import kotlin.math.acos
import kotlin.math.cos
import kotlin.math.sin
import kotlin.math.sqrt
private fun round(v: Double): Int {
return (v + 0.5).toInt()
}
private val sphere = arrayOf(
// ядро
BlockPos(-1, -1, -1),
BlockPos(-1, -1, 0),
BlockPos(-1, -1, 1),
BlockPos(-1, 0, -1),
BlockPos(-1, 0, 0),
BlockPos(-1, 0, 1),
BlockPos(-1, 1, -1),
BlockPos(-1, 1, 0),
BlockPos(-1, 1, 1),
BlockPos(0, -1, -1),
BlockPos(0, -1, 0),
BlockPos(0, -1, 1),
BlockPos(0, 0, -1),
BlockPos(0, 0, 0),
BlockPos(0, 0, 1),
BlockPos(0, 1, -1),
BlockPos(0, 1, 0),
BlockPos(0, 1, 1),
BlockPos(1, -1, -1),
BlockPos(1, -1, 0),
BlockPos(1, -1, 1),
BlockPos(1, 0, -1),
BlockPos(1, 0, 0),
BlockPos(1, 0, 1),
BlockPos(1, 1, -1),
BlockPos(1, 1, 0),
BlockPos(1, 1, 1),
// столбы
BlockPos(-2, 0, 0),
BlockPos(2, 0, 0),
BlockPos(0, 2, 0),
BlockPos(0, -2, 0),
BlockPos(0, 0, 2),
BlockPos(0, 0, -2),
)
private val initialDirections = arrayOf(
Vector(1.0, 0.0, 0.0),
Vector(-1.0, 0.0, 0.0),
Vector(0.0, 1.0, 0.0),
Vector(0.0, -1.0, 0.0),
Vector(0.0, 0.0, 1.0),
Vector(0.0, 0.0, -1.0),
Vector(-1.0, -1.0, -1.0).normalize(),
Vector(1.0, -1.0, 1.0).normalize(),
Vector(1.0, -1.0, -1.0).normalize(),
Vector(-1.0, -1.0, 1.0).normalize(),
Vector(-1.0, 1.0, -1.0).normalize(),
Vector(1.0, 1.0, 1.0).normalize(),
Vector(1.0, 1.0, -1.0).normalize(),
Vector(-1.0, 1.0, 1.0).normalize(),
)
class ExplosionSphere(val hive: ExplosionSphereHive, var pos: Vec3, var stepVelocity: Vec3, var force: Double) {
val initialPos = pos
private var lastSplitPos = pos
val level: ServerLevel get() = hive.level
val blockPos: BlockPos get() = BlockPos(round(pos.x), round(pos.y), round(pos.z))
fun travelled(): Double {
return pos.distanceTo(initialPos)
}
private fun travelledFromLastSplit(): Double {
return pos.distanceTo(lastSplitPos)
}
fun step(): Boolean {
if (force <= 0.0) {
return false
}
val blockPos = blockPos
for (point in sphere) {
val finalPos = blockPos + point
val block = level.getBlockState(finalPos)
if (!block.isAir && block.block !is BlockExplosionDebugger) {
val explosion = Explosion(level, null, null, null, pos.x, pos.y, pos.z, force.toFloat(), false, Explosion.BlockInteraction.DESTROY_WITH_DECAY)
val explosionResistance = block.getExplosionResistance(level, blockPos, explosion)
if (explosionResistance > force) {
// поглощено
// TODO: вместо полного поглощения отражение
force = 0.0
return false
} else {
// взорвано
force -= explosionResistance
// TODO: дропы когда будет добавлена более общая версия
level.setBlock(blockPos, Blocks.AIR.defaultBlockState(), Block.UPDATE_ALL)
}
}
}
pos += stepVelocity
force -= 0.4
if (travelledFromLastSplit() >= TRAVEL_TO_SPLIT && force >= 10) {
force /= 2.0
val up = stepVelocity.up()
val left = stepVelocity.left()
val a = stepVelocity.rotateAroundAxis(up, Math.PI / 4)
val b = stepVelocity.rotateAroundAxis(up, -Math.PI / 4)
val c = stepVelocity.rotateAroundAxis(left, Math.PI / 4)
val d = stepVelocity.rotateAroundAxis(left, -Math.PI / 4)
hive.addRay(pos, a, force)
hive.addRay(pos, b, force)
hive.addRay(pos, c, force)
hive.addRay(pos, d, force)
lastSplitPos = pos
}
return force > 0.0
}
fun serializeNbt(): CompoundTag {
return CompoundTag()
}
companion object {
const val TRAVEL_TO_SPLIT = 4.0
fun deserializeNbt(hive: ExplosionSphereHive, tag: CompoundTag): ExplosionSphere {
return ExplosionSphere(hive, Vector.ZERO, Vector.ZERO, 0.0)
}
}
}
class ExplosionSphereHive(val level: ServerLevel) {
private val spheres = ArrayList<ExplosionSphere>()
var stepNumber = 0
private set
fun addRay(pos: Vec3, stepVelocity: Vec3, force: Double) {
spheres.add(ExplosionSphere(this, pos, stepVelocity, force))
}
fun addDefaultRays(pos: Vec3, force: Double) {
for (stepVelocity in initialDirections) {
addRay(pos, stepVelocity, force * 8)
}
}
fun step() {
stepNumber++
val toRemove = ArrayList<Int>()
for (i in 0 until spheres.size) {
if (!spheres[i].step()) {
toRemove.add(i)
}
}
for (i in toRemove.size - 1 downTo 0) {
spheres.removeAt(toRemove[i])
}
}
fun serializeNbt(): CompoundTag {
return CompoundTag().also {
it["spheres"] = ListTag().also {
for (ray in spheres)
it.add(ray.serializeNbt())
}
}
}
fun deserializeNbt(tag: CompoundTag) {
(tag["spheres"] as? ListTag)?.also {
for (elem in it) {
spheres.add(ExplosionSphere.deserializeNbt(this, elem as CompoundTag))
}
}
}
fun isEmpty(): Boolean {
return spheres.isEmpty()
}
}
class ExplosionRay(val hive: ExplosionRayHive, var pos: Vec3, var stepVelocity: Vec3, var force: Double) {
val initialPos = pos
private var lastSplitPos = pos
val level: ServerLevel get() = hive.level
val blockPos: BlockPos get() = BlockPos(round(pos.x), round(pos.y), round(pos.z))
private var prev: MutableInt? = null
fun travelled(): Double {
return pos.distanceTo(initialPos)
}
private fun travelledFromLastSplit(): Double {
return pos.distanceTo(lastSplitPos)
}
fun step(spread: Boolean): Boolean {
if (force <= 0.0) {
return false
}
val blockPos = blockPos
if (!level.isInWorldBounds(blockPos))
return false
// val chunk = level.chunkSource.getChunkNow(SectionPos.blockToSectionCoord(blockPos.x), SectionPos.blockToSectionCoord(blockPos.z)) ?: return true
val block = level.getBlockState(blockPos)
if (!block.isAir && block.block !is BlockExplosionDebugger) {
val explosion = Explosion(level, null, null, null, pos.x, pos.y, pos.z, force.toFloat(), false, Explosion.BlockInteraction.DESTROY_WITH_DECAY)
val explosionResistance = block.getExplosionResistance(level, blockPos, explosion)
if (explosionResistance > force) {
// поглощено
// TODO: вместо полного поглощения отражение
force = 0.0
return false
} else {
// взорвано
force -= explosionResistance
// TODO: дропы когда будет добавлена более общая версия
level.setBlock(blockPos, Blocks.AIR.defaultBlockState(), Block.UPDATE_ALL)
}
}
val old = this.blockPos
pos += stepVelocity
val new = this.blockPos
if (old != new) {
val prev = prev
if (prev != null) {
prev.dec()
if (prev.value <= 0) {
hive.checkKey(old)
}
}
this.prev = hive.incDensity(new)
}
force -= 0.4
if (spread && travelledFromLastSplit() >= TRAVEL_TO_SPLIT * sqrt(travelled() / 9.0) && force >= 10) {
force /= 2.0
val up = stepVelocity.up()
val left = stepVelocity.left()
val a = stepVelocity.rotateAroundAxis(up, Math.PI / 5.5)
val b = stepVelocity.rotateAroundAxis(up, -Math.PI / 5.5)
val c = stepVelocity.rotateAroundAxis(left, Math.PI / 5.5)
val d = stepVelocity.rotateAroundAxis(left, -Math.PI / 5.5)
hive.addRay(pos, a, force)
hive.addRay(pos, b, force)
hive.addRay(pos, c, force)
hive.addRay(pos, d, force)
lastSplitPos = pos
}
return force > 0f
}
fun serializeNbt(): CompoundTag {
return CompoundTag().also {
it["pos"] = ListTag().also {
it.add(DoubleTag.valueOf(pos.x))
it.add(DoubleTag.valueOf(pos.y))
it.add(DoubleTag.valueOf(pos.z))
}
it["stepVelocity"] = ListTag().also {
it.add(DoubleTag.valueOf(stepVelocity.x))
it.add(DoubleTag.valueOf(stepVelocity.y))
it.add(DoubleTag.valueOf(stepVelocity.z))
}
it["force"] = force
}
}
companion object {
const val TRAVEL_TO_SPLIT = 4.0
fun deserializeNbt(hive: ExplosionRayHive, tag: CompoundTag): ExplosionRay {
val pos = tag["pos"] as ListTag
val stepVelocity = tag["stepVelocity"] as ListTag
return ExplosionRay(hive,
Vector((pos[0] as DoubleTag).asDouble, (pos[1] as DoubleTag).asDouble, (pos[2] as DoubleTag).asDouble),
Vector((stepVelocity[0] as DoubleTag).asDouble, (stepVelocity[1] as DoubleTag).asDouble, (stepVelocity[2] as DoubleTag).asDouble),
(tag["force"] as DoubleTag).asDouble
)
}
}
}
data class MutableInt(var value: Int = 0) {
fun inc() {value++}
fun dec() {value--}
fun zero() = value <= 0
}
class ExplosionRayHive(val level: ServerLevel) {
private val rays = ArrayList<ExplosionRay>()
private val densityMap = HashMap<BlockPos, MutableInt>()
var stepNumber = 0
private set
fun incDensity(pos: BlockPos): MutableInt {
return densityMap.computeIfAbsent(pos) {MutableInt()}.also(MutableInt::inc)
}
fun decDensity(pos: BlockPos) {
val value = densityMap.computeIfAbsent(pos) {MutableInt()}
value.dec()
if (value.zero()) {
densityMap.remove(pos)
}
}
fun checkKey(pos: BlockPos) {
val value = densityMap.computeIfAbsent(pos) {MutableInt()}
if (value.zero()) {
densityMap.remove(pos)
}
}
fun addRay(pos: Vec3, stepVelocity: Vec3, force: Double) {
rays.add(ExplosionRay(this, pos, stepVelocity, force))
}
fun step() {
stepNumber++
val toRemove = ArrayList<Int>()
val density = calculateDensity()
for (i in 0 until rays.size) {
if (!rays[i].step(density < 3.0)) {
toRemove.add(i)
decDensity(rays[i].blockPos)
}
}
for (i in toRemove.size - 1 downTo 0) {
rays.removeAt(toRemove[i])
}
if (stepNumber % 4 == 0) {
LOGGER.info("At step {} density of hive {} with {} elements is {}", stepNumber, this, rays.size, density)
}
}
fun calculateDensity(): Double {
return rays.size.toDouble() / densityMap.size
}
fun serializeNbt(): CompoundTag {
return CompoundTag().also {
it["rays"] = ListTag().also {
for (ray in rays)
it.add(ray.serializeNbt())
}
}
}
fun deserializeNbt(tag: CompoundTag) {
(tag["rays"] as? ListTag)?.also {
for (elem in it) {
rays.add(ExplosionRay.deserializeNbt(this, elem as CompoundTag))
}
}
}
fun isEmpty(): Boolean {
return rays.isEmpty()
}
companion object {
private val LOGGER = LogManager.getLogger()
private val SQUARE_5 = sqrt(5.0)
fun evenlyDistributedPoints(amount: Int): List<Vec3> {
val list = ArrayList<Vec3>()
for (i in 0 .. amount) {
val idx = i.toDouble() / amount
val phi = acos(1.0 - 2.0 * idx)
val theta = Math.PI * (1.0 + SQUARE_5) * i
list.add(Vec3(cos(theta) * sin(phi), sin(theta) * sin(phi), cos(phi)))
}
return list
}
}
}
private object BlackHoleExplosionDamageCalculator : ExplosionDamageCalculator() {
override fun getBlockExplosionResistance(
explosion: Explosion,
getter: BlockGetter,
pos: BlockPos,
state: BlockState,
fstate: FluidState
): Optional<Float> {
return if (state.isAir && fstate.isEmpty) Optional.empty() else Optional.of(
Math.sqrt(
Math.max(
0f,
Math.max(
state.getExplosionResistance(getter, pos, explosion),
fstate.getExplosionResistance(getter, pos, explosion)
)
).toDouble()
).toFloat()
)
}
}
private data class RingExplosion(val x: Double, val y: Double, val z: Double, val radius: Double, val strength: Float) {
fun serializeNBT(): CompoundTag {
return CompoundTag().also {
it["x"] = x
it["y"] = y
it["z"] = z
it["radius"] = radius
it["strength"] = strength
}
}
fun explode(queue: ExplosionQueue) {
for (pos in ExplosionRayHive.evenlyDistributedPoints(radius.toInt() * 80)) {
val (x, y, z) = pos
queue.explode(
this.x + x * radius * 15,
this.y + y * radius * 15,
this.z + z * radius * 15,
strength
)
}
}
companion object {
@JvmStatic
fun deserializeNBT(tag: CompoundTag): RingExplosion {
return RingExplosion(
tag.getDouble("x"),
tag.getDouble("y"),
tag.getDouble("z"),
tag.getDouble("radius"),
tag.getFloat("strength")
)
}
}
}
private data class QueuedExplosion(val x: Double, val y: Double, val z: Double, val radius: Float) {
fun serializeNBT(): CompoundTag {
return CompoundTag().also {
it["x"] = x
it["y"] = y
it["z"] = z
it["radius"] = radius
}
}
fun explode(level: Level) {
level.explode(
null,
MatteryDamageSource(level.registryAccess().damageType(MDamageTypes.HAWKING_RADIATION)),
BlackHoleExplosionDamageCalculator,
x,
y,
z,
radius,
false,
Level.ExplosionInteraction.BLOCK // TODO: 1.19.3
)
}
companion object {
fun deserializeNBT(tag: CompoundTag): QueuedExplosion {
return QueuedExplosion(tag.getDouble("x"), tag.getDouble("y"), tag.getDouble("z"), tag.getFloat("radius"))
}
}
}
class ExplosionQueue(private val level: ServerLevel) : SavedData() {
private var indexExplosion = 0
private var indexRing = 0
private val explosions = ArrayList<QueuedExplosion>()
private val rings = ArrayList<RingExplosion>()
private val hives = ArrayList<ExplosionRayHive>()
override fun save(tag: CompoundTag): CompoundTag {
val listExplosions = ListTag()
val listRings = ListTag()
for (i in indexExplosion until explosions.size)
listExplosions.add(explosions[i].serializeNBT())
for (i in indexRing until rings.size)
listRings.add(rings[i].serializeNBT())
tag["explosions"] = listExplosions
tag["rings"] = listRings
// tag["hives"] = ListTag().also {
// for (hive in hives) {
// it.add(hive.serializeNbt())
// }
// }
return tag
}
fun load(tag: CompoundTag) {
explosions.clear()
rings.clear()
hives.clear()
indexExplosion = 0
indexRing = 0
for (explosion in tag.getList("explosions", Tag.TAG_COMPOUND.toInt()))
explosions.add(QueuedExplosion.deserializeNBT(explosion as CompoundTag))
for (ring in tag.getList("rings", Tag.TAG_COMPOUND.toInt()))
rings.add(RingExplosion.deserializeNBT(ring as CompoundTag))
for (hive in tag.getList("hives", Tag.TAG_COMPOUND.toInt()))
hives.add(ExplosionRayHive(level).also { it.deserializeNbt(hive as CompoundTag) })
}
fun explode(x: Double, y: Double, z: Double, radius: Float) {
if (level.isOutsideBuildHeight(BlockPos(x.toInt(), y.toInt() + 24, z.toInt())) || level.isOutsideBuildHeight(BlockPos(x.toInt(), y.toInt() - 24, z.toInt())))
return
explosions.add(QueuedExplosion(x, y, z, radius))
isDirty = true
}
fun explodeRing(x: Double, y: Double, z: Double, radius: Double, strength: Float) {
rings.add(RingExplosion(x, y, z, radius, strength))
isDirty = true
}
fun explodeRays(tpos: Vector, force: Double) {
val hive = ExplosionRayHive(level)
hives.add(hive)
for (normal in ExplosionRayHive.evenlyDistributedPoints(1000)) {
hive.addRay(normal + tpos, normal, force)
}
isDirty = true
}
fun tick() {
if (explosions.size != 0) {
isDirty = true
var iterations = 0
for (i in indexExplosion until explosions.size) {
explosions[i].explode(level)
indexExplosion++
if (iterations++ == 4) {
break
}
}
if (indexExplosion >= explosions.size) {
indexExplosion = 0
explosions.clear()
}
} else if (rings.size != 0) {
if (indexRing >= rings.size) {
indexRing = 0
rings.clear()
} else {
rings[indexRing++].explode(this)
}
}
for (i in hives.size - 1 downTo 0) {
isDirty = true
hives[i].step()
if (hives[i].isEmpty()) {
hives.removeAt(i)
}
}
}
companion object {
@JvmStatic
fun queueForLevel(level: ServerLevel): ExplosionQueue {
return level.dataStorage.computeIfAbsent(
Factory({ ExplosionQueue(level) }, {
val factory = ExplosionQueue(level)
factory.load(it)
factory
}, DataFixTypes.LEVEL),
"otm_blackhole_explosion_queue"
)
}
@SubscribeEvent
fun onWorldTick(event: TickEvent.LevelTickEvent) {
if (event.phase == TickEvent.Phase.START && event.level is ServerLevel) {
queueForLevel(event.level as ServerLevel).tick()
}
}
}
}

View File

@ -6,7 +6,7 @@ import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.capabilities.ForgeCapabilities
import net.neoforged.neoforge.capabilities.Capabilities
import ru.dbotthepony.mc.otm.SERVER_IS_LIVE
import ru.dbotthepony.mc.otm.block.CableBlock
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
@ -43,23 +43,23 @@ abstract class EnergyCableBlockEntity(type: BlockEntityType<*>, blockPos: BlockP
init {
check(side !in energySidesInternal)
energySidesInternal[side] = this
sides[side]!!.Cap(ForgeCapabilities.ENERGY, this)
exposeSided(side, Capabilities.EnergyStorage.BLOCK, this)
}
val neighbour = sides[side]!!.trackEnergy()
val neighbour = CapabilityCache(side, Capabilities.EnergyStorage.BLOCK)
init {
waitForServerLevel {
neighbour.addListener(Consumer {
if (isEnabled) {
if (it.isPresent) {
if (it.resolve().get() !is CableSide) {
if (neighbour.isPresent) {
if (neighbour.get() !is CableSide) {
node.graph.livelyNodes.add(node)
}
}
onceServer {
updateBlockState(blockRotation.side2Dir(side), it.isPresent || node.neighboursView[GraphNode.link(blockRotation.side2Dir(side))] != null)
updateBlockState(blockRotation.side2Dir(side), neighbour.isPresent || node.neighboursView[GraphNode.link(blockRotation.side2Dir(side))] != null)
}
}
})
@ -144,8 +144,8 @@ abstract class EnergyCableBlockEntity(type: BlockEntityType<*>, blockPos: BlockP
}
init {
sides.keys.forEach { CableSide(it) }
exposeGlobally(MatteryCapability.ENERGY_CABLE_NODE, node)
RelativeSide.entries.forEach { CableSide(it) }
exposeSideless(MatteryCapability.ENERGY_CABLE_NODE, node)
}
}

View File

@ -1,14 +1,10 @@
package ru.dbotthepony.mc.otm.block.entity.cable
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
import it.unimi.dsi.fastutil.objects.ObjectAVLTreeSet
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet
import ru.dbotthepony.mc.otm.capability.receiveEnergy
import ru.dbotthepony.mc.otm.core.ifPresentK
import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.math.RelativeSide
import ru.dbotthepony.mc.otm.graph.GraphNodeList
import java.util.PriorityQueue
import java.util.*
import kotlin.math.ln
class EnergyCableGraph : GraphNodeList<EnergyCableBlockEntity.Node, EnergyCableGraph>() {
@ -102,7 +98,7 @@ class EnergyCableGraph : GraphNodeList<EnergyCableBlockEntity.Node, EnergyCableG
continue
}
side.neighbour.get().ifPresentK {
side.neighbour.get()?.let {
if (it !is EnergyCableBlockEntity.CableSide) {
val limit = getPath(fromNode, node)
hit = true

View File

@ -2,6 +2,7 @@ package ru.dbotthepony.mc.otm.block.entity.decorative
import net.minecraft.advancements.CriteriaTriggers
import net.minecraft.core.BlockPos
import net.minecraft.core.HolderLookup
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.LongTag
import net.minecraft.nbt.StringTag
@ -23,7 +24,7 @@ import net.minecraft.world.level.storage.loot.LootParams
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets
import net.minecraft.world.level.storage.loot.parameters.LootContextParams
import net.minecraft.world.phys.Vec3
import net.minecraftforge.common.capabilities.ForgeCapabilities
import net.neoforged.neoforge.capabilities.Capabilities
import ru.dbotthepony.mc.otm.block.decorative.CargoCrateBlock
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
import ru.dbotthepony.mc.otm.container.MatteryContainer
@ -84,18 +85,18 @@ class CargoCrateBlockEntity(
}
init {
exposeGlobally(ForgeCapabilities.ITEM_HANDLER, handler)
exposeGlobally(Capabilities.ItemHandler.BLOCK, handler)
savetablesLevel.stateful(::container, INVENTORY_KEY)
}
override fun saveLevel(nbt: CompoundTag) {
super.saveLevel(nbt)
override fun saveLevel(nbt: CompoundTag, registry: HolderLookup.Provider) {
super.saveLevel(nbt, registry)
lootTable?.let { nbt[LOOT_TABLE_KEY] = it.toString() }
lootTableSeed?.let { nbt[LOOT_TABLE_SEED_KEY] = it }
}
override fun load(nbt: CompoundTag) {
super.load(nbt)
override fun loadAdditional(nbt: CompoundTag, registry: HolderLookup.Provider) {
super.loadAdditional(nbt, registry)
lootTable = nbt.map(LOOT_TABLE_KEY) { it: StringTag -> ResourceLocation.tryParse(it.asString) }
lootTableSeed = (nbt[LOOT_TABLE_SEED_KEY] as LongTag?)?.asLong
}
@ -105,7 +106,7 @@ class CargoCrateBlockEntity(
val lootTableSeed = lootTableSeed ?: 0L
val server = level?.server ?: return
val loot = server.lootData.getLootTable(lootTable)
val loot = server.loot.getLootTable(lootTable)
if (ply is ServerPlayer) {
CriteriaTriggers.GENERATE_LOOT.trigger(ply, lootTable)

View File

@ -2,14 +2,13 @@ package ru.dbotthepony.mc.otm.block.entity.decorative
import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap
import net.minecraft.core.BlockPos
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.capabilities.ForgeCapabilities
import net.minecraftforge.items.IItemHandler
import net.minecraftforge.registries.ForgeRegistries
import net.minecraftforge.registries.IdMappingEvent
import net.neoforged.neoforge.capabilities.Capabilities
import net.neoforged.neoforge.items.IItemHandler
import net.neoforged.neoforge.registries.IdMappingEvent
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
import ru.dbotthepony.mc.otm.core.getID
import ru.dbotthepony.mc.otm.registry.MBlockEntities
class DevChestBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryBlockEntity(MBlockEntities.DEV_CHEST, blockPos, blockState), IItemHandler {
@ -38,7 +37,7 @@ class DevChestBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryB
}
init {
exposeGlobally(ForgeCapabilities.ITEM_HANDLER, this)
exposeGlobally(Capabilities.ItemHandler.BLOCK, this)
}
companion object {
@ -52,8 +51,8 @@ class DevChestBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryB
val sorted = Int2ObjectAVLTreeMap<ItemStack>()
for (item in ForgeRegistries.ITEMS.values) {
check(sorted.put(ForgeRegistries.ITEMS.getID(item), ItemStack(item, 1).also { it.count = item.getMaxStackSize(it) }) == null)
for (item in BuiltInRegistries.ITEM) {
check(sorted.put(BuiltInRegistries.ITEM.getId(item), ItemStack(item, 1).also { it.count = item.getMaxStackSize(it) }) == null)
}
cache.addAll(sorted.values)

View File

@ -8,9 +8,9 @@ import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.capabilities.ForgeCapabilities
import net.minecraftforge.fluids.FluidStack
import net.minecraftforge.fluids.capability.IFluidHandler
import net.neoforged.neoforge.capabilities.Capabilities
import net.neoforged.neoforge.fluids.FluidStack
import net.neoforged.neoforge.fluids.capability.IFluidHandler
import org.apache.logging.log4j.LogManager
import ru.dbotthepony.kommons.util.ListenableDelegate
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
@ -22,7 +22,6 @@ import ru.dbotthepony.mc.otm.container.HandlerFilter
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.container.get
import ru.dbotthepony.mc.otm.core.isNotEmpty
import ru.dbotthepony.mc.otm.core.orNull
import ru.dbotthepony.mc.otm.core.util.FluidStackValueCodec
import ru.dbotthepony.mc.otm.menu.decorative.FluidTankMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities
@ -47,10 +46,10 @@ class FluidTankBlockEntity(blockPos: BlockPos, blockState: BlockState) : Mattery
fillInput.handler(object : HandlerFilter {
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
if (fluid.isEmpty) {
return stack.getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).map { it.tanks > 0 }.orElse(false)
return stack.getCapability(Capabilities.FluidHandler.ITEM)?.let { it.tanks > 0 } ?: false
}
return stack.getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).map { it.fill(fluid[0], IFluidHandler.FluidAction.SIMULATE) > 0 }.orElse(false)
return stack.getCapability(Capabilities.FluidHandler.ITEM)?.let { it.fill(fluid[0], IFluidHandler.FluidAction.SIMULATE) > 0 } ?: false
}
override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
@ -80,7 +79,7 @@ class FluidTankBlockEntity(blockPos: BlockPos, blockState: BlockState) : Mattery
val item = drainInput[0]
if (item.isNotEmpty) {
val cap = (if (item.count == 1) item else item.copyWithCount(1)).getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).orNull()
val cap = (if (item.count == 1) item else item.copyWithCount(1)).getCapability(Capabilities.FluidHandler.ITEM)
if (cap == null) {
if (output.consumeItem(item, simulate = false)) {
@ -106,7 +105,7 @@ class FluidTankBlockEntity(blockPos: BlockPos, blockState: BlockState) : Mattery
if (moved0.isNotEmpty) {
if (output.consumeItem(cap.container, simulate = true)) {
val cap1 = item.copyWithCount(1).getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).orNull() ?: throw ConcurrentModificationException()
val cap1 = item.copyWithCount(1).getCapability(Capabilities.FluidHandler.ITEM) ?: throw ConcurrentModificationException()
val moved1 = moveFluid(source = cap1, destination = fluid)
@ -132,7 +131,7 @@ class FluidTankBlockEntity(blockPos: BlockPos, blockState: BlockState) : Mattery
val item = fillInput[0]
if (item.isNotEmpty) {
val cap = (if (item.count == 1) item else item.copyWithCount(1)).getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).orNull()
val cap = (if (item.count == 1) item else item.copyWithCount(1)).getCapability(Capabilities.FluidHandler.ITEM)
if (cap == null) {
if (output.consumeItem(item, simulate = false)) {
@ -158,7 +157,7 @@ class FluidTankBlockEntity(blockPos: BlockPos, blockState: BlockState) : Mattery
if (moved0.isNotEmpty) {
if (output.consumeItem(cap.container, simulate = true)) {
val cap1 = item.copyWithCount(1).getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).orNull() ?: throw ConcurrentModificationException()
val cap1 = item.copyWithCount(1).getCapability(Capabilities.FluidHandler.ITEM) ?: throw ConcurrentModificationException()
val moved1 = moveFluid(source = fluid, destination = cap1)

View File

@ -1,6 +1,7 @@
package ru.dbotthepony.mc.otm.block.entity.decorative
import net.minecraft.core.BlockPos
import net.minecraft.core.HolderLookup
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.chat.Component
import net.minecraft.server.level.ServerLevel
@ -86,8 +87,8 @@ class HoloSignBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryB
}
}
override fun load(nbt: CompoundTag) {
super.load(nbt)
override fun loadAdditional(nbt: CompoundTag, registry: HolderLookup.Provider) {
super.loadAdditional(nbt, registry)
if (!isLocked)
signText = truncate(signText)

View File

@ -3,11 +3,11 @@ package ru.dbotthepony.mc.otm.block.entity.decorative
import net.minecraft.core.BlockPos
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.material.Fluids
import net.minecraftforge.common.capabilities.ForgeCapabilities
import net.minecraftforge.fluids.FluidStack
import net.minecraftforge.fluids.capability.IFluidHandler
import net.neoforged.neoforge.capabilities.Capabilities
import net.neoforged.neoforge.fluids.FluidStack
import net.neoforged.neoforge.fluids.capability.IFluidHandler
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
import ru.dbotthepony.mc.otm.core.ifPresentK
import ru.dbotthepony.mc.otm.core.math.RelativeSide
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import java.util.function.Consumer
@ -45,18 +45,16 @@ class InfiniteWaterSourceBlockEntity(blockPos: BlockPos, blockState: BlockState)
}
init {
exposeGlobally(ForgeCapabilities.FLUID_HANDLER, this)
exposeGlobally(Capabilities.FluidHandler.BLOCK, this)
for (side in sides.values) {
val tracker = side.track(ForgeCapabilities.FLUID_HANDLER)
for (side in RelativeSide.entries) {
val tracker = CapabilityCache(side, Capabilities.FluidHandler.BLOCK)
val ticker = tickList.Ticker {
tracker.get().ifPresentK {
it.fill(FluidStack(Fluids.WATER, Int.MAX_VALUE), IFluidHandler.FluidAction.EXECUTE)
}
tracker.get()?.fill(FluidStack(Fluids.WATER, Int.MAX_VALUE), IFluidHandler.FluidAction.EXECUTE)
}
tracker.addListener(Consumer { ticker.isEnabled = it.isPresent })
tracker.addListener(Consumer { ticker.isEnabled = tracker.isPresent })
}
}
}

View File

@ -1,12 +1,11 @@
package ru.dbotthepony.mc.otm.block.entity.decorative
import com.google.common.collect.ImmutableList
import com.mojang.datafixers.util.Either
import it.unimi.dsi.fastutil.ints.Int2IntArrayMap
import it.unimi.dsi.fastutil.objects.Object2IntArrayMap
import it.unimi.dsi.fastutil.objects.Object2IntMap
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap
import net.minecraft.core.BlockPos
import net.minecraft.core.HolderLookup
import net.minecraft.nbt.CompoundTag
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
@ -15,13 +14,12 @@ import net.minecraft.world.item.DyeColor
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.material.Fluids
import net.minecraftforge.common.capabilities.ForgeCapabilities
import net.minecraftforge.fluids.FluidStack
import net.minecraftforge.fluids.capability.IFluidHandler
import net.neoforged.neoforge.capabilities.Capabilities
import net.neoforged.neoforge.fluids.FluidStack
import net.neoforged.neoforge.fluids.capability.IFluidHandler
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
import ru.dbotthepony.mc.otm.container.HandlerFilter
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.core.ifPresentK
import ru.dbotthepony.mc.otm.core.immutableList
import ru.dbotthepony.mc.otm.core.immutableMap
import ru.dbotthepony.mc.otm.core.isNotEmpty
@ -85,7 +83,7 @@ class PainterBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDe
addDroppableContainer(dyeInput)
savetables.stateful(dyeInput, INVENTORY_KEY)
savetables.bool(::isBulk)
exposeGlobally(ForgeCapabilities.FLUID_HANDLER, this)
exposeGlobally(Capabilities.FluidHandler.BLOCK, this)
}
fun takeDyes(dyes: Map<out DyeColor?, Int>) {
@ -113,7 +111,7 @@ class PainterBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDe
val config = ConfigurableItemHandler(input = dyeInput.handler(object : HandlerFilter {
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
if (waterStored() < MAX_WATER_STORAGE) {
stack.getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).ifPresentK {
stack.getCapability(Capabilities.FluidHandler.ITEM)?.let {
val drain = it.drain(FluidStack(Fluids.WATER, MAX_WATER_STORAGE - waterStored()), IFluidHandler.FluidAction.SIMULATE)
if (drain.isNotEmpty) {
@ -127,7 +125,7 @@ class PainterBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDe
}
override fun modifyInsertCount(slot: Int, stack: ItemStack, existing: ItemStack, simulate: Boolean): Int {
if (!stack.equals(existing, false))
if (!ItemStack.isSameItemSameComponents(stack, existing))
return super.modifyInsertCount(slot, stack, existing, simulate)
val dye = DyeColor.entries.firstOrNull { stack.`is`(it.tag) } ?: return 0
@ -147,8 +145,8 @@ class PainterBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDe
return dyeStored.getInt(dye)
}
override fun saveShared(nbt: CompoundTag) {
super.saveShared(nbt)
override fun saveShared(nbt: CompoundTag, registry: HolderLookup.Provider) {
super.saveShared(nbt, registry)
nbt["dyes"] = CompoundTag().also {
for ((k, v) in dyeStored) {
@ -157,8 +155,8 @@ class PainterBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDe
}
}
override fun load(nbt: CompoundTag) {
super.load(nbt)
override fun loadAdditional(nbt: CompoundTag, registry: HolderLookup.Provider) {
super.loadAdditional(nbt, registry)
dyeStored.clear()
@ -177,7 +175,7 @@ class PainterBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDe
for (slot in dyeInput.slotIterator()) {
if (waterStored() < MAX_WATER_STORAGE) {
slot.item.getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).ifPresentK {
slot.item.getCapability(Capabilities.FluidHandler.ITEM)?.let {
val drain = it.drain(FluidStack(Fluids.WATER, MAX_WATER_STORAGE - waterStored()), IFluidHandler.FluidAction.EXECUTE)
if (drain.isNotEmpty) {

View File

@ -81,13 +81,13 @@ class MatterBottlerBlockEntity(blockPos: BlockPos, blockState: BlockState) :
val bottlingHandler = bottling.handler(object : HandlerFilter {
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
return isBottling && stack.getCapability(MatteryCapability.MATTER).map { it.matterFlow.input && it.missingMatter.isPositive }.orElse(false)
return isBottling && stack.getCapability(MatteryCapability.MATTER_ITEM)?.let { it.matterFlow.input && it.missingMatter.isPositive } ?: false
}
})
val unbottlingHandler = unbottling.handler(object : HandlerFilter {
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
return !isBottling && stack.getCapability(MatteryCapability.MATTER).map { it.matterFlow.output && it.storedMatter.isPositive }.orElse(false)
return !isBottling && stack.getCapability(MatteryCapability.MATTER_ITEM)?.let { it.matterFlow.output && it.storedMatter.isPositive } ?: false
}
})
@ -109,7 +109,7 @@ class MatterBottlerBlockEntity(blockPos: BlockPos, blockState: BlockState) :
val matterNode = SimpleMatterNode(matter = matter)
init {
exposeGlobally(MatteryCapability.MATTER, matter)
exposeGlobally(MatteryCapability.MATTER_BLOCK, matter)
exposeGlobally(MatteryCapability.MATTER_NODE, matterNode)
savetables.bool(::isBottling)
@ -145,7 +145,7 @@ class MatterBottlerBlockEntity(blockPos: BlockPos, blockState: BlockState) :
var state = blockState
for (i in 0 .. 2) {
val desired = !container.getItem(i).isEmpty && container.getItem(i).getCapability(MatteryCapability.MATTER).isPresent
val desired = !container.getItem(i).isEmpty && container.getItem(i).getCapability(MatteryCapability.MATTER_ITEM) != null
if (state.getValue(MatterBottlerBlock.SLOT_PROPERTIES[i]) != desired) {
state = state.setValue(MatterBottlerBlock.SLOT_PROPERTIES[i], desired)
@ -190,7 +190,7 @@ class MatterBottlerBlockEntity(blockPos: BlockPos, blockState: BlockState) :
for (slot in bottling.slotIterator()) {
val item = slot.item
item.getCapability(MatteryCapability.MATTER).ifPresentK {
item.getCapability(MatteryCapability.MATTER_ITEM)?.let {
if (!it.missingMatter.isPositive) {
unbottling.consumeItem(item, false)
slot.setChanged()
@ -256,7 +256,7 @@ class MatterBottlerBlockEntity(blockPos: BlockPos, blockState: BlockState) :
for (slot in unbottling.slotIterator()) {
val item = slot.item
item.getCapability(MatteryCapability.MATTER).ifPresentK {
item.getCapability(MatteryCapability.MATTER_ITEM)?.let {
if (!it.storedMatter.isPositive) {
bottling.consumeItem(item, false)
slot.setChanged()

View File

@ -19,7 +19,6 @@ import ru.dbotthepony.mc.otm.container.HandlerFilter
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.core.immutableList
import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.ifPresentK
import ru.dbotthepony.mc.otm.graph.matter.SimpleMatterNode
import ru.dbotthepony.mc.otm.menu.matter.MatterCapacitorBankMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities
@ -39,7 +38,7 @@ class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState)
for (stack in container)
if (!stack.isEmpty)
stack.getCapability(MatteryCapability.MATTER).ifPresentK {
stack.getCapability(MatteryCapability.MATTER_ITEM)?.let {
summ += it.storedMatter
}
@ -55,7 +54,7 @@ class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState)
for (stack in container)
if (!stack.isEmpty)
stack.getCapability(MatteryCapability.MATTER).ifPresentK {
stack.getCapability(MatteryCapability.MATTER_ITEM)?.let {
summ += it.maxStoredMatter
}
@ -72,7 +71,7 @@ class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState)
for (stack in container) {
if (!stack.isEmpty) {
stack.getCapability(MatteryCapability.MATTER).ifPresent {
stack.getCapability(MatteryCapability.MATTER_ITEM)?.let {
val diff = it.receiveMatterChecked(howMuch, simulate)
summ += diff
howMuch -= diff
@ -101,7 +100,7 @@ class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState)
for (stack in container) {
if (!stack.isEmpty) {
stack.getCapability(MatteryCapability.MATTER).ifPresent {
stack.getCapability(MatteryCapability.MATTER_ITEM)?.let {
val diff = it.extractMatterChecked(howMuch, simulate)
summ += diff
howMuch -= diff
@ -123,10 +122,10 @@ class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState)
override val matterFlow: FlowDirection
get() = FlowDirection.BI_DIRECTIONAL
val container = object : MatteryContainer(this::markDirtyFast, BatteryBankBlockEntity.CAPACITY) {
val container = object : MatteryContainer(::markDirtyFast, BatteryBankBlockEntity.CAPACITY) {
override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) {
super.setChanged(slot, new, old)
capacitorStatus[slot].value = new.getCapability(MatteryCapability.MATTER).isPresent
capacitorStatus[slot].value = new.getCapability(MatteryCapability.MATTER_ITEM) != null
gaugeLevel = storedMatter.percentage(maxStoredMatter)
}
@ -135,11 +134,11 @@ class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState)
val itemConfig = ConfigurableItemHandler(inputOutput = container.handler(object : HandlerFilter {
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
return stack.getCapability(MatteryCapability.MATTER).isPresent
return stack.getCapability(MatteryCapability.MATTER_ITEM) != null
}
override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
stack.getCapability(MatteryCapability.MATTER).ifPresentK {
stack.getCapability(MatteryCapability.MATTER_ITEM)?.let {
if (it.storedMatter.isPositive) {
return false
}
@ -155,7 +154,7 @@ class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState)
init {
savetables.stateful(::container, INVENTORY_KEY)
exposeGlobally(MatteryCapability.MATTER, this)
exposeGlobally(MatteryCapability.MATTER_BLOCK, this)
exposeGlobally(MatteryCapability.MATTER_NODE, matterNode)
}

View File

@ -67,7 +67,7 @@ class MatterDecomposerBlockEntity(pos: BlockPos, state: BlockState)
val matterNode = SimpleMatterNode(matter = matter)
init {
exposeGlobally(MatteryCapability.MATTER, matter)
exposeGlobally(MatteryCapability.MATTER_BLOCK, matter)
exposeGlobally(MatteryCapability.MATTER_NODE, matterNode)
savetables.stateful(::matter, MATTER_STORAGE_KEY)
}

View File

@ -7,9 +7,10 @@ import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.crafting.CraftingInput
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.capabilities.ForgeCapabilities
import net.neoforged.neoforge.capabilities.Capabilities
import ru.dbotthepony.mc.otm.block.entity.ExperienceStorage
import ru.dbotthepony.mc.otm.block.entity.ItemJob
import ru.dbotthepony.mc.otm.block.entity.JobContainer
@ -26,7 +27,6 @@ import ru.dbotthepony.mc.otm.config.MachinesConfig
import ru.dbotthepony.mc.otm.container.MatteryCraftingContainer
import ru.dbotthepony.mc.otm.container.HandlerFilter
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.container.ShadowCraftingContainer
import ru.dbotthepony.mc.otm.container.UpgradeContainer
import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.data.DecimalCodec
@ -75,12 +75,13 @@ class MatterEntanglerBlockEntity(blockPos: BlockPos, blockState: BlockState) : M
val itemConfig = ConfigurableItemHandler(
input = inputs.handler(object : HandlerFilter {
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
val shadow = ShadowCraftingContainer.shadow(inputs, slot, stack)
val list = inputs.toList()
list[slot] = stack
val shadow = CraftingInput.of(3, 3, list)
return (level ?: return false)
.recipeManager
.byType(MRecipes.MATTER_ENTANGLER)
.values
.any { it.value.preemptivelyMatches(shadow, level!!) }
}
@ -92,7 +93,7 @@ class MatterEntanglerBlockEntity(blockPos: BlockPos, blockState: BlockState) : M
)
init {
exposeGlobally(ForgeCapabilities.FLUID_HANDLER, experience)
exposeGlobally(Capabilities.FluidHandler.BLOCK, experience)
savetables.stateful(::energy, ENERGY_KEY)
savetables.stateful(::matter, MATTER_STORAGE_KEY)
@ -102,7 +103,7 @@ class MatterEntanglerBlockEntity(blockPos: BlockPos, blockState: BlockState) : M
savetables.stateful(::experience)
exposeGlobally(MatteryCapability.MATTER_NODE, node)
exposeGlobally(MatteryCapability.MATTER, matter)
exposeGlobally(MatteryCapability.MATTER_BLOCK, matter)
}
override fun setLevel(level: Level) {
@ -144,16 +145,17 @@ class MatterEntanglerBlockEntity(blockPos: BlockPos, blockState: BlockState) : M
if (!energy.batteryLevel.isPositive)
return JobContainer.noEnergy()
val inputs = CraftingInput.of(3, 3, inputs.toList())
val recipe = (level ?: return JobContainer.failure())
.recipeManager
.byType(MRecipes.MATTER_ENTANGLER)
.values
.firstOrNull { it.value.matches(inputs, level!!) } ?: return JobContainer.noItem()
val result = recipe.value.assemble(inputs, level!!.registryAccess())
inputs.forEach { it.shrink(1) }
inputs.setChanged()
this.inputs.forEach { it.shrink(1) }
this.inputs.setChanged()
return JobContainer.success(
Job(

View File

@ -3,27 +3,28 @@ package ru.dbotthepony.mc.otm.block.entity.matter
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
import net.minecraft.core.BlockPos
import net.minecraft.world.level.block.state.BlockState
import ru.dbotthepony.mc.otm.menu.matter.MatterPanelMenu
import net.minecraft.core.HolderLookup
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag
import net.minecraft.world.level.Level
import net.minecraftforge.common.util.INBTSerializable
import net.minecraft.world.level.block.state.BlockState
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
import ru.dbotthepony.mc.otm.capability.matter.*
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.matter.IReplicationTaskProvider
import ru.dbotthepony.mc.otm.capability.matter.PatternState
import ru.dbotthepony.mc.otm.capability.matter.ReplicationTask
import ru.dbotthepony.mc.otm.capability.matter.ReplicationTaskAllocation
import ru.dbotthepony.mc.otm.core.collect.WeakHashSet
import ru.dbotthepony.mc.otm.core.nbt.getBoolean
import ru.dbotthepony.mc.otm.core.nbt.getCompoundList
import ru.dbotthepony.mc.otm.core.nbt.map
import ru.dbotthepony.mc.otm.core.nbt.mapString
import ru.dbotthepony.mc.otm.core.nbt.set
import ru.dbotthepony.mc.otm.core.util.ItemSorter
import ru.dbotthepony.mc.otm.graph.matter.SimpleMatterNode
import ru.dbotthepony.mc.otm.menu.IItemSortingSettings
import ru.dbotthepony.mc.otm.menu.matter.MatterPanelMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import java.util.*
import java.util.stream.Stream
@ -81,7 +82,7 @@ class MatterPanelBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte
init {
exposeGlobally(MatteryCapability.MATTER_NODE, matterNode)
exposeGlobally(MatteryCapability.TASK, this)
exposeGlobally(MatteryCapability.REPLICATION_TASK, this)
savetables.bool(::isProvidingTasks)
}
@ -149,8 +150,8 @@ class MatterPanelBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte
return true
}
override fun saveShared(nbt: CompoundTag) {
super.saveShared(nbt)
override fun saveShared(nbt: CompoundTag, registry: HolderLookup.Provider) {
super.saveShared(nbt, registry)
val list = ListTag()
@ -163,14 +164,14 @@ class MatterPanelBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte
val settings = CompoundTag()
for ((uuid, value) in playerSettings) {
settings[uuid.toString()] = value.serializeNBT()
settings[uuid.toString()] = value.serializeNBT(registry)
}
nbt["settings"] = settings
}
override fun load(nbt: CompoundTag) {
super.load(nbt)
override fun loadAdditional(nbt: CompoundTag, registry: HolderLookup.Provider) {
super.loadAdditional(nbt, registry)
_tasks.clear()
val list = nbt.getCompoundList("tasks")
@ -186,8 +187,9 @@ class MatterPanelBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte
nbt.map("settings") { it: CompoundTag ->
for (k in it.allKeys) {
playerSettings.computeIfAbsent(UUID.fromString(k), Object2ObjectFunction { PlayerSettings() })
.deserializeNBT(it.getCompound(k))
playerSettings
.computeIfAbsent(UUID.fromString(k), Object2ObjectFunction { PlayerSettings() })
.deserializeNBT(registry, it.getCompound(k))
}
}
}

View File

@ -1,6 +1,7 @@
package ru.dbotthepony.mc.otm.block.entity.matter
import net.minecraft.core.BlockPos
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.nbt.StringTag
import net.minecraft.resources.ResourceLocation
import net.minecraft.world.entity.player.Inventory
@ -10,7 +11,6 @@ import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.registries.ForgeRegistries
import ru.dbotthepony.kommons.util.getValue
import ru.dbotthepony.kommons.util.setValue
import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity
@ -78,7 +78,7 @@ class MatterReconstructorBlockEntity(blockPos: BlockPos, blockState: BlockState)
}
init {
exposeGlobally(MatteryCapability.MATTER, matter)
exposeGlobally(MatteryCapability.MATTER_BLOCK, matter)
exposeGlobally(MatteryCapability.MATTER_NODE, matterNode)
savetables.stateful(::repairContainer)
@ -92,7 +92,7 @@ class MatterReconstructorBlockEntity(blockPos: BlockPos, blockState: BlockState)
savetables.Stateless(::lastItem, type = StringTag::class.java)
.withSerializer { it?.registryName?.toString()?.let(StringTag::valueOf) }
.withDeserializer { ResourceLocation.tryParse(it.asString)?.let { ForgeRegistries.ITEMS.getValue(it) } }
.withDeserializer { ResourceLocation.tryParse(it.asString)?.let { BuiltInRegistries.ITEM.get(it) } }
}
val energyConfig = ConfigurableEnergy(energy)

View File

@ -66,7 +66,7 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState)
val energyConfig = ConfigurableEnergy(energy)
init {
exposeGlobally(MatteryCapability.MATTER, matter)
exposeGlobally(MatteryCapability.MATTER_BLOCK, matter)
exposeGlobally(MatteryCapability.MATTER_NODE, matterNode)
savetables.stateful(::energy, ENERGY_KEY)

View File

@ -30,7 +30,6 @@ import ru.dbotthepony.mc.otm.container.UpgradeContainer
import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.util.item
import ru.dbotthepony.mc.otm.data.DecimalCodec
import ru.dbotthepony.mc.otm.data.UUIDCodec
import ru.dbotthepony.mc.otm.data.minRange
import ru.dbotthepony.mc.otm.graph.matter.MatterNode
import ru.dbotthepony.mc.otm.matter.MatterManager
@ -96,7 +95,7 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
}
init {
exposeGlobally(MatteryCapability.MATTER, matter)
exposeGlobally(MatteryCapability.MATTER_BLOCK, matter)
exposeGlobally(MatteryCapability.MATTER_NODE, matterNode)
savetables.stateful(::energy, ENERGY_KEY)

View File

@ -72,11 +72,6 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
savetables.stateful(::upgrades)
}
override fun invalidateCaps() {
super.invalidateCaps()
matterNode.isValid = false
}
override fun setRemoved() {
super.setRemoved()
matterNode.isValid = false

View File

@ -19,7 +19,6 @@ import ru.dbotthepony.mc.otm.core.collect.filterNotNull
import ru.dbotthepony.mc.otm.core.collect.map
import ru.dbotthepony.mc.otm.core.filterNotNull
import ru.dbotthepony.mc.otm.core.isNotEmpty
import ru.dbotthepony.mc.otm.core.orNull
import ru.dbotthepony.mc.otm.graph.matter.SimpleMatterNode
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import java.util.stream.Stream
@ -29,17 +28,17 @@ class PatternStorageBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
val matterNode = SimpleMatterNode(patterns = this)
val container: MatteryContainer = object : MatteryContainer(this::setChanged, 8) {
val container: MatteryContainer = object : MatteryContainer(::markDirtyFast, 8) {
override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) {
if (!ItemStack.isSameItemSameTags(new, old)) {
if (!ItemStack.isSameItemSameComponents(new, old)) {
if (!old.isEmpty) {
old.getCapability(MatteryCapability.PATTERN).ifPresent { cap: IPatternStorage ->
old.getCapability(MatteryCapability.PATTERN_ITEM)?.let { cap: IPatternStorage ->
cap.patterns.forEach { matterNode.graph.onPatternRemoved(it) }
}
}
if (!new.isEmpty) {
new.getCapability(MatteryCapability.PATTERN).ifPresent { cap: IPatternStorage ->
new.getCapability(MatteryCapability.PATTERN_ITEM)?.let { cap: IPatternStorage ->
cap.patterns.forEach { matterNode.graph.onPatternAdded(it) }
}
}
@ -61,7 +60,7 @@ class PatternStorageBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
for (i in 0..7) {
state = state.setValue(
PatternStorageBlock.PATTERN_STORAGE_DISKS_PROPS[i],
this.container.getItem(i).getCapability(MatteryCapability.PATTERN).isPresent
this.container.getItem(i).getCapability(MatteryCapability.PATTERN_ITEM) != null
)
}
@ -77,13 +76,8 @@ class PatternStorageBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
matterNode.discover(this)
}
override fun invalidateCaps() {
super.invalidateCaps()
matterNode.isValid = false
}
init {
exposeGlobally(MatteryCapability.PATTERN, this)
exposeGlobally(MatteryCapability.PATTERN_BLOCK, this)
exposeGlobally(MatteryCapability.MATTER_NODE, matterNode)
savetables.stateful(::container, INVENTORY_KEY)
@ -96,7 +90,7 @@ class PatternStorageBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
override val patterns: Stream<PatternState> get() {
return container.stream()
.filter { it.isNotEmpty }
.map { it.getCapability(MatteryCapability.PATTERN).orNull() }
.map { it.getCapability(MatteryCapability.PATTERN_ITEM) }
.filterNotNull()
.flatMap { it.patterns }
}
@ -104,7 +98,7 @@ class PatternStorageBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
override val patternCapacity: Int get() {
var stored = 0L
for (pattern in this.container.iterator().map { it.getCapability(MatteryCapability.PATTERN).orNull() }.filterNotNull())
for (pattern in this.container.iterator().map { it.getCapability(MatteryCapability.PATTERN_ITEM) }.filterNotNull())
stored += pattern.patternCapacity.toLong()
return if (stored > Int.MAX_VALUE) Int.MAX_VALUE else stored.toInt()
@ -113,7 +107,7 @@ class PatternStorageBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
override val storedPatterns: Int get() {
var stored = 0L
for (pattern in this.container.iterator().map { it.getCapability(MatteryCapability.PATTERN).orNull() }.filterNotNull())
for (pattern in this.container.iterator().map { it.getCapability(MatteryCapability.PATTERN_ITEM) }.filterNotNull())
stored += pattern.storedPatterns.toLong()
return if (stored > Int.MAX_VALUE) Int.MAX_VALUE else stored.toInt()
@ -125,7 +119,7 @@ class PatternStorageBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
}
override fun insertPattern(pattern: PatternState, onlyUpdate: Boolean, simulate: Boolean): PatternInsertStatus {
for (spattern in this.container.iterator().map { it.getCapability(MatteryCapability.PATTERN).orNull() }.filterNotNull()) {
for (spattern in this.container.iterator().map { it.getCapability(MatteryCapability.PATTERN_ITEM) }.filterNotNull()) {
val status = spattern.insertPattern(pattern, onlyUpdate, simulate)
if (!status.isFailed) {

View File

@ -15,7 +15,6 @@ import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.config.MachinesConfig
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.core.ifPresentK
import ru.dbotthepony.mc.otm.menu.storage.DriveRackMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.storage.optics.priority
@ -46,15 +45,15 @@ class DriveRackBlockEntity(blockPos: BlockPos, blockState: BlockState) : Mattery
markDirtyFast()
}
val container: MatteryContainer = object : MatteryContainer(this::setChanged, 4) {
val container: MatteryContainer = object : MatteryContainer(::markDirtyFast, 4) {
override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) {
super.setChanged(slot, new, old)
old.getCapability(MatteryCapability.DRIVE).ifPresentK {
old.getCapability(MatteryCapability.CONDENSATION_DRIVE)?.let {
cell.removeStorageComponent(it.priority(::insertPriority, ::extractPriority).powered(energy).flow(::mode))
}
new.getCapability(MatteryCapability.DRIVE).ifPresentK {
new.getCapability(MatteryCapability.CONDENSATION_DRIVE)?.let {
cell.addStorageComponent(it.priority(::insertPriority, ::extractPriority).powered(energy).flow(::mode))
}
}

View File

@ -29,7 +29,7 @@ class DriveViewerBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte
override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::energyUpdated, MachinesConfig.DRIVE_VIEWER))
val energyConfig = ConfigurableEnergy(energy)
val container: MatteryContainer = object : MatteryContainer(this::markDirtyFast, 1) {
val container: MatteryContainer = object : MatteryContainer(::markDirtyFast, 1) {
override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) {
super.setChanged(slot, new, old)
@ -37,7 +37,7 @@ class DriveViewerBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte
if (level is ServerLevel) {
tickList.once {
val isPresent = new.getCapability(MatteryCapability.DRIVE).isPresent
val isPresent = new.getCapability(MatteryCapability.CONDENSATION_DRIVE) != null
var state = this@DriveViewerBlockEntity.blockState.setValue(DriveViewerBlock.DRIVE_PRESENT, isPresent)
if (!isPresent) {

View File

@ -3,6 +3,7 @@ package ru.dbotthepony.mc.otm.block.entity.storage
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap
import net.minecraft.core.BlockPos
import net.minecraft.core.HolderLookup
import net.minecraft.core.NonNullList
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.chat.Component
@ -11,15 +12,13 @@ import net.minecraft.world.Container
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.inventory.TransientCraftingContainer
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.crafting.CraftingRecipe
import net.minecraft.world.item.crafting.RecipeType
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.ForgeHooks
import net.minecraftforge.common.util.INBTSerializable
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import net.neoforged.neoforge.common.CommonHooks
import net.neoforged.neoforge.common.util.INBTSerializable
import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
@ -27,28 +26,35 @@ import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.client.render.IGUIRenderable
import ru.dbotthepony.mc.otm.client.render.UVWindingOrder
import ru.dbotthepony.mc.otm.client.render.Widgets8
import ru.dbotthepony.mc.otm.config.MachinesConfig
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.graph.storage.StorageNode
import ru.dbotthepony.mc.otm.graph.storage.StorageGraph
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.container.set
import ru.dbotthepony.mc.otm.container.CombinedContainer
import ru.dbotthepony.mc.otm.container.MatteryCraftingContainer
import ru.dbotthepony.mc.otm.container.util.slotIterator
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.collect.map
import ru.dbotthepony.mc.otm.core.collect.toList
import ru.dbotthepony.mc.otm.core.isNotEmpty
import ru.dbotthepony.mc.otm.core.nbt.mapString
import ru.dbotthepony.mc.otm.core.nbt.set
import ru.dbotthepony.mc.otm.core.util.ItemStorageStackSorter
import ru.dbotthepony.mc.otm.graph.storage.StorageGraph
import ru.dbotthepony.mc.otm.graph.storage.StorageNode
import ru.dbotthepony.mc.otm.menu.storage.ItemMonitorMenu
import ru.dbotthepony.mc.otm.storage.*
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.storage.IStorageEventConsumer
import ru.dbotthepony.mc.otm.storage.IStorageProvider
import ru.dbotthepony.mc.otm.storage.ItemStorageStack
import ru.dbotthepony.mc.otm.storage.StorageStack
import ru.dbotthepony.mc.otm.storage.powered.PoweredVirtualComponent
import java.math.BigInteger
import java.util.*
import kotlin.collections.HashMap
import ru.dbotthepony.mc.otm.client.render.Widgets8
import ru.dbotthepony.mc.otm.container.CombinedContainer
import ru.dbotthepony.mc.otm.container.MatteryCraftingContainer
import ru.dbotthepony.mc.otm.container.util.slotIterator
import ru.dbotthepony.mc.otm.core.collect.map
import ru.dbotthepony.mc.otm.core.collect.toList
import ru.dbotthepony.mc.otm.core.isNotEmpty
import ru.dbotthepony.mc.otm.core.util.ItemStorageStackSorter
import kotlin.collections.component1
import kotlin.collections.component2
import kotlin.collections.indices
import kotlin.collections.iterator
import kotlin.collections.set
interface IItemMonitorPlayerSettings {
var ingredientPriority: ItemMonitorPlayerSettings.IngredientPriority
@ -64,7 +70,7 @@ private fun takeOne(inventory: Container?, item: ItemStack): Boolean {
for (slot in iterator) {
val stack = slot.item
if (stack.equals(item, false)) {
if (ItemStack.isSameItemSameComponents(stack, item)) {
stack.shrink(1)
slot.setChanged()
return true
@ -154,7 +160,7 @@ class ItemMonitorPlayerSettings : INBTSerializable<CompoundTag>, IItemMonitorPla
override var sorting: ItemStorageStackSorter = ItemStorageStackSorter.DEFAULT
override var ascendingSort: Boolean = false
override fun serializeNBT(): CompoundTag {
override fun serializeNBT(registry: HolderLookup.Provider): CompoundTag {
return CompoundTag().also {
it["ingredientPriority"] = ingredientPriority.name
it["resultTarget"] = resultTarget.name
@ -164,7 +170,7 @@ class ItemMonitorPlayerSettings : INBTSerializable<CompoundTag>, IItemMonitorPla
}
}
override fun deserializeNBT(nbt: CompoundTag) {
override fun deserializeNBT(registry: HolderLookup.Provider, nbt: CompoundTag) {
ingredientPriority = nbt.mapString("ingredientPriority", IngredientPriority::valueOf, IngredientPriority.SYSTEM)
resultTarget = nbt.mapString("resultTarget", ResultTarget::valueOf, ResultTarget.MIXED)
craftingAmount = nbt.mapString("quickCraftAmount", Amount::valueOf, Amount.STACK)
@ -227,10 +233,10 @@ class ItemMonitorBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte
val server = level.server ?: return false
var craftingRecipe = craftingRecipe
if (craftingRecipe != null && craftingRecipe.matches(craftingGrid, level)) return true
if (craftingRecipe != null && craftingRecipe.matches(craftingGrid.asCraftInput(), level)) return true
if (justCheckForRecipeChange) return false
craftingRecipe = server.recipeManager.getRecipeFor(RecipeType.CRAFTING, craftingGrid, level).orElse(null)?.value
craftingRecipe = server.recipeManager.getRecipeFor(RecipeType.CRAFTING, craftingGrid.asCraftInput(), level).orElse(null)?.value
Arrays.fill(craftingGridTuples, null)
val poweredView = poweredView
@ -303,13 +309,14 @@ class ItemMonitorBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte
val craftingPlayer = craftingPlayer ?: return ItemStack.EMPTY
try {
ForgeHooks.setCraftingPlayer(craftingPlayer)
CommonHooks.setCraftingPlayer(craftingPlayer)
if (craftingRecipe.getResultItem(level.registryAccess()).count != amount) {
return ItemStack.EMPTY
}
} finally {
ForgeHooks.setCraftingPlayer(null)
@Suppress("NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS")
CommonHooks.setCraftingPlayer(null)
}
craftingAmount[craftingPlayer] = craftingAmount.getInt(craftingPlayer) + 1
@ -325,15 +332,16 @@ class ItemMonitorBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte
inProcessOfCraft = true
try {
ForgeHooks.setCraftingPlayer(craftingPlayer)
CommonHooks.setCraftingPlayer(craftingPlayer)
val residue: NonNullList<ItemStack>
val result: ItemStack
try {
residue = craftingRecipe.getRemainingItems(craftingGrid)
residue = craftingRecipe.getRemainingItems(craftingGrid.asCraftInput())
result = craftingRecipe.getResultItem(level.registryAccess())
} finally {
ForgeHooks.setCraftingPlayer(null)
@Suppress("NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS")
CommonHooks.setCraftingPlayer(null)
}
check(residue.size == craftingGrid.containerSize) { "Container and residue list sizes mismatch: ${residue.size} != ${craftingGrid.containerSize}" }
@ -408,29 +416,29 @@ class ItemMonitorBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte
val craftingResultContainer = CraftingResultContainer()
override fun saveLevel(nbt: CompoundTag) {
super.saveLevel(nbt)
override fun saveLevel(nbt: CompoundTag, registry: HolderLookup.Provider) {
super.saveLevel(nbt, registry)
nbt.put("player_settings", CompoundTag().also {
for ((key, value) in this.settings) {
it[key.toString()] = value.serializeNBT()
it[key.toString()] = value.serializeNBT(registry)
}
})
nbt["crafting_grid"] = craftingGrid.serializeNBT()
nbt["crafting_grid"] = craftingGrid.serializeNBT(registry)
}
override fun load(nbt: CompoundTag) {
super.load(nbt)
override fun loadAdditional(nbt: CompoundTag, registry: HolderLookup.Provider) {
super.loadAdditional(nbt, registry)
this.settings.clear()
val settings = nbt.getCompound("player_settings")
for (key in settings.allKeys) {
check(this.settings.put(UUID.fromString(key), ItemMonitorPlayerSettings().also { it.deserializeNBT(settings.getCompound(key)) }) == null)
check(this.settings.put(UUID.fromString(key), ItemMonitorPlayerSettings().also { it.deserializeNBT(registry, settings.getCompound(key)) }) == null)
}
craftingGrid.deserializeNBT(nbt["crafting_grid"])
craftingGrid.deserializeNBT(registry, nbt["crafting_grid"])
}
fun getSettings(ply: ServerPlayer): ItemMonitorPlayerSettings {

View File

@ -12,8 +12,8 @@ import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.capabilities.ForgeCapabilities
import net.minecraftforge.items.IItemHandler
import net.neoforged.neoforge.capabilities.Capabilities
import net.neoforged.neoforge.items.IItemHandler
import ru.dbotthepony.mc.otm.*
import ru.dbotthepony.mc.otm.block.CableBlock
import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity
@ -102,10 +102,10 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter
savetables.int(::extractPriority)
exposeGlobally(MatteryCapability.STORAGE_NODE, cell) { it != RelativeSide.FRONT }
side(RelativeSide.FRONT).track(ForgeCapabilities.ITEM_HANDLER).addListener(Consumer {
CapabilityCache(RelativeSide.FRONT, Capabilities.ItemHandler.BLOCK).addListener(Consumer {
component?.let(cell::removeStorageComponent)
component = if (it.isPresent) {
ItemHandlerComponent(it.orThrow()).also { if (!redstoneControl.isBlockedByRedstone) cell.addStorageComponent(it) }
component = if (it != null) {
ItemHandlerComponent(it).also { if (!redstoneControl.isBlockedByRedstone) cell.addStorageComponent(it) }
} else {
null
}
@ -353,7 +353,7 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter
} else if (current != null && last == null) {
addTracked(slot, current)
} else if (current != null && last != null) {
if (!ItemStack.isSameItemSameTags(current, last)) {
if (!ItemStack.isSameItemSameComponents(current, last)) {
removeTracked(slot)
addTracked(slot, current)
} else if (current.count != last.count) {

View File

@ -11,8 +11,8 @@ import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.capabilities.ForgeCapabilities
import net.minecraftforge.items.IItemHandler
import net.neoforged.neoforge.capabilities.Capabilities
import net.neoforged.neoforge.items.IItemHandler
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.SERVER_IS_LIVE
import ru.dbotthepony.mc.otm.block.CableBlock
@ -27,7 +27,6 @@ import ru.dbotthepony.mc.otm.container.ItemFilter
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.isNotEmpty
import ru.dbotthepony.mc.otm.core.math.RelativeSide
import ru.dbotthepony.mc.otm.core.orNull
import ru.dbotthepony.mc.otm.graph.storage.StorageNode
import ru.dbotthepony.mc.otm.menu.storage.StorageImporterExporterMenu
import ru.dbotthepony.mc.otm.once
@ -39,7 +38,6 @@ import ru.dbotthepony.mc.otm.storage.ItemStorageStack
import ru.dbotthepony.mc.otm.storage.StorageStack
import java.math.BigInteger
import java.util.*
import kotlin.collections.ArrayList
abstract class AbstractStorageImportExport(
blockType: BlockEntityType<*>,
@ -97,7 +95,7 @@ abstract class AbstractStorageImportExport(
cell.discover(this)
}
protected val target = front.track(ForgeCapabilities.ITEM_HANDLER)
protected val target = CapabilityCache(RelativeSide.FRONT, Capabilities.ItemHandler.BLOCK)
abstract val filter: ItemFilter
@ -122,7 +120,7 @@ class StorageImporterBlockEntity(
private var nextTick = INTERVAL
init {
front.Cap(ForgeCapabilities.ITEM_HANDLER, this)
exposeSided(RelativeSide.FRONT, Capabilities.ItemHandler.BLOCK, this)
}
override fun getSlots(): Int {
@ -190,7 +188,7 @@ class StorageImporterBlockEntity(
nextTick--
val target = target.get().orNull()
val target = target.get()
if (nextTick <= 0 && target != null) {
if (lastSlot >= target.slots) {
@ -280,7 +278,7 @@ class StorageExporterBlockEntity(blockPos: BlockPos, blockState: BlockState) :
nextTick--
val target = target.get().orNull()
val target = target.get()
if (nextTick <= 0 && target != null) {
val items = cell.graph.getVirtualComponent(StorageStack.ITEMS)

View File

@ -1,5 +1,6 @@
package ru.dbotthepony.mc.otm.block.entity.tech
import it.unimi.dsi.fastutil.ints.IntList
import net.minecraft.core.BlockPos
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.entity.player.Inventory
@ -9,19 +10,19 @@ import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.crafting.AbstractCookingRecipe
import net.minecraft.world.item.crafting.BlastingRecipe
import net.minecraft.world.item.crafting.RecipeType
import net.minecraft.world.item.crafting.SingleRecipeInput
import net.minecraft.world.item.crafting.SmeltingRecipe
import net.minecraft.world.item.crafting.SmokingRecipe
import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.capabilities.ForgeCapabilities
import net.neoforged.neoforge.capabilities.Capabilities
import ru.dbotthepony.kommons.util.getValue
import ru.dbotthepony.kommons.util.setValue
import ru.dbotthepony.mc.otm.block.entity.ExperienceStorage
import ru.dbotthepony.mc.otm.block.entity.ItemJob
import ru.dbotthepony.mc.otm.block.entity.JobContainer
import ru.dbotthepony.mc.otm.block.entity.JobStatus
import ru.dbotthepony.mc.otm.block.entity.ItemJob
import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity
import ru.dbotthepony.mc.otm.capability.item.CombinedItemHandler
import ru.dbotthepony.mc.otm.capability.UpgradeType
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
@ -34,7 +35,6 @@ import ru.dbotthepony.mc.otm.container.UpgradeContainer
import ru.dbotthepony.mc.otm.container.balance
import ru.dbotthepony.mc.otm.core.collect.filter
import ru.dbotthepony.mc.otm.core.collect.maybe
import ru.dbotthepony.mc.otm.core.getValue
import ru.dbotthepony.mc.otm.core.immutableList
import ru.dbotthepony.mc.otm.core.util.item
import ru.dbotthepony.mc.otm.menu.tech.PoweredFurnaceMenu
@ -55,12 +55,12 @@ sealed class AbstractPoweredFurnaceBlockEntity<P : AbstractCookingRecipe, S : Ma
final override val upgrades = UpgradeContainer(this::markDirtyFast, 2, UpgradeType.BASIC_PROCESSING)
final override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::energyLevelUpdated, upgrades.transform(config)))
val inputs = immutableList(maxJobs) { MatteryContainer(this::itemContainerUpdated, 1) }
val outputs = immutableList(maxJobs) { MatteryContainer(this::itemContainerUpdated, 1) }
val inputs = MatteryContainer(this::itemContainerUpdated, maxJobs)
val outputs = MatteryContainer(this::itemContainerUpdated, maxJobs)
init {
inputs.forEach { addDroppableContainer(it) }
outputs.forEach { addDroppableContainer(it) }
addDroppableContainer(inputs)
addDroppableContainer(outputs)
}
inner class SyncSlot {
@ -77,13 +77,13 @@ sealed class AbstractPoweredFurnaceBlockEntity<P : AbstractCookingRecipe, S : Ma
val experience = ExperienceStorage(config::maxExperienceStored).also(::addNeighbourListener)
val energyConfig = ConfigurableEnergy(energy)
val itemConfig = ConfigurableItemHandler(
input = CombinedItemHandler(inputs.map { it.handler(HandlerFilter.OnlyIn) }),
output = CombinedItemHandler(outputs.map { it.handler(HandlerFilter.OnlyOut) }),
input = inputs.handler(HandlerFilter.OnlyIn),
output = outputs.handler(HandlerFilter.OnlyOut),
battery = batteryItemHandler
)
init {
exposeGlobally(ForgeCapabilities.FLUID_HANDLER, experience)
exposeGlobally(Capabilities.FluidHandler.BLOCK, experience)
savetables.stateful(::upgrades)
savetables.stateful(::energy)
@ -105,7 +105,7 @@ sealed class AbstractPoweredFurnaceBlockEntity<P : AbstractCookingRecipe, S : Ma
}
override fun onJobFinish(status: JobStatus<ItemJob>, id: Int) {
if (outputs[id].fullyAddItem(status.job.itemStack)) {
if (outputs.fullyAddItem(status.job.itemStack, slots = IntList.of(id))) {
experience.storeExperience(status.experience, this)
syncSlots[id].inputItem = ItemStack.EMPTY
syncSlots[id].outputItem = ItemStack.EMPTY
@ -132,16 +132,22 @@ sealed class AbstractPoweredFurnaceBlockEntity<P : AbstractCookingRecipe, S : Ma
if (secondaryRecipeType != null) {
val recipe = level.recipeManager
.byType(secondaryRecipeType)
.values
.iterator()
.filter { it.value.matches(inputs[id], 0) }
.filter { it.value.matches(SingleRecipeInput(inputs[id]), level) }
.maybe()?.value
if (recipe != null) {
val toProcess = inputs[id][0].count.coerceAtMost(1 + upgrades.processingItems)
val toProcess = inputs[id].count.coerceAtMost(1 + upgrades.processingItems)
inputs[id][0].shrink(toProcess)
inputs[id].setChanged(id)
val output = recipe.getResultItem(level.registryAccess()).copyWithCount(toProcess)
val inputItem = inputs[id].copyWithCount(1)
inputs[id].shrink(toProcess)
inputs.setChanged(id)
syncSlots[id].inputItem = inputItem
syncSlots[id].outputItem = output.copy()
syncSlots[id].progress = 0f
return JobContainer.success(
ItemJob(
@ -152,11 +158,11 @@ sealed class AbstractPoweredFurnaceBlockEntity<P : AbstractCookingRecipe, S : Ma
}
}
return level.recipeManager.getRecipeFor(recipeType, inputs[id], level).map {
val output = it.value.assemble(inputs[id], level.registryAccess())
val inputItem = inputs[id][0].copyWithCount(1)
val toProcess = inputs[id][0].count.coerceAtMost(upgrades.processingItems + 1)
inputs[id][0].shrink(toProcess)
return level.recipeManager.getRecipeFor(recipeType, SingleRecipeInput(inputs[id]), level).map {
val output = it.value.assemble(SingleRecipeInput(inputs[id]), level.registryAccess())
val inputItem = inputs[id].copyWithCount(1)
val toProcess = inputs[id].count.coerceAtMost(upgrades.processingItems + 1)
inputs[id].shrink(toProcess)
syncSlots[id].inputItem = inputItem
syncSlots[id].outputItem = output.copy()

View File

@ -44,7 +44,7 @@ class AndroidChargerBlockEntity(blockPos: BlockPos, blockState: BlockState) : Ma
ents.sort()
for ((ent) in ents) {
val ply = ent.matteryPlayer ?: continue
val ply = (ent as Player).matteryPlayer
if (ply.isAndroid) {
val received = ply.androidEnergy.receiveEnergyChecked(available, false)

View File

@ -11,13 +11,13 @@ import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.phys.AABB
import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity
import ru.dbotthepony.mc.otm.block.entity.WorkerState
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.IMatteryPlayer
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.capability.moveEnergy
import ru.dbotthepony.mc.otm.config.MachinesConfig
import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.ifPresentK
import ru.dbotthepony.mc.otm.menu.tech.AndroidStationMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities
@ -81,10 +81,8 @@ class AndroidStationBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
val z = blockPos.z.toDouble()
for (ent in level.getEntitiesOfClass(ServerPlayer::class.java, AABB(x, y, z, x + 1.0, y + 2.0, z + 1.0))) {
ent.getCapability(MatteryCapability.MATTERY_PLAYER).ifPresentK {
if (it.isAndroid)
moveEnergy(energy, it.androidEnergy, amount = energy.batteryLevel, simulate = false, ignoreFlowRestrictions = true)
}
if (ent.matteryPlayer.isAndroid)
moveEnergy(energy, ent.matteryPlayer.androidEnergy, amount = energy.batteryLevel, simulate = false, ignoreFlowRestrictions = true)
}
}
}

View File

@ -6,10 +6,14 @@ import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.capabilities.ForgeCapabilities
import net.neoforged.bus.api.SubscribeEvent
import net.neoforged.fml.common.EventBusSubscriber
import net.neoforged.neoforge.capabilities.Capabilities
import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent
import ru.dbotthepony.kommons.util.getValue
import ru.dbotthepony.kommons.util.setValue
import ru.dbotthepony.kommons.util.value
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
import ru.dbotthepony.mc.otm.capability.FlowDirection
import ru.dbotthepony.mc.otm.capability.energy
@ -35,7 +39,7 @@ class BatteryBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Matte
val container: MatteryContainer = object : MatteryContainer(::setChanged, CAPACITY) {
override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) {
super.setChanged(slot, new, old)
batteryStatus[slot].value = new.getCapability(ForgeCapabilities.ENERGY).isPresent
batteryStatus[slot].value = new.getCapability(Capabilities.EnergyStorage.ITEM) != null
gaugeLevel = batteryLevel.percentage(maxBatteryLevel)
}

View File

@ -6,7 +6,6 @@ import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.ForgeHooks
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
import ru.dbotthepony.mc.otm.block.entity.WorkerState
import ru.dbotthepony.mc.otm.capability.*
@ -89,7 +88,7 @@ class ChemicalGeneratorBlockEntity(pos: BlockPos, state: BlockState) : MatteryDe
if (workTicks == 0 && !redstoneControl.isBlockedByRedstone && checkFuelSlot) {
if (!fuelContainer[0].isEmpty) {
val ticks = ForgeHooks.getBurnTime(fuelContainer[0], null) / MachinesConfig.ChemicalGenerator.RATIO
val ticks = fuelContainer[0].getBurnTime(null) / MachinesConfig.ChemicalGenerator.RATIO
if (
ticks > 0 &&

View File

@ -1,6 +1,7 @@
package ru.dbotthepony.mc.otm.block.entity.tech
import net.minecraft.core.BlockPos
import net.minecraft.core.HolderLookup
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.IntTag
import net.minecraft.nbt.ListTag
@ -9,7 +10,7 @@ import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.capabilities.ForgeCapabilities
import net.neoforged.neoforge.capabilities.Capabilities
import ru.dbotthepony.kommons.util.getValue
import ru.dbotthepony.kommons.util.setValue
import ru.dbotthepony.mc.otm.block.tech.EnergyCounterBlock
@ -19,6 +20,7 @@ import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
import ru.dbotthepony.mc.otm.core.*
import ru.dbotthepony.mc.otm.core.math.BlockRotation
import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.math.RelativeSide
import ru.dbotthepony.mc.otm.core.math.getDecimal
import ru.dbotthepony.mc.otm.core.nbt.getByteArrayList
import ru.dbotthepony.mc.otm.core.nbt.map
@ -84,14 +86,14 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
return value
}
override fun saveShared(nbt: CompoundTag) {
super.saveShared(nbt)
override fun saveShared(nbt: CompoundTag, registry: HolderLookup.Provider) {
super.saveShared(nbt, registry)
nbt[PASSED_ENERGY_KEY] = passed.serializeNBT()
ioLimit?.let { nbt[IO_LIMIT_KEY] = it.serializeNBT() }
}
override fun saveLevel(nbt: CompoundTag) {
super.saveLevel(nbt)
override fun saveLevel(nbt: CompoundTag, registry: HolderLookup.Provider) {
super.saveLevel(nbt, registry)
val list = ListTag()
nbt[POWER_HISTORY_KEY] = list
nbt[POWER_HISTORY_POINTER_KEY] = historyTick
@ -100,8 +102,8 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
list.add(num.serializeNBT())
}
override fun load(nbt: CompoundTag) {
super.load(nbt)
override fun loadAdditional(nbt: CompoundTag, registry: HolderLookup.Provider) {
super.loadAdditional(nbt, registry)
passed = nbt.getDecimal(PASSED_ENERGY_KEY)
ioLimit = nbt.mapPresent(IO_LIMIT_KEY, Decimal.Companion::deserializeNBT)
@ -127,8 +129,8 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
private val energyInput = EnergyCounterCap(true)
private val energyOutput = EnergyCounterCap(false)
private val inputCapability by front.trackEnergy()
private val outputCapability by back.trackEnergy()
private val inputCapability by CapabilityCache(RelativeSide.FRONT, Capabilities.EnergyStorage.BLOCK)
private val outputCapability by CapabilityCache(RelativeSide.BACK, Capabilities.EnergyStorage.BLOCK)
private inner class EnergyCounterCap(isInput: Boolean) : IMatteryEnergyStorage {
override val energyFlow = FlowDirection.input(isInput)
@ -137,7 +139,7 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
if (redstoneControl.isBlockedByRedstone)
return Decimal.ZERO
val it = inputCapability.orNull()
val it = inputCapability
if (it != null) {
val diff: Decimal
@ -165,7 +167,7 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
if (redstoneControl.isBlockedByRedstone)
return Decimal.ZERO
val it = outputCapability.orNull()
val it = outputCapability
if (it != null) {
val diff: Decimal
@ -195,7 +197,7 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
override var batteryLevel: Decimal
get() {
if (energyFlow.input) {
val it = outputCapability.orNull()
val it = outputCapability
if (it != null) {
if (it is IMatteryEnergyStorage) {
@ -205,7 +207,7 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
return Decimal(it.energyStored)
}
} else {
val it = inputCapability.orNull()
val it = inputCapability
if (it != null) {
if (it is IMatteryEnergyStorage) {
@ -225,7 +227,7 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
override val maxBatteryLevel: Decimal
get() {
if (energyFlow.input) {
val it = outputCapability.orNull()
val it = outputCapability
if (it != null) {
if (it is IMatteryEnergyStorage) {
@ -235,7 +237,7 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
return Decimal(it.maxEnergyStored)
}
} else {
val it = inputCapability.orNull()
val it = inputCapability
if (it != null) {
if (it is IMatteryEnergyStorage) {
@ -252,7 +254,7 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
override val missingPower: Decimal
get() {
if (energyFlow.input) {
val it = outputCapability.orNull()
val it = outputCapability
if (it != null) {
if (it is IMatteryEnergyStorage) {
@ -262,7 +264,7 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
return Decimal((it.maxEnergyStored - it.energyStored).coerceAtLeast(0))
}
} else {
val it = inputCapability.orNull()
val it = inputCapability
if (it != null) {
if (it is IMatteryEnergyStorage) {
@ -278,11 +280,8 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
}
init {
front.Cap(ForgeCapabilities.ENERGY, energyInput)
front.Cap(MatteryCapability.ENERGY, energyInput)
back.Cap(ForgeCapabilities.ENERGY, energyOutput)
back.Cap(MatteryCapability.ENERGY, energyOutput)
exposeEnergySided(RelativeSide.FRONT, energyInput)
exposeEnergySided(RelativeSide.BACK, energyOutput)
}
override fun tick() {

View File

@ -7,10 +7,9 @@ import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.capabilities.ForgeCapabilities
import net.neoforged.neoforge.capabilities.Capabilities
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
import ru.dbotthepony.mc.otm.capability.FlowDirection
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.energy.BlockEnergyStorageImpl
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
import ru.dbotthepony.mc.otm.capability.moveEnergy
@ -19,7 +18,6 @@ import ru.dbotthepony.mc.otm.config.MachinesConfig
import ru.dbotthepony.mc.otm.container.HandlerFilter
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.core.MultiblockBuilder
import ru.dbotthepony.mc.otm.core.ifPresentK
import ru.dbotthepony.mc.otm.menu.tech.EnergyHatchMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities
@ -32,7 +30,7 @@ class EnergyHatchBlockEntity(
) : MatteryDeviceBlockEntity(type, blockPos, blockState) {
val energy = ProfiledEnergyStorage(BlockEnergyStorageImpl(this::markDirtyFast, FlowDirection.input(isInput), capacity))
val container = object : MatteryContainer(this::markDirtyFast, CAPACITY) {
val container = object : MatteryContainer(::markDirtyFast, CAPACITY) {
override fun getMaxStackSize(slot: Int, itemStack: ItemStack): Int {
return 1
}
@ -45,9 +43,8 @@ class EnergyHatchBlockEntity(
savetables.stateful(::container, BATTERY_KEY)
// it would cause a lot of frustration if hatches accept stuff only though one face
exposeGlobally(ForgeCapabilities.ENERGY, energy)
exposeGlobally(MatteryCapability.ENERGY, energy)
exposeGlobally(ForgeCapabilities.ITEM_HANDLER, itemHandler)
exposeGlobally(Capabilities.EnergyStorage.BLOCK, energy)
exposeGlobally(Capabilities.ItemHandler.BLOCK, itemHandler)
}
override fun tick() {
@ -55,7 +52,7 @@ class EnergyHatchBlockEntity(
if (!redstoneControl.isBlockedByRedstone) {
container.forEach {
it.getCapability(ForgeCapabilities.ENERGY).ifPresentK {
it.getCapability(Capabilities.EnergyStorage.ITEM)?.let {
if (isInput) {
moveEnergy(it, energy, simulate = false)
} else {

View File

@ -1,6 +1,9 @@
package ru.dbotthepony.mc.otm.block.entity.tech
import net.minecraft.core.BlockPos
import net.minecraft.core.Holder
import net.minecraft.core.HolderLookup
import net.minecraft.nbt.CompoundTag
import net.minecraft.server.level.ServerLevel
import net.minecraft.sounds.SoundEvents
import net.minecraft.sounds.SoundSource
@ -9,11 +12,12 @@ import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.enchantment.Enchantment
import net.minecraft.world.item.enchantment.Enchantments
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.fluids.FluidStack
import net.minecraftforge.fluids.capability.IFluidHandler
import net.neoforged.neoforge.fluids.FluidStack
import net.neoforged.neoforge.fluids.capability.IFluidHandler
import ru.dbotthepony.mc.otm.block.entity.ExperienceStorage.Companion.XP_TO_LIQUID_RATIO
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
import ru.dbotthepony.mc.otm.block.tech.EssenceStorageBlock
@ -22,6 +26,7 @@ import ru.dbotthepony.mc.otm.config.MachinesConfig
import ru.dbotthepony.mc.otm.container.HandlerFilter
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.core.getEntitiesInEllipsoid
import ru.dbotthepony.mc.otm.core.lookupOrThrow
import ru.dbotthepony.mc.otm.core.math.Vector
import ru.dbotthepony.mc.otm.core.util.countingLazy
import ru.dbotthepony.mc.otm.item.EssenceCapsuleItem
@ -42,6 +47,8 @@ class EssenceStorageBlockEntity(blockPos: BlockPos, blockState: BlockState) : Ma
val servoContainer = MatteryContainer(::markDirtyFast, 1)
val mendingContainer = MatteryContainer(::markDirtyFast, 1).also(::addDroppableContainer)
private var mending: Holder<Enchantment>? = null
init {
savetables.long(::experienceStored)
savetables.stateful(::capsuleContainer)
@ -62,7 +69,7 @@ class EssenceStorageBlockEntity(blockPos: BlockPos, blockState: BlockState) : Ma
})),
mendingContainer.handler(object : HandlerFilter {
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
return stack.isDamaged && stack.getEnchantmentLevel(Enchantments.MENDING) > 0
return stack.isDamaged && stack.getEnchantmentLevel(mending!!) > 0
}
override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
@ -72,6 +79,12 @@ class EssenceStorageBlockEntity(blockPos: BlockPos, blockState: BlockState) : Ma
)
)
override fun loadAdditional(nbt: CompoundTag, registry: HolderLookup.Provider) {
super.loadAdditional(nbt, registry)
mending = registry.lookupOrThrow(Enchantments.MENDING)
}
val fluidConfig = ConfigurableFluidHandler(this)
override fun getTanks(): Int {

View File

@ -70,10 +70,6 @@ class GravitationStabilizerBlockEntity(p_155229_: BlockPos, p_155230_: BlockStat
blackHole?.stabilizerDetached(this)
}
override fun getRenderBoundingBox(): AABB {
return AABB(blockPos.offset(-RANGE, -RANGE, -RANGE), blockPos.offset(RANGE, RANGE, RANGE))
}
companion object {
const val RANGE = 64
}

View File

@ -6,7 +6,7 @@ import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.capabilities.ForgeCapabilities
import net.neoforged.neoforge.capabilities.Capabilities
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
import ru.dbotthepony.mc.otm.block.entity.decorative.CargoCrateBlockEntity
import ru.dbotthepony.mc.otm.container.HandlerFilter
@ -26,7 +26,7 @@ class ItemHatchBlockEntity(
init {
savetables.stateful(::container, INVENTORY_KEY)
exposeGlobally(ForgeCapabilities.ITEM_HANDLER, itemHandler)
exposeGlobally(Capabilities.ItemHandler.BLOCK, itemHandler)
}
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {

View File

@ -7,7 +7,7 @@ import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.capabilities.ForgeCapabilities
import net.neoforged.neoforge.capabilities.Capabilities
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
import ru.dbotthepony.mc.otm.capability.FlowDirection
import ru.dbotthepony.mc.otm.capability.MatteryCapability
@ -18,7 +18,6 @@ import ru.dbotthepony.mc.otm.config.MachinesConfig
import ru.dbotthepony.mc.otm.container.HandlerFilter
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.core.MultiblockBuilder
import ru.dbotthepony.mc.otm.core.ifPresentK
import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.menu.tech.MatterHatchMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities
@ -29,7 +28,7 @@ class MatterHatchBlockEntity(
blockPos: BlockPos,
blockState: BlockState
) : MatteryDeviceBlockEntity(type, blockPos, blockState) {
val container = object : MatteryContainer(this::markDirtyFast, CAPACITY) {
val container = object : MatteryContainer(::markDirtyFast, CAPACITY) {
override fun getMaxStackSize(slot: Int, itemStack: ItemStack): Int {
return 1
}
@ -48,8 +47,8 @@ class MatterHatchBlockEntity(
savetables.stateful(::matter, MATTER_STORAGE_KEY)
// it would cause a lot of frustration if hatches accept stuff only though one face
exposeGlobally(ForgeCapabilities.ITEM_HANDLER, itemHandler)
exposeGlobally(MatteryCapability.MATTER, matter)
exposeGlobally(Capabilities.ItemHandler.BLOCK, itemHandler)
exposeGlobally(MatteryCapability.MATTER_BLOCK, matter)
}
override fun tick() {
@ -57,7 +56,7 @@ class MatterHatchBlockEntity(
if (!redstoneControl.isBlockedByRedstone && matter.missingMatter > Decimal.ZERO) {
container.forEach {
it.getCapability(MatteryCapability.MATTER).ifPresentK {
it.getCapability(MatteryCapability.MATTER_ITEM)?.let {
if (isInput) {
moveMatter(it, matter, simulate = false)
} else {

View File

@ -6,7 +6,7 @@ import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.capabilities.ForgeCapabilities
import net.neoforged.neoforge.capabilities.Capabilities
import ru.dbotthepony.mc.otm.block.entity.ExperienceStorage
import ru.dbotthepony.mc.otm.block.entity.JobContainer
import ru.dbotthepony.mc.otm.block.entity.JobStatus
@ -44,7 +44,7 @@ class PlatePressBlockEntity(
)
init {
exposeGlobally(ForgeCapabilities.FLUID_HANDLER, experience)
exposeGlobally(Capabilities.FluidHandler.BLOCK, experience)
savetables.stateful(::energy, ENERGY_KEY)
savetables.stateful(::inputContainer)
@ -76,7 +76,6 @@ class PlatePressBlockEntity(
val recipe = level.recipeManager
.byType(MRecipes.PLATE_PRESS)
.values
.iterator()
.filter { it.value.matches(inputContainer, id) }
.maybe()?.value ?: return JobContainer.noItem()

View File

@ -22,7 +22,7 @@ import ru.dbotthepony.mc.otm.block.addSimpleDescription
import ru.dbotthepony.mc.otm.block.entity.tech.AndroidStationBlockEntity
import ru.dbotthepony.mc.otm.block.entity.WorkerState
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.core.orNull
import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.shapes.BlockShapes
@ -41,9 +41,7 @@ class AndroidStationBlock(val color: DyeColor?) : MatteryBlock(DEFAULT_MACHINE_P
hand: InteractionHand,
blockHitResult: BlockHitResult
): InteractionResult {
val cap = ply.getCapability(MatteryCapability.MATTERY_PLAYER).orNull() ?: return InteractionResult.FAIL
if (!cap.isAndroid)
if (!ply.matteryPlayer.isAndroid)
return InteractionResult.FAIL
return super.use(blockState, level, blockPos, ply, hand, blockHitResult)

View File

@ -40,7 +40,7 @@ class EssenceStorageBlock(val color: DyeColor?) : RotatableMatteryBlock(Properti
addSimpleDescription()
tooltips.blockEntityData<LongTag>("experienceStored") { _, l, acceptor ->
tooltips.blockEntityData<LongTag>("experienceStored") { _, _, l, acceptor ->
if (minecraft.window.isShiftDown) {
acceptor(TranslatableComponent("otm.gui.experience", l.asLong).withStyle(ChatFormatting.GRAY))
} else {

View File

@ -2,10 +2,11 @@ package ru.dbotthepony.mc.otm.capability
import com.google.common.collect.ImmutableList
import it.unimi.dsi.fastutil.objects.ObjectArrayList
import net.minecraft.core.HolderLookup
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag
import net.minecraft.nbt.NumericTag
import net.minecraftforge.common.util.INBTSerializable
import net.neoforged.neoforge.common.util.INBTSerializable
import ru.dbotthepony.mc.otm.core.forValidRefs
import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.nbt.map
@ -81,7 +82,7 @@ abstract class AbstractProfiledStorage<out P>(val parent: P) : INBTSerializable<
}
val savedata: INBTSerializable<CompoundTag?> = object : INBTSerializable<CompoundTag?> {
override fun serializeNBT(): CompoundTag {
override fun serializeNBT(registry: HolderLookup.Provider): CompoundTag {
return CompoundTag().also { tag ->
tag["historyReceive"] = ListTag().also {
for (value in historyReceiveInternal) {
@ -99,7 +100,7 @@ abstract class AbstractProfiledStorage<out P>(val parent: P) : INBTSerializable<
}
}
override fun deserializeNBT(nbt: CompoundTag?) {
override fun deserializeNBT(registry: HolderLookup.Provider, nbt: CompoundTag?) {
tick = 0
thisTickReceive = Decimal.ZERO
thisTickTransfer = Decimal.ZERO
@ -131,16 +132,16 @@ abstract class AbstractProfiledStorage<out P>(val parent: P) : INBTSerializable<
}
}
override fun serializeNBT(): CompoundTag {
override fun serializeNBT(registry: HolderLookup.Provider): CompoundTag {
val tag: CompoundTag
if (parent is INBTSerializable<*>) {
tag = (parent as INBTSerializable<CompoundTag?>).serializeNBT() ?: CompoundTag()
tag = (parent as INBTSerializable<CompoundTag?>).serializeNBT(registry) ?: CompoundTag()
} else {
tag = CompoundTag()
}
val tag2 = savedata.serializeNBT()!!
val tag2 = savedata.serializeNBT(registry)!!
for (k in tag2.allKeys) {
tag[k] = tag2[k]!!
@ -157,12 +158,12 @@ abstract class AbstractProfiledStorage<out P>(val parent: P) : INBTSerializable<
return calcWeightedAverage(historyReceive, tick)
}
override fun deserializeNBT(nbt: CompoundTag?) {
override fun deserializeNBT(registry: HolderLookup.Provider, nbt: CompoundTag?) {
if (parent is INBTSerializable<*>) {
(parent as INBTSerializable<CompoundTag?>).deserializeNBT(nbt)
(parent as INBTSerializable<CompoundTag?>).deserializeNBT(registry, nbt)
}
savedata.deserializeNBT(nbt)
savedata.deserializeNBT(registry, nbt)
}
companion object {

View File

@ -3,14 +3,14 @@ package ru.dbotthepony.mc.otm.capability
import com.google.common.collect.Streams
import net.minecraft.ChatFormatting
import net.minecraft.network.chat.Component
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import net.minecraftforge.common.capabilities.ForgeCapabilities
import net.minecraftforge.common.capabilities.ICapabilityProvider
import net.minecraftforge.energy.IEnergyStorage
import net.minecraftforge.fluids.FluidStack
import net.minecraftforge.fluids.capability.IFluidHandler
import net.minecraftforge.items.IItemHandler
import net.neoforged.neoforge.capabilities.Capabilities
import net.neoforged.neoforge.energy.IEnergyStorage
import net.neoforged.neoforge.fluids.FluidStack
import net.neoforged.neoforge.fluids.capability.IFluidHandler
import net.neoforged.neoforge.items.IItemHandler
import org.apache.logging.log4j.LogManager
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
import ru.dbotthepony.mc.otm.capability.fluid.iterator
@ -33,13 +33,13 @@ import ru.dbotthepony.mc.otm.core.collect.filter
import ru.dbotthepony.mc.otm.core.collect.map
import ru.dbotthepony.mc.otm.core.isNotEmpty
import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.orNull
import ru.dbotthepony.mc.otm.core.util.formatFluidLevel
import java.util.stream.Stream
private val LOGGER = LogManager.getLogger()
val ICapabilityProvider.matteryPlayer: MatteryPlayerCapability? get() = getCapability(MatteryCapability.MATTERY_PLAYER).orNull()
val Player.matteryPlayer: MatteryPlayer get() = (this as IMatteryPlayer).otmPlayer
val LivingEntity.matteryPlayer: MatteryPlayer? get() = (this as? IMatteryPlayer)?.otmPlayer
/**
* Does a checked energy receive, calls [IMatteryEnergyStorage.receiveEnergyChecked] if possible
@ -131,21 +131,21 @@ val IEnergyStorage.chargeRatio: Float get() {
/**
* Shortcut for getting [IEnergyStorage], including wrappers for it
*/
val ICapabilityProvider.energy: IEnergyStorage? get() {
val mattery = getCapability(MatteryCapability.ENERGY)
val ItemStack.energy: IEnergyStorage? get() {
//val mattery = getCapability(MatteryCapability.ITEM_ENERGY)
if (mattery.isPresent) {
return mattery.orNull()
}
//if (mattery != null) {
// return mattery
//}
return getCapability(ForgeCapabilities.ENERGY).orNull()
return getCapability(Capabilities.EnergyStorage.ITEM)
}
/**
* Shortcut for getting sideless [IMatteryEnergyStorage], including wrappers for it
*/
val ICapabilityProvider.matteryEnergy: IMatteryEnergyStorage? get() {
return getCapability(MatteryCapability.ENERGY).orNull()
val ItemStack.matteryEnergy: IMatteryEnergyStorage? get() {
return getCapability(MatteryCapability.ITEM_ENERGY)
}
fun Player.items(includeCosmetics: Boolean = true): Iterator<ItemStack> {
@ -320,7 +320,7 @@ internal fun IFluidHandler.fluidLevel(tooltips: (Component) -> Unit) {
if (fluid.isEmpty) {
tooltips(formatFluidLevel(0, getTankCapacity(0), formatAsReadable = ShiftPressedCond).withStyle(ChatFormatting.GRAY))
} else {
tooltips(formatFluidLevel(fluid.amount, getTankCapacity(0), fluid.displayName, formatAsReadable = ShiftPressedCond).withStyle(ChatFormatting.GRAY))
tooltips(formatFluidLevel(fluid.amount, getTankCapacity(0), fluid.hoverName, formatAsReadable = ShiftPressedCond).withStyle(ChatFormatting.GRAY))
}
}
@ -330,18 +330,18 @@ private fun actuallyMoveFluid(drained: FluidStack, source: IFluidHandler, destin
val filled = destination.fill(drained, IFluidHandler.FluidAction.SIMULATE)
if (filled == 0) return FluidStack.EMPTY
val drained2 = source.drain(FluidStack(drained, filled), IFluidHandler.FluidAction.SIMULATE)
val drained2 = source.drain(drained.copyWithAmount(filled), IFluidHandler.FluidAction.SIMULATE)
if (drained2.amount != filled) return FluidStack.EMPTY
val filled2 = destination.fill(drained2, IFluidHandler.FluidAction.SIMULATE)
if (filled2 != drained2.amount) return FluidStack.EMPTY
if (!actuallyDrain && !actuallyFill) return FluidStack(drained2, filled2)
if (!actuallyDrain && !actuallyFill) return drained2.copyWithAmount(filled2)
val drained3: FluidStack
if (actuallyDrain) {
drained3 = source.drain(FluidStack(drained2, filled2), IFluidHandler.FluidAction.EXECUTE)
drained3 = source.drain(drained2.copyWithAmount(filled2), IFluidHandler.FluidAction.EXECUTE)
if (drained3.amount != filled2) {
LOGGER.warn("Inconsistency of fluid extraction from $source between simulate and execute modes (simulated $drained2; extracted $drained3); This can lead to duping!!!")
@ -362,7 +362,7 @@ private fun actuallyMoveFluid(drained: FluidStack, source: IFluidHandler, destin
filled3 = filled2
}
return FluidStack(drained3, filled3)
return drained3.copyWithAmount(filled3)
}
fun moveFluid(source: IFluidHandler, sourceTank: Int? = null, destination: IFluidHandler, limit: Int = Int.MAX_VALUE, actuallyDrain: Boolean = true, actuallyFill: Boolean = true): FluidStack {

View File

@ -0,0 +1,8 @@
package ru.dbotthepony.mc.otm.capability
interface IMatteryPlayer {
// since new capabilities dont get to live through getCapability calls by design
// and data attachments are.... limited.
// We gonna do it Fabric way
val otmPlayer: MatteryPlayer
}

View File

@ -10,12 +10,14 @@ import net.minecraft.client.model.PlayerModel
import net.minecraft.client.player.AbstractClientPlayer
import net.minecraft.commands.Commands
import net.minecraft.commands.arguments.EntityArgument
import net.minecraft.core.Direction
import net.minecraft.core.HolderLookup
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.IntTag
import net.minecraft.nbt.ListTag
import net.minecraft.nbt.StringTag
import net.minecraft.network.chat.Component
import net.minecraft.network.protocol.common.custom.CustomPacketPayload
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerLevel
import net.minecraft.server.level.ServerPlayer
@ -26,40 +28,31 @@ import net.minecraft.world.damagesource.DamageSource
import net.minecraft.world.effect.MobEffect
import net.minecraft.world.effect.MobEffectInstance
import net.minecraft.world.effect.MobEffects
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.boss.wither.WitherBoss
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import net.minecraft.world.item.ProjectileWeaponItem
import net.minecraft.world.item.crafting.RecipeManager
import net.minecraft.world.item.crafting.RecipeType
import net.minecraft.world.item.crafting.SingleRecipeInput
import net.minecraft.world.level.GameRules
import net.minecraft.world.level.Level
import net.minecraft.world.phys.Vec3
import net.minecraftforge.common.ForgeHooks
import net.minecraftforge.common.MinecraftForge
import net.minecraftforge.common.capabilities.Capability
import net.minecraftforge.common.capabilities.ICapabilityProvider
import net.minecraftforge.common.util.INBTSerializable
import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.event.AttachCapabilitiesEvent
import net.minecraftforge.event.RegisterCommandsEvent
import net.minecraftforge.event.TickEvent
import net.minecraftforge.event.TickEvent.PlayerTickEvent
import net.minecraftforge.event.entity.living.LivingAttackEvent
import net.minecraftforge.event.entity.living.LivingDeathEvent
import net.minecraftforge.event.entity.living.LivingHurtEvent
import net.minecraftforge.event.entity.living.MobEffectEvent
import net.minecraftforge.event.entity.player.PlayerEvent
import net.minecraftforge.eventbus.api.Cancelable
import net.minecraftforge.eventbus.api.Event
import net.minecraftforge.network.PacketDistributor
import net.minecraftforge.registries.ForgeRegistries
import net.minecraftforge.server.command.EnumArgument
import net.neoforged.bus.api.Event
import net.neoforged.bus.api.ICancellableEvent
import net.neoforged.neoforge.common.CommonHooks
import net.neoforged.neoforge.common.NeoForge
import net.neoforged.neoforge.event.RegisterCommandsEvent
import net.neoforged.neoforge.event.entity.living.LivingDeathEvent
import net.neoforged.neoforge.event.entity.living.LivingIncomingDamageEvent
import net.neoforged.neoforge.event.entity.living.MobEffectEvent
import net.neoforged.neoforge.event.entity.player.PlayerEvent
import net.neoforged.neoforge.event.tick.PlayerTickEvent
import net.neoforged.neoforge.network.PacketDistributor
import net.neoforged.neoforge.server.command.EnumArgument
import org.apache.logging.log4j.LogManager
import org.joml.Vector4f
import ru.dbotthepony.kommons.collect.ListenableMap
@ -93,18 +86,18 @@ import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.config.AndroidConfig
import ru.dbotthepony.mc.otm.config.ExopackConfig
import ru.dbotthepony.mc.otm.container.CombinedContainer
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.container.get
import ru.dbotthepony.mc.otm.container.DynamicallyProxiedContainer
import ru.dbotthepony.mc.otm.container.IContainer
import ru.dbotthepony.mc.otm.container.IMatteryContainer
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.container.get
import ru.dbotthepony.mc.otm.container.util.slotIterator
import ru.dbotthepony.mc.otm.container.vanishCursedItems
import ru.dbotthepony.mc.otm.core.*
import ru.dbotthepony.mc.otm.core.collect.UUIDIntModifiersMap
import ru.dbotthepony.mc.otm.core.collect.filter
import ru.dbotthepony.mc.otm.core.math.RGBColorDFUCodec
import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.math.RGBColorDFUCodec
import ru.dbotthepony.mc.otm.core.math.minus
import ru.dbotthepony.mc.otm.core.nbt.getCompoundList
import ru.dbotthepony.mc.otm.core.nbt.getIntList
@ -147,45 +140,32 @@ private fun Player.dropContainer(container: Container, spill: Boolean = true, se
}
@Suppress("unused")
class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerializable<CompoundTag> {
class MatteryPlayer(val ply: Player) {
/**
* This event is fired on main event bus before ticking logic takes place.
*
* Cancelling it is probably not a good idea, but you can do it anyway.
*/
@Cancelable
data class PreTick(val capability: MatteryPlayerCapability) : Event() {
data class PreTick(val capability: MatteryPlayer) : Event(), ICancellableEvent {
val player get() = capability.ply
val level: Level get() = capability.ply.level()
override fun isCancelable(): Boolean {
return true
}
}
/**
* This event is fired on main event bus after ticking logic took place.
*/
data class PostTick(val capability: MatteryPlayerCapability) : Event() {
data class PostTick(val capability: MatteryPlayer) : Event() {
val player get() = capability.ply
val level: Level get() = capability.ply.level()
override fun isCancelable(): Boolean {
return false
}
}
/**
* This event is fired on main event bus when [Inventory.add] was called and entire [ItemStack] can not be stored
* (both in [Inventory] and [MatteryPlayerCapability] exopack due to inventory filters or no free space).
* (both in [Inventory] and [MatteryPlayer] exopack due to inventory filters or no free space).
*/
data class ItemStackLeftoverEvent(val stack: ItemStack, val capability: MatteryPlayerCapability) : Event() {
data class ItemStackLeftoverEvent(val stack: ItemStack, val capability: MatteryPlayer) : Event() {
val player get() = capability.ply
val level: Level get() = capability.ply.level()
override fun isCancelable(): Boolean {
return false
}
}
private inner class PlayerMatteryContainer(size: Int) : MatteryContainer(size) {
@ -327,7 +307,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
field[i] = ItemStack.EMPTY
}
value.deserializeNBT(field.serializeNBT())
value.deserializeNBT(ply.level().registryAccess(), field.serializeNBT(ply.level().registryAccess()))
value.addFilterSynchronizer(syncher)
field = value
@ -449,7 +429,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
private val deathLog = ArrayDeque<Pair<Int, Component>>()
private val featureMap = IdentityHashMap<AndroidFeatureType<*>, AndroidFeature>()
private val networkQueue = ArrayList<Any>()
private val networkQueue = ArrayList<CustomPacketPayload>()
private val queuedTicks = ArrayList<Runnable>()
private var tickedOnce = false
@ -474,7 +454,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
private var lastLiquidPosition = Vec3(0.0, 0.0, 0.0)
private var liquidDistanceTravelled = 0.0
private var wasInLiquid = false
private var lastDimension = ResourceLocation("overworld")
private var lastDimension = ResourceLocation("minecraft", "overworld")
// clientside only flag for render hook
// TODO: actual code, currently particles spawn just behind player on ExopackSmokePacket
@ -539,13 +519,13 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
override fun computeNextJob(): JobContainer<ItemJob> {
if (!exopackEnergy.batteryLevel.isPositive) return JobContainer.noEnergy()
val level = ply.level() as? ServerLevel ?: return JobContainer.failure()
val recipe = cache.getRecipeFor(input, level)
val recipe = cache.getRecipeFor(SingleRecipeInput(input[0]), level)
if (recipe.isEmpty) {
return JobContainer.noItem()
} else {
val actual = recipe.get()
val item = actual.value.assemble(input, level.registryAccess())
val item = actual.value.assemble(SingleRecipeInput(input[0]), level.registryAccess())
input[0].shrink(1)
input.setChanged(0)
return JobContainer.success(ItemJob(item, actual.value.cookingTime.toDouble(), ExopackConfig.FURNACE_POWER_CONSUMPTION, actual.value.experience))
@ -556,7 +536,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
super.onJobTick(status)
if (isExopackVisible && ply.level().random.nextFloat() <= 0.05f) {
MatteryPlayerNetworkChannel.send(PacketDistributor.TRACKING_ENTITY_AND_SELF.with(ply as ServerPlayer), ExopackSmokePacket(ply.uuid))
PacketDistributor.sendToPlayersTrackingEntityAndSelf(ply, ExopackSmokePacket(ply.uuid))
}
}
@ -912,7 +892,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
return featureMap[feature] as T?
}
private fun onHurt(event: LivingHurtEvent) {
private fun onHurt(event: LivingIncomingDamageEvent) {
if (isAndroid) {
for (feature in featureMap.values) {
feature.onHurt(event)
@ -924,14 +904,6 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
}
}
private fun onAttack(event: LivingAttackEvent) {
if (isAndroid) {
for (feature in featureMap.values) {
feature.onAttack(event)
}
}
}
internal fun <T : AndroidFeature> computeIfAbsent(feature: AndroidFeatureType<T>): T {
return getFeature(feature) ?: addFeature(feature)
}
@ -947,22 +919,22 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
}
}
override fun serializeNBT(): CompoundTag {
val tag = savetables.serializeNBT()
fun serializeNBT(registry: HolderLookup.Provider): CompoundTag {
val tag = savetables.serializeNBT(registry)
// iteration
tag["deathLog"] = ListTag().also {
for ((ticks, component) in deathLog) {
it.add(CompoundTag().also {
it["ticks"] = ticks
it["component"] = StringTag.valueOf(Component.Serializer.toJson(component))
it["component"] = StringTag.valueOf(Component.Serializer.toJson(component, registry))
})
}
}
tag["features"] = ListTag().also {
for (feature in featureMap.values) {
it.add(feature.serializeNBT().also {
it.add(feature.serializeNBT(registry).also {
it["id"] = feature.type.registryName!!.toString()
})
}
@ -991,8 +963,8 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
return tag
}
override fun deserializeNBT(tag: CompoundTag) {
savetables.deserializeNBT(tag)
fun deserializeNBT(tag: CompoundTag, registry: HolderLookup.Provider) {
savetables.deserializeNBT(registry, tag)
if (MItems.ExopackUpgrades.INVENTORY_UPGRADE_ENDER_DRAGON.uuid(ItemStack.EMPTY) in exopackSlotModifierMap.delegate) {
isExopackEnderAccessInstalled = true
@ -1014,7 +986,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
for (i in 0 until regularSlotFilters.size.coerceAtMost(this.regularSlotFilters.size)) {
val path = regularSlotFilters[i].asString
if (path == "") continue
this.regularSlotFilters[i].value = ForgeRegistries.ITEMS.getValue(ResourceLocation.tryParse(path) ?: continue) ?: Items.AIR
this.regularSlotFilters[i].value = BuiltInRegistries.ITEM.get(ResourceLocation.tryParse(path) ?: continue)
}
if ("slotsChargeFlag" in tag) {
@ -1029,7 +1001,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
deathLog.clear()
for (value in tag.getCompoundList("deathLog")) {
val component = Component.Serializer.fromJson(value.getString("component"))
val component = Component.Serializer.fromJson(value.getString("component"), registry)
if (component != null) {
deathLog.add(value.getInt("ticks") to component)
@ -1040,12 +1012,12 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
research.clear()
for (featureTag in tag.getCompoundList("features")) {
val feature = MRegistry.ANDROID_FEATURES.getValue(ResourceLocation(featureTag.getString("id")))
val feature = MRegistry.ANDROID_FEATURES.get(ResourceLocation.parse(featureTag.getString("id")))
if (feature?.isApplicable(this) == true) {
val instance = feature.create(this)
instance.deserializeNBT(featureTag)
instance.deserializeNBT(registry, featureTag)
addFeature(instance)
if (!ply.level().isClientSide) {
@ -1055,7 +1027,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
}
for (researchTag in tag.getCompoundList("research")) {
val research = AndroidResearchManager[ResourceLocation(researchTag.getString("id"))]
val research = AndroidResearchManager[ResourceLocation.parse(researchTag.getString("id"))]
if (research != null) {
val instance = AndroidResearch(research, this)
@ -1088,10 +1060,10 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
androidEnergy.item = ItemStack.EMPTY
}
private fun sendNetwork(packet: Any) {
private fun sendNetwork(packet: CustomPacketPayload) {
if (ply is ServerPlayer) {
if (tickedOnce) {
MatteryPlayerNetworkChannel.send(ply, packet)
PacketDistributor.sendToPlayer(ply, packet)
} else {
networkQueue.add(packet)
}
@ -1128,7 +1100,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
if (!ply.isAlive) return
if (isAndroid) {
ForgeRegistries.MOB_EFFECTS.tags()?.getTag(ANDROID_IMMUNE_EFFECTS)?.forEach {
BuiltInRegistries.MOB_EFFECT.getOrCreateTag(ANDROID_IMMUNE_EFFECTS).forEach {
if (ply.hasEffect(it))
ply.removeEffect(it)
}
@ -1138,10 +1110,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
private fun tick() {
if (!ply.isAlive) return
PreTick(this).also {
MinecraftForge.EVENT_BUS.post(it)
if (it.isCanceled) return
}
if (NeoForge.EVENT_BUS.post(PreTick(this)).isCanceled) return
ticksIExist++
@ -1335,7 +1304,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
val payload = privateSyncherRemote.write()
if (payload != null) {
MatteryPlayerNetworkChannel.send(ply, MatteryPlayerFieldPacket(payload, false))
PacketDistributor.sendToPlayer(ply as ServerPlayer, MatteryPlayerDataPacket(payload, false))
}
val trackingIterator = remoteSynchers.entries.iterator()
@ -1349,19 +1318,19 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
val payload2 = remote.write()
if (payload2 != null) {
MatteryPlayerNetworkChannel.send(ply, MatteryPlayerFieldPacket(payload2, true, this.ply.uuid))
PacketDistributor.sendToPlayer(ply as ServerPlayer, MatteryPlayerDataPacket(payload2, true, this.ply.uuid))
}
}
val payload3 = publicSyncherRemote.write()
if (payload3 != null) {
MatteryPlayerNetworkChannel.send(ply, MatteryPlayerFieldPacket(payload3, true))
PacketDistributor.sendToPlayer(ply as ServerPlayer, MatteryPlayerDataPacket(payload3, true))
}
if (networkQueue.size != 0) {
for (packet in networkQueue) {
MatteryPlayerNetworkChannel.send(ply, packet)
PacketDistributor.sendToPlayer(ply as ServerPlayer, packet)
}
networkQueue.clear()
@ -1395,18 +1364,10 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
tickInventory()
PostTick(this).also {
MinecraftForge.EVENT_BUS.post(it)
NeoForge.EVENT_BUS.post(it)
}
}
private val resolver = LazyOptional.of { this }
override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
return if (cap == MatteryCapability.MATTERY_PLAYER) {
resolver.cast()
} else LazyOptional.empty()
}
/**
* This re-implement [Inventory.add] logic (original method is redirected to this)
*/
@ -1421,7 +1382,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
wrappedItemInventory.consumeItem(stack, false, onlyIntoExisting = false, popTime = 5)
}
MinecraftForge.EVENT_BUS.post(ItemStackLeftoverEvent(stack, this))
NeoForge.EVENT_BUS.post(ItemStackLeftoverEvent(stack, this))
if (ply.abilities.instabuild) {
stack.count = 0
@ -1445,10 +1406,10 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
}
}
enum class UpgradeType(val prop: KMutableProperty1<MatteryPlayerCapability, Boolean>) {
CRAFTING(MatteryPlayerCapability::isExopackCraftingUpgraded),
ENDER_ACCESS(MatteryPlayerCapability::isExopackEnderAccessInstalled),
SMELTING(MatteryPlayerCapability::isExopackSmeltingInstalled);
enum class UpgradeType(val prop: KMutableProperty1<MatteryPlayer, Boolean>) {
CRAFTING(MatteryPlayer::isExopackCraftingUpgraded),
ENDER_ACCESS(MatteryPlayer::isExopackEnderAccessInstalled),
SMELTING(MatteryPlayer::isExopackSmeltingInstalled);
}
@Suppress("unused")
@ -1457,8 +1418,8 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
private fun setExoPack(players: Collection<Player>, hasExoPack: Boolean): Int {
for (player in players) {
player.matteryPlayer?.hasExopack = hasExoPack
player.matteryPlayer?._exoPackMenu = null
player.matteryPlayer.hasExopack = hasExoPack
player.matteryPlayer._exoPackMenu = null
}
return players.size
@ -1466,7 +1427,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
private fun makeAndroid(players: Collection<Player>): Int {
for (player in players) {
player.matteryPlayer?.becomeAndroid()
player.matteryPlayer.becomeAndroid()
}
return players.size
@ -1474,7 +1435,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
private fun makeHuman(players: Collection<Player>): Int {
for (player in players) {
player.matteryPlayer?.becomeHumane()
player.matteryPlayer.becomeHumane()
}
return players.size
@ -1482,7 +1443,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
private fun setUpgrade(players: Collection<Player>, type: UpgradeType, state: Boolean): Int {
for (player in players) {
player.matteryPlayer?.let { type.prop.set(it, state) }
player.matteryPlayer.let { type.prop.set(it, state) }
}
return players.size
@ -1530,104 +1491,73 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
WitherBoss.LIVING_ENTITY_SELECTOR = WitherBoss.LIVING_ENTITY_SELECTOR.and { it.matteryPlayer?.isAndroid != true }
}
val ANDROID_IMMUNE_EFFECTS: TagKey<MobEffect> = TagKey.create(ForgeRegistries.MOB_EFFECTS.registryKey, ResourceLocation(OverdriveThatMatters.MOD_ID, "android_immune_effects"))
val ANDROID_IMMUNE_EFFECTS: TagKey<MobEffect> = TagKey.create(BuiltInRegistries.MOB_EFFECT.key(), ResourceLocation(OverdriveThatMatters.MOD_ID, "android_immune_effects"))
fun onPlayerTick(event: PlayerTickEvent) {
val ent = event.player
fun onPlayerTickPre(event: PlayerTickEvent.Pre) {
val ent = event.entity
if (event.phase == TickEvent.Phase.START) {
if (!ent.level().isClientSide) {
ent.getCapability(MatteryCapability.MATTERY_PLAYER).ifPresentK {
it.preTick()
ent.matteryPlayer.preTick()
}
}
} else {
fun onPlayerTickPost(event: PlayerTickEvent.Pre) {
val ent = event.entity
if (ent.level().isClientSide) {
ent.getCapability(MatteryCapability.MATTERY_PLAYER).ifPresentK {
it.tickClient()
}
ent.matteryPlayer.tickClient()
} else {
ent.getCapability(MatteryCapability.MATTERY_PLAYER).ifPresentK {
it.tick()
}
}
ent.matteryPlayer.tick()
}
}
fun isMobEffectApplicable(event: MobEffectEvent.Applicable) {
event.entity.getCapability(MatteryCapability.MATTERY_PLAYER).ifPresentK {
if (it.isAndroid && ForgeRegistries.MOB_EFFECTS.tags()?.getTag(ANDROID_IMMUNE_EFFECTS)?.stream()?.anyMatch { it == event.effectInstance.effect } == true) {
event.result = Event.Result.DENY
event.entity.matteryPlayer?.let {
if (it.isAndroid && BuiltInRegistries.MOB_EFFECT.getOrCreateTag(ANDROID_IMMUNE_EFFECTS).any { it == event.effectInstance?.effect }) {
event.result = MobEffectEvent.Applicable.Result.DO_NOT_APPLY
}
}
}
fun onHurtEvent(event: LivingHurtEvent) {
event.entity.getCapability(MatteryCapability.MATTERY_PLAYER).ifPresentK { it.onHurt(event) }
}
fun onAttackEvent(event: LivingAttackEvent) {
event.entity.getCapability(MatteryCapability.MATTERY_PLAYER).ifPresentK { it.onAttack(event) }
}
val CAPABILITY_LOCATION = ResourceLocation(OverdriveThatMatters.MOD_ID, "player")
fun onAttachCapabilityEvent(event: AttachCapabilitiesEvent<Entity>) {
val ent = event.`object`
if (ent is Player) {
event.addCapability(CAPABILITY_LOCATION, MatteryPlayerCapability(ent))
}
fun onHurtEvent(event: LivingIncomingDamageEvent) {
event.entity.matteryPlayer?.onHurt(event)
}
fun onPlayerChangeDimensionEvent(event: PlayerEvent.PlayerChangedDimensionEvent) {
onceServer {
event.entity.getCapability(MatteryCapability.MATTERY_PLAYER).ifPresentK {
it.invalidateNetworkState()
it.recreateExoPackMenu()
}
event.entity.matteryPlayer.invalidateNetworkState()
event.entity.matteryPlayer.recreateExoPackMenu()
}
}
fun onPlayerDeath(event: LivingDeathEvent) {
val ply = event.entity as? Player ?: return
val mattery = ply.matteryPlayer ?: return
if (mattery.lastDeathTick != ply.tickCount) {
mattery.lastDeathTick = ply.tickCount
if (ply.matteryPlayer.lastDeathTick != ply.tickCount) {
ply.matteryPlayer.lastDeathTick = ply.tickCount
} else {
return
}
if (!mattery.isAndroid) {
if (!ply.matteryPlayer.isAndroid) {
return
}
mattery.iteration++
mattery.shouldSendIteration = true
mattery.deathLog.addLast(ply.tickCount to ply.combatTracker.deathMessage)
ply.matteryPlayer.iteration++
ply.matteryPlayer.shouldSendIteration = true
ply.matteryPlayer.deathLog.addLast(ply.tickCount to ply.combatTracker.deathMessage)
if (mattery.androidEnergy.batteryLevel < AndroidConfig.ANDROID_MAX_ENERGY * Decimal("0.2"))
mattery.androidEnergy.batteryLevel = AndroidConfig.ANDROID_MAX_ENERGY * Decimal("0.2") // если смерть была от разряда батареи, то предотвращаем софтлок
if (ply.matteryPlayer.androidEnergy.batteryLevel < AndroidConfig.ANDROID_MAX_ENERGY * Decimal("0.2"))
ply.matteryPlayer.androidEnergy.batteryLevel = AndroidConfig.ANDROID_MAX_ENERGY * Decimal("0.2") // если смерть была от разряда батареи, то предотвращаем софтлок
while (mattery.deathLog.size > 6) {
mattery.deathLog.removeFirst()
while (ply.matteryPlayer.deathLog.size > 6) {
ply.matteryPlayer.deathLog.removeFirst()
}
}
fun onPlayerCloneEvent(event: PlayerEvent.Clone) {
val it = event.entity.matteryPlayer ?: return
var original = event.original.matteryPlayer
if (original == null) {
event.original.reviveCaps()
original = event.original.matteryPlayer
}
if (original == null) {
event.original.invalidateCaps()
return
}
val it = event.entity.matteryPlayer
val original = event.original.matteryPlayer
if (original.willBecomeAndroid && event.isWasDeath) {
original.becomeAndroid()
@ -1640,15 +1570,12 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
}
}
it.deserializeNBT(original.serializeNBT())
it.deserializeNBT(original.serializeNBT(it.ply.registryAccess()), it.ply.registryAccess())
it.invalidateNetworkState()
event.original.invalidateCaps()
onceServer {
event.entity.getCapability(MatteryCapability.MATTERY_PLAYER).ifPresentK {
it.invalidateNetworkState()
it.recreateExoPackMenu()
}
event.entity.matteryPlayer.invalidateNetworkState()
event.entity.matteryPlayer.recreateExoPackMenu()
}
}
@ -1661,7 +1588,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
*/
@JvmStatic
fun phantomSpawnHook(iterator: Iterator<Player>): Iterator<Player> {
return iterator.filter { it.matteryPlayer?.isAndroid != true }
return iterator.filter { it.matteryPlayer.isAndroid != true }
}
/**
@ -1673,9 +1600,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
return iterator
}
val mattery = entity.matteryPlayer ?: return iterator
if (mattery.isAndroid) {
if (entity.matteryPlayer.isAndroid) {
return iterator.filter {
it.first.effect != MobEffects.HUNGER
}
@ -1686,7 +1611,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
@JvmStatic
fun inventoryDropAll(inventory: Inventory) {
val mattery = inventory.player.matteryPlayer ?: return
val mattery = inventory.player.matteryPlayer
if (!mattery.hasExopack) {
return
@ -1724,19 +1649,17 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
@JvmStatic
fun playerDestroyVanishingCursedItems(player: Player) {
player.matteryPlayer?.let {
if (it.hasExopack) {
it.exopackContainer.vanishCursedItems()
it.exopackChargeSlots.vanishCursedItems()
if (player.matteryPlayer.hasExopack) {
player.matteryPlayer.exopackContainer.vanishCursedItems()
player.matteryPlayer.exopackChargeSlots.vanishCursedItems()
// it.exoPackEnergy.parent.vanishCursedItems()
for (smelter in it.smelters) {
for (smelter in player.matteryPlayer.smelters) {
smelter.input.vanishCursedItems()
smelter.output.vanishCursedItems()
}
}
}
}
@JvmStatic
fun pickBlockHook(determinedSlot: Int, itemStack: ItemStack) {
@ -1746,25 +1669,25 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
return
}
val matteryPlayer = player.matteryPlayer ?: return
val matteryPlayer = player.matteryPlayer
if (!matteryPlayer.hasExopack) {
return
}
val targetSlot = player.inventory.suitableHotbarSlot
val itemSlot = matteryPlayer.exopackContainer.indexOfFirst { !it.isEmpty && ItemStack.isSameItemSameTags(itemStack, it) }
val itemSlot = matteryPlayer.exopackContainer.indexOfFirst { !it.isEmpty && ItemStack.isSameItemSameComponents(itemStack, it) }
if (itemSlot == -1) {
return
}
MatteryPlayerNetworkChannel.sendToServer(PickItemFromInventoryPacket(targetSlot, itemSlot))
PacketDistributor.sendToServer(PickItemFromInventoryPacket(targetSlot, itemSlot))
}
fun onStartTracking(event: PlayerEvent.StartTracking) {
if (event.target is ServerPlayer) {
event.target.matteryPlayer?.let {
(event.target as ServerPlayer).matteryPlayer.let {
it.remoteSynchers[event.entity as ServerPlayer] = it.publicSyncher.Remote()
}
}
@ -1772,21 +1695,21 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
fun onStopTracking(event: PlayerEvent.StopTracking) {
if (event.target is ServerPlayer) {
event.target.matteryPlayer?.remoteSynchers?.remove(event.entity as ServerPlayer)
(event.target as ServerPlayer).matteryPlayer.remoteSynchers.remove(event.entity as ServerPlayer)
}
}
@JvmStatic
fun getProjectileHook(player: Player, weaponItem: ItemStack): ItemStack? {
val weapon = weaponItem.item as? ProjectileWeaponItem ?: return null
val matteryPlayer = player.matteryPlayer ?: return null
val matteryPlayer = player.matteryPlayer
if (!matteryPlayer.hasExopack) {
return null
}
val item = matteryPlayer.exopackContainer.stream().filter(weapon.allSupportedProjectiles).findFirst().orElse(null) ?: return null
return ForgeHooks.getProjectile(player, weaponItem, item)
return CommonHooks.getProjectile(player, weaponItem, item)
}
}
}

View File

@ -1,5 +1,6 @@
package ru.dbotthepony.mc.otm.capability.drive
import net.minecraft.core.HolderLookup
import net.minecraft.nbt.CompoundTag
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
@ -33,6 +34,6 @@ interface IMatteryDrive<T : StorageStack<T>> : IStorageComponent<T> {
val driveCapacity: BigInteger
// not extending INBTSerializable to avoid serializing it as forgecaps
fun serializeNBT(): CompoundTag
fun deserializeNBT(nbt: CompoundTag)
fun serializeNBT(registry: HolderLookup.Provider): CompoundTag
fun deserializeNBT(nbt: CompoundTag, registry: HolderLookup.Provider)
}

View File

@ -4,6 +4,8 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
import it.unimi.dsi.fastutil.objects.ObjectArraySet
import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet
import net.minecraft.core.HolderLookup
import net.minecraft.core.HolderLookup.Provider
import kotlin.jvm.JvmOverloads
import java.util.UUID
import net.minecraft.nbt.CompoundTag
@ -147,10 +149,10 @@ abstract class AbstractMatteryDrive<T : StorageStack<T>>(
return copy
}
protected abstract fun serializeStack(item: T): CompoundTag?
protected abstract fun deserializeStack(tag: CompoundTag): T?
protected abstract fun serializeStack(item: T, registry: Provider): CompoundTag?
protected abstract fun deserializeStack(tag: CompoundTag, registry: Provider): T?
override fun serializeNBT(): CompoundTag {
override fun serializeNBT(registry: Provider): CompoundTag {
val compound = CompoundTag()
compound["capacity"] = driveCapacity.serializeNBT()
@ -160,7 +162,7 @@ abstract class AbstractMatteryDrive<T : StorageStack<T>>(
compound["items"] = list
for (tuple in stack2tuples.values) {
val serialized = serializeStack(tuple.stack)
val serialized = serializeStack(tuple.stack, registry)
if (serialized != null) {
list.add(serialized)
@ -170,7 +172,7 @@ abstract class AbstractMatteryDrive<T : StorageStack<T>>(
return compound
}
override fun deserializeNBT(nbt: CompoundTag) {
override fun deserializeNBT(nbt: CompoundTag, registry: HolderLookup.Provider) {
for (listener in listeners) {
for (get in stack2tuples.values) {
listener.onStackRemoved(get.id)
@ -183,12 +185,12 @@ abstract class AbstractMatteryDrive<T : StorageStack<T>>(
storedDifferentStacks = 0
// nextID = 0L
driveCapacity = nbt.map("capacity", ::BigInteger) ?: driveCapacity
driveCapacity = nbt.get("capacity")?.let { BigInteger(it) } ?: driveCapacity
maxDifferentStacks = nbt.getInt("max_different_stacks")
for (entry in nbt.getList("items", Tag.TAG_COMPOUND.toInt())) {
if (entry is CompoundTag) {
val stack = deserializeStack(entry)
val stack = deserializeStack(entry, registry)
if (stack != null && stack.isNotEmpty) {
storedCount += stack.count

Some files were not shown because too many files have changed in this diff Show More