Add ability for minecarts to specify their detector rail comparator value (#1321)

* Add ability for minecarts to specify their detector rail comparator value

Address comments

* Apply suggestions from code review

Co-authored-by: Juuxel <6596629+Juuxel@users.noreply.github.com>

* Warn instead of debug

Co-authored-by: Juuxel <6596629+Juuxel@users.noreply.github.com>
This commit is contained in:
Vincent Lee 2021-12-03 07:34:17 -06:00 committed by modmuss50
parent 3fec4ad922
commit 3b82842e3d
4 changed files with 160 additions and 0 deletions

View file

@ -0,0 +1,39 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.api.object.builder.v1.entity;
import net.minecraft.block.BlockState;
import net.minecraft.entity.vehicle.AbstractMinecartEntity;
import net.minecraft.util.math.BlockPos;
/**
* Provides custom comparator output for minecarts resting on detector rails.
* @param <T> the handled minecart type
*/
@FunctionalInterface
public interface MinecartComparatorLogic<T extends AbstractMinecartEntity> {
/**
* Compute the comparator output of a detector rail when a minecart is resting
* on top of it. Called from {@link net.minecraft.block.DetectorRailBlock#getComparatorOutput}.
* @param minecart The minecart on the rail
* @param state Block state of the rail
* @param pos Position of the rail
* @return A redstone power value {@literal >=} 0 to use, else a value {@literal <} 0 to try the next minecart with
* a registered logic. If no logic chooses to provide a value, vanilla's logic is invoked.
*/
int getComparatorValue(T minecart, BlockState state, BlockPos pos);
}

View file

@ -0,0 +1,63 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.api.object.builder.v1.entity;
import java.util.HashMap;
import java.util.Map;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.Nullable;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.vehicle.AbstractMinecartEntity;
import net.minecraft.util.registry.Registry;
/**
* A registry for {@linkplain MinecartComparatorLogic custom minecart compator logic}.
*/
public final class MinecartComparatorLogicRegistry {
private static final Logger LOGGER = LogManager.getLogger();
private static final Map<EntityType<?>, MinecartComparatorLogic<?>> logics = new HashMap<>();
/**
* Gets the registered custom comparator logic for the specified minecart entity type.
*
* @param type the entity type
* @return the comparator logic, or {@code null} if not registered
*/
@Nullable
@SuppressWarnings("unchecked")
public static MinecartComparatorLogic<AbstractMinecartEntity> getCustomComparatorLogic(EntityType<?> type) {
return (MinecartComparatorLogic<AbstractMinecartEntity>) logics.get(type);
}
/**
* Registers a comparator logic for a minecart entity type.
*
* <p>Registering a second value for an entity type will replace the old logic.
*
* @param <T> the handled minecart type
* @param type the minecart entity type
* @param logic the logic to register
*/
public static <T extends AbstractMinecartEntity> void register(EntityType<T> type, MinecartComparatorLogic<? super T> logic) {
if (logics.put(type, logic) != null) {
LOGGER.warn("Overriding existing minecart comparator logic for entity type {}", Registry.ENTITY_TYPE.getId(type));
}
}
}

View file

@ -0,0 +1,57 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.mixin.object.builder;
import java.util.List;
import java.util.function.Predicate;
import org.jetbrains.annotations.Nullable;
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.CallbackInfoReturnable;
import net.minecraft.block.BlockState;
import net.minecraft.block.DetectorRailBlock;
import net.minecraft.entity.Entity;
import net.minecraft.entity.vehicle.AbstractMinecartEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.fabricmc.fabric.api.object.builder.v1.entity.MinecartComparatorLogicRegistry;
@Mixin(DetectorRailBlock.class)
public abstract class DetectorRailBlockMixin {
@Shadow protected abstract <T extends AbstractMinecartEntity> List<T> getCarts(World world, BlockPos pos, Class<T> entityClass, @Nullable Predicate<Entity> entityPredicate);
@Inject(at = @At("HEAD"), method = "getComparatorOutput", cancellable = true)
private void getCustomComparatorOutput(BlockState state, World world, BlockPos pos, CallbackInfoReturnable<Integer> cir) {
if (state.get(DetectorRailBlock.POWERED)) {
List<AbstractMinecartEntity> carts = getCarts(world, pos, AbstractMinecartEntity.class,
cart -> MinecartComparatorLogicRegistry.getCustomComparatorLogic(cart.getType()) != null);
for (AbstractMinecartEntity cart : carts) {
int comparatorValue = MinecartComparatorLogicRegistry.getCustomComparatorLogic(cart.getType())
.getComparatorValue(cart, state, pos);
if (comparatorValue >= 0) {
cir.setReturnValue(comparatorValue);
break;
}
}
}
}
}

View file

@ -9,6 +9,7 @@
"CriteriaAccessor",
"DefaultAttributeRegistryAccessor",
"DefaultAttributeRegistryMixin",
"DetectorRailBlockMixin",
"MaterialBuilderAccessor",
"MixinBlock",
"PointOfInterestTypeAccessor",