Jump to content

ProspectPyxis

Members
  • Posts

    33
  • Joined

  • Last visited

Posts posted by ProspectPyxis

  1. So, here's what I wanna do: I have an item that's supposed to be used with another block that would damage it (if you want specifics, it's supposed to be for Pyrotech's chopping block). I want it so that once the item runs out of durability, it'd transform into another item rather than breaking outright. I can't seem to figure out how I'd do this, though. Here are the things I've tried:

    • Edit the setDamage function. Problem is, there's no method to change the stack's item or get the holder of the itemstack that I've seen, so it wouldn't work.
    • Use onItemUseFinish. It...doesn't seem to fire at all with this.
    • Subscribe to PlayerDestroyItemEvent. This feels too unspecific, and the event might fire when I don't want it to.

    Is there some way of doing this properly?

  2. I want an item to do something when you left click it while pointing at the air. How would I do this? I tried subscribing to onEntitySwing, but that event seems to also fire even if you're pointing at a block or entity. I also tried checking if the player is looking at anything with Item.rayTrace, but the method always returns null somehow.
    One way I've seen is subscribing to a clientside event, but from my understanding that would require a packet, and I'd like to limit that if possible. Is there any other way, or is that the best way?

  3. I'm gonna have to look into all those methods, but one more thing you're missing: I only want to change the mode when shift-right clicking the item, not just when hovering while holding shift. Since a right click constitutes removing the item from the inventory temporarily, I assume this will be a bit more difficult?
    If it gets too impractical to implement, I can simply use a keybind while holding the item for this, but I wanna see what I can do first.

  4. Alright, so adding a lightmap value actually got rid of the weird stretching, but now I have a couple new problems, as you can see in the image here:

    Spoiler

    image.png.56e5a8b6e8260334a29c5ed9ad6026e7.png

    (Ignore the transparency issue, the block is supposed to be a full block either way)

    1. The texture is completely dark.
    2. The texture doesn't fully fill the outline of the blockstate texture - you can see the empty gaps in the image.

    How would I fix this? The new TESR code is here (I'm only testing for one face for now so I removed a massive chunk of the code):

    Spoiler
    
    package prospectpyxis.customcapacitors.client.render;
    
    import net.minecraft.block.state.IBlockState;
    import net.minecraft.client.renderer.BufferBuilder;
    import net.minecraft.client.renderer.texture.TextureAtlasSprite;
    import net.minecraftforge.client.model.animation.FastTESR;
    import org.lwjgl.util.vector.Vector3f;
    import prospectpyxis.customcapacitors.block.BlockCapacitor;
    import prospectpyxis.customcapacitors.block.tile.TileEntityCapacitor;
    import prospectpyxis.customcapacitors.proxy.ClientProxy;
    
    import java.awt.*;
    
    public class TESRCapacitor extends FastTESR<TileEntityCapacitor> {
    
        @Override
        public void renderTileEntityFast(TileEntityCapacitor tec, double x, double y, double z, float partialTicks, int destroyStage, float partial, BufferBuilder buffer) {
    
            IBlockState state = tec.getWorld().getBlockState(tec.getPos());
    
            Color cb = new Color(tec.data.getColorBase(), false);
            Color ct = new Color(tec.data.getColorTrim(), false);
    
            createNewLayer(tec, state, new Vector3f((float)x, (float)y, (float)z), ClientProxy.ctexBase, cb.getRed(), cb.getBlue(), cb.getGreen(), buffer);
        }
    
        public void createNewLayer(TileEntityCapacitor tec, IBlockState state, Vector3f offset, TextureAtlasSprite tas, int r, int g, int b, BufferBuilder buffer) {
    
            int blocklight = (state.getPackedLightmapCoords(tec.getWorld(), tec.getPos())) & 0xFFFF;
            int skylight = (state.getPackedLightmapCoords(tec.getWorld(), tec.getPos())) >> 16 & 0xFFFF;
    
            buffer.pos(offset.x + 0, offset.y + 0, offset.z + 0).color(r, g, b, 255).tex(tas.getMinU(), tas.getMaxV()).lightmap(skylight, blocklight).endVertex();
            buffer.pos(offset.x + 1, offset.y + 0, offset.z + 0).color(r, g, b, 255).tex(tas.getMaxU(), tas.getMaxV()).lightmap(skylight, blocklight).endVertex();
            buffer.pos(offset.x + 1, offset.y + 1, offset.z + 0).color(r, g, b, 255).tex(tas.getMaxU(), tas.getMinV()).lightmap(skylight, blocklight).endVertex();
            buffer.pos(offset.x + 0, offset.y + 1, offset.z + 0).color(r, g, b, 255).tex(tas.getMinU(), tas.getMinV()).lightmap(skylight, blocklight).endVertex();
        }
    }

     

     

  5. So from what I can understand from the code you sent, one square face of a block is equal to four vertices. I don't really know what I'm doing wrong, though, since I already translated the buffer in the first line of renderTileEntityFast - do I need to add an offset to the pos as well?
    Also, is a lightmap value absolutely required? It seems to be used in all the code you've sent me but I don't fully understand what it does.

  6. So this is a bit of a follow up to my previous topic - I'm currently trying to use a FastTESR to render a tile entity that stores its color. I can't really find any pointers on how to use it, though - trying to follow a code example I found just...made it break horribly, as you can see in the attached image.
    Here's the relevant code that I'm using, can anyone give some pointers on what I'm doing wrong?

    FastTESR class:

    Spoiler
    
    package prospectpyxis.customcapacitors.client.render;
    
    import net.minecraft.block.state.IBlockState;
    import net.minecraft.client.renderer.BufferBuilder;
    import net.minecraft.client.renderer.texture.TextureAtlasSprite;
    import net.minecraftforge.client.model.animation.FastTESR;
    import prospectpyxis.customcapacitors.block.BlockCapacitor;
    import prospectpyxis.customcapacitors.block.tile.TileEntityCapacitor;
    import prospectpyxis.customcapacitors.proxy.ClientProxy;
    
    import java.awt.*;
    
    public class TESRCapacitor extends FastTESR<TileEntityCapacitor> {
    
        @Override
        public void renderTileEntityFast(TileEntityCapacitor tec, double x, double y, double z, float partialTicks, int destroyStage, float partial, BufferBuilder buffer) {
            buffer.setTranslation(x, y, z);
    
            IBlockState state = tec.getWorld().getBlockState(tec.getPos());
    
            Color cb = new Color(tec.data.getColorBase(), false);
            Color ct = new Color(tec.data.getColorTrim(), false);
    
            createNewLayer(tec, ClientProxy.ctexBase, cb.getRed(), cb.getBlue(), cb.getGreen(), buffer);
            createNewLayer(tec, ClientProxy.ctexTrim, ct.getRed(), ct.getBlue(), ct.getGreen(), buffer);
    
            switch (state.getValue(BlockCapacitor.FACING)) {
                case DOWN:
                    buffer.pos(1, 0, 1).color(255, 255, 255, 255)
                            .tex(ClientProxy.ctexOverlayO.getMinU(), ClientProxy.ctexOverlayO.getMaxV()).endVertex();
                    buffer.pos(0, 0, 1).color(255, 255, 255, 255)
                            .tex(ClientProxy.ctexOverlayO.getMaxU(), ClientProxy.ctexOverlayO.getMaxV()).endVertex();
                    buffer.pos(0, 0, 0).color(255, 255, 255, 255)
                            .tex(ClientProxy.ctexOverlayO.getMaxU(), ClientProxy.ctexOverlayO.getMinV()).endVertex();
                    buffer.pos(1, 0, 0).color(255, 255, 255, 255)
                            .tex(ClientProxy.ctexOverlayO.getMinU(), ClientProxy.ctexOverlayO.getMinV()).endVertex();
                    break;
                case UP:
                    buffer.pos(1, 0, 1).color(255, 255, 255, 255)
                            .tex(ClientProxy.ctexOverlayO.getMinU(), ClientProxy.ctexOverlayO.getMaxV()).endVertex();
                    buffer.pos(0, 0, 1).color(255, 255, 255, 255)
                            .tex(ClientProxy.ctexOverlayO.getMaxU(), ClientProxy.ctexOverlayO.getMaxV()).endVertex();
                    buffer.pos(0, 0, 0).color(255, 255, 255, 255)
                            .tex(ClientProxy.ctexOverlayO.getMaxU(), ClientProxy.ctexOverlayO.getMinV()).endVertex();
                    buffer.pos(1, 0, 0).color(255, 255, 255, 255)
                            .tex(ClientProxy.ctexOverlayO.getMinU(), ClientProxy.ctexOverlayO.getMinV()).endVertex();
                    break;
                case NORTH:
                    buffer.pos(0, 1, 0).color(255, 255, 255, 255)
                            .tex(ClientProxy.ctexOverlayO.getMinU(), ClientProxy.ctexOverlayO.getMaxV()).endVertex();
                    buffer.pos(1, 1, 0).color(255, 255, 255, 255)
                            .tex(ClientProxy.ctexOverlayO.getMaxU(), ClientProxy.ctexOverlayO.getMaxV()).endVertex();
                    buffer.pos(1, 0, 0).color(255, 255, 255, 255)
                            .tex(ClientProxy.ctexOverlayO.getMaxU(), ClientProxy.ctexOverlayO.getMinV()).endVertex();
                    buffer.pos(0, 0, 0).color(255, 255, 255, 255)
                            .tex(ClientProxy.ctexOverlayO.getMinU(), ClientProxy.ctexOverlayO.getMinV()).endVertex();
                    break;
                case SOUTH:
                    buffer.pos(1, 1, 1).color(255, 255, 255, 255)
                            .tex(ClientProxy.ctexOverlayO.getMinU(), ClientProxy.ctexOverlayO.getMaxV()).endVertex();
                    buffer.pos(0, 1, 1).color(255, 255, 255, 255)
                            .tex(ClientProxy.ctexOverlayO.getMaxU(), ClientProxy.ctexOverlayO.getMaxV()).endVertex();
                    buffer.pos(0, 0, 1).color(255, 255, 255, 255)
                            .tex(ClientProxy.ctexOverlayO.getMaxU(), ClientProxy.ctexOverlayO.getMinV()).endVertex();
                    buffer.pos(1, 0, 1).color(255, 255, 255, 255)
                            .tex(ClientProxy.ctexOverlayO.getMinU(), ClientProxy.ctexOverlayO.getMinV()).endVertex();
                    break;
                case WEST:
                    buffer.pos(0, 1, 1).color(255, 255, 255, 255)
                            .tex(ClientProxy.ctexOverlayO.getMinU(), ClientProxy.ctexOverlayO.getMaxV()).endVertex();
                    buffer.pos(0, 1, 0).color(255, 255, 255, 255)
                            .tex(ClientProxy.ctexOverlayO.getMaxU(), ClientProxy.ctexOverlayO.getMaxV()).endVertex();
                    buffer.pos(0, 0, 0).color(255, 255, 255, 255)
                            .tex(ClientProxy.ctexOverlayO.getMaxU(), ClientProxy.ctexOverlayO.getMinV()).endVertex();
                    buffer.pos(0, 0, 1).color(255, 255, 255, 255)
                            .tex(ClientProxy.ctexOverlayO.getMinU(), ClientProxy.ctexOverlayO.getMinV()).endVertex();
                    break;
                case EAST:
                    buffer.pos(1, 1, 0).color(255, 255, 255, 255)
                            .tex(ClientProxy.ctexOverlayO.getMinU(), ClientProxy.ctexOverlayO.getMaxV()).endVertex();
                    buffer.pos(1, 1, 1).color(255, 255, 255, 255)
                            .tex(ClientProxy.ctexOverlayO.getMaxU(), ClientProxy.ctexOverlayO.getMaxV()).endVertex();
                    buffer.pos(1, 0, 1).color(255, 255, 255, 255)
                            .tex(ClientProxy.ctexOverlayO.getMaxU(), ClientProxy.ctexOverlayO.getMinV()).endVertex();
                    buffer.pos(1, 0, 0).color(255, 255, 255, 255)
                            .tex(ClientProxy.ctexOverlayO.getMinU(), ClientProxy.ctexOverlayO.getMinV()).endVertex();
                    break;
                default:
            }
    
        }
    
        public void createNewLayer(TileEntityCapacitor tec, TextureAtlasSprite tas, int r, int g, int b, BufferBuilder buffer) {
            // DOWN
            buffer.pos(1, 0, 1).color(r, g, b, 255).tex(tas.getMinU(), tas.getMaxV()).endVertex();
            buffer.pos(0, 0, 1).color(r, g, b, 255).tex(tas.getMaxU(), tas.getMaxV()).endVertex();
            buffer.pos(0, 0, 0).color(r, g, b, 255).tex(tas.getMaxU(), tas.getMinV()).endVertex();
            buffer.pos(1, 0, 0).color(r, g, b, 255).tex(tas.getMinU(), tas.getMinV()).endVertex();
    
            // UP
            buffer.pos(1, 1, 0).color(r, g, b, 255).tex(tas.getMinU(), tas.getMaxV()).endVertex();
            buffer.pos(0, 1, 0).color(r, g, b, 255).tex(tas.getMaxU(), tas.getMaxV()).endVertex();
            buffer.pos(0, 1, 1).color(r, g, b, 255).tex(tas.getMaxU(), tas.getMinV()).endVertex();
            buffer.pos(1, 1, 1).color(r, g, b, 255).tex(tas.getMinU(), tas.getMinV()).endVertex();
    
            // NORTH
            buffer.pos(0, 1, 0).color(r, g, b, 255).tex(tas.getMinU(), tas.getMaxV()).endVertex();
            buffer.pos(1, 1, 0).color(r, g, b, 255).tex(tas.getMaxU(), tas.getMaxV()).endVertex();
            buffer.pos(1, 0, 0).color(r, g, b, 255).tex(tas.getMaxU(), tas.getMinV()).endVertex();
            buffer.pos(0, 0, 0).color(r, g, b, 255).tex(tas.getMinU(), tas.getMinV()).endVertex();
    
            // SOUTH
            buffer.pos(1, 1, 1).color(r, g, b, 255).tex(tas.getMinU(), tas.getMaxV()).endVertex();
            buffer.pos(0, 1, 1).color(r, g, b, 255).tex(tas.getMaxU(), tas.getMaxV()).endVertex();
            buffer.pos(0, 0, 1).color(r, g, b, 255).tex(tas.getMaxU(), tas.getMinV()).endVertex();
            buffer.pos(1, 0, 1).color(r, g, b, 255).tex(tas.getMinU(), tas.getMinV()).endVertex();
    
            // WEST
            buffer.pos(0, 1, 1).color(r, g, b, 255).tex(tas.getMinU(), tas.getMaxV()).endVertex();
            buffer.pos(0, 1, 0).color(r, g, b, 255).tex(tas.getMaxU(), tas.getMaxV()).endVertex();
            buffer.pos(0, 0, 0).color(r, g, b, 255).tex(tas.getMaxU(), tas.getMinV()).endVertex();
            buffer.pos(0, 0, 1).color(r, g, b, 255).tex(tas.getMinU(), tas.getMinV()).endVertex();
    
            // EAST
            buffer.pos(1, 1, 0).color(r, g, b, 255).tex(tas.getMinU(), tas.getMaxV()).endVertex();
            buffer.pos(1, 1, 1).color(r, g, b, 255).tex(tas.getMaxU(), tas.getMaxV()).endVertex();
            buffer.pos(1, 0, 1).color(r, g, b, 255).tex(tas.getMaxU(), tas.getMinV()).endVertex();
            buffer.pos(1, 0, 0).color(r, g, b, 255).tex(tas.getMinU(), tas.getMinV()).endVertex();
        }
    }

     

    ClientProxy where the textures are registered:

    Spoiler
    
    package prospectpyxis.customcapacitors.proxy;
    
    import net.minecraft.client.Minecraft;
    import net.minecraft.client.renderer.block.model.ModelResourceLocation;
    import net.minecraft.client.renderer.texture.TextureAtlasSprite;
    import net.minecraft.item.Item;
    import net.minecraft.util.ResourceLocation;
    import net.minecraftforge.client.event.TextureStitchEvent;
    import net.minecraftforge.client.model.ModelLoader;
    import net.minecraftforge.fml.common.Mod;
    import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
    import prospectpyxis.customcapacitors.CustomCapacitors;
    
    @Mod.EventBusSubscriber
    public class ClientProxy extends CommonProxy {
    
        @Override
        public void registerItemRenderer(Item item, int meta, String id) {
            ModelLoader.setCustomModelResourceLocation(item, meta, new ModelResourceLocation(CustomCapacitors.modid + ":" + id, "inventory"));
        }
    
        public static TextureAtlasSprite ctexBase;
        public static TextureAtlasSprite ctexTrim;
        public static TextureAtlasSprite ctexOverlay;
        public static TextureAtlasSprite ctexOverlayO;
    
        @SubscribeEvent
        public static void registerTextureStitch(TextureStitchEvent.Pre event) {
            if (event.getMap() == Minecraft.getMinecraft().getTextureMapBlocks()) {
                ctexBase = event.getMap().registerSprite(new ResourceLocation(CustomCapacitors.modid + ":blocks/capacitor_base"));
                ctexTrim = event.getMap().registerSprite(new ResourceLocation(CustomCapacitors.modid + ":blocks/capacitor_trim"));
                ctexOverlay = event.getMap().registerSprite(new ResourceLocation(CustomCapacitors.modid + ":blocks/capacitor_overlay"));
                ctexOverlayO = event.getMap().registerSprite(new ResourceLocation(CustomCapacitors.modid + ":blocks/capacitor_overlay_output"));
            }
        }
    }

     

    TileEntity class:

    Spoiler
    
    package prospectpyxis.customcapacitors.block.tile;
    
    import com.google.common.collect.ImmutableMap;
    import net.minecraft.block.state.IBlockState;
    import net.minecraft.nbt.NBTTagCompound;
    import net.minecraft.tileentity.TileEntity;
    import net.minecraft.util.EnumFacing;
    import net.minecraft.util.ITickable;
    import net.minecraft.util.math.BlockPos;
    import net.minecraft.world.World;
    import net.minecraftforge.common.capabilities.Capability;
    import net.minecraftforge.energy.CapabilityEnergy;
    import prospectpyxis.customcapacitors.CustomCapacitors;
    import prospectpyxis.customcapacitors.block.BlockCapacitor;
    import prospectpyxis.customcapacitors.data.CapacitorData;
    import prospectpyxis.customcapacitors.registry.CapacitorRegistry;
    import prospectpyxis.pyxislib.energy.EnergyManager;
    
    import javax.annotation.Nullable;
    
    public class TileEntityCapacitor extends TileEntity implements ITickable {
    
        public CapacitorData data = new CapacitorData();
    
        public EnergyManager eContainer = new EnergyManager(0, 0);
        public EnergyManager eReceiver = new EnergyManager(0, 0);
        public EnergyManager eExtractor = new EnergyManager(0, 0);
        @Override
        public void update() {
            if (world.getTotalWorldTime() % data.storageLossData.lossDelay == 0) {
                int minThreshold = data.storageLossData.minThreshold == -1 ? 0 : data.storageLossData.minThreshold;
                int maxThreshold = data.storageLossData.maxThreshold == -1 ? eContainer.getMaxEnergyStored() + 1 : data.storageLossData.minThreshold;
                if (data.storageLossType != CapacitorData.EnumLossType.NONE && eContainer.getEnergyStored() >= minThreshold && eContainer.getEnergyStored() < maxThreshold) {
                    switch (data.storageLossType) {
                        case CONSTANT:
                            eContainer.extractEnergy((int) Math.floor(data.storageLossData.lossValue), false);
                            break;
                        case PERCENTAGE:
                            eContainer.extractEnergy(Math.round(eContainer.getEnergyStored() * data.storageLossData.lossValue), false);
                            break;
                        case PERCENTAGE_INVERTED:
                            eContainer.extractEnergy(Math.round
                                    ((eContainer.getMaxEnergyStored() - eContainer.getEnergyStored()) * data.storageLossData.lossValue), false);
                            break;
                        default:
                    }
                }
            }
    
            ImmutableMap blockProperties = world.getBlockState(pos).getProperties();
            if (blockProperties.containsKey(BlockCapacitor.FACING)) {
                EnumFacing fc = (EnumFacing)blockProperties.get(BlockCapacitor.FACING);
                    TileEntity te = world.getTileEntity(pos.offset(fc));
                    if (te != null && te.hasCapability(CapabilityEnergy.ENERGY, fc.getOpposite())) {
                        te.getCapability(CapabilityEnergy.ENERGY, fc.getOpposite())
                                .receiveEnergy(eExtractor.extractEnergy(data.maxOutputRate, false), false);
                    }
            }
        }
    
        @Override
        public boolean hasFastRenderer() {
            return true;
        }
    
        @Override
        public boolean hasCapability(Capability<?> capability, EnumFacing facing)
        {
            if (capability == CapabilityEnergy.ENERGY) {
                return true;
            }
            return super.hasCapability(capability, facing);
        }
    
        @Nullable
        @SuppressWarnings("unchecked")
        @Override
        public <T> T getCapability(Capability<T> capability, @Nullable EnumFacing facing) {
            if (capability == CapabilityEnergy.ENERGY) {
                if (facing == null) return (T)eContainer;
                ImmutableMap blockProperties = world.getBlockState(pos).getProperties();
                if (blockProperties.containsKey(BlockCapacitor.FACING)) {
                    if (facing.equals(blockProperties.get(BlockCapacitor.FACING))) {
                        return (T)eExtractor;
                    }
                    else return (T)eReceiver;
                }
            }
            return super.getCapability(capability, facing);
        }
    
        @Override
        public boolean shouldRefresh(World world, BlockPos pos, IBlockState oldState, IBlockState newState)
        {
            return (oldState.getBlock() != newState.getBlock());
        }
    
        @Override
        public NBTTagCompound writeToNBT(NBTTagCompound compound) {
            compound.setInteger("energy", eContainer.getEnergyStored());
            compound.setString("capid", data.id);
            return super.writeToNBT(compound);
        }
    
        @Override
        public void readFromNBT(NBTTagCompound compound) {
            data = CapacitorRegistry.getDataById(compound.getString("capid")) == null ? new CapacitorData() : CapacitorRegistry.getDataById(compound.getString("capid"));
    
            if (data != null) {
                if (data.storageLossData.lossDelay < 1) {
                    data.storageLossData.lossDelay = 1;
                    CustomCapacitors.logger.warn("Warning! Capacitor " + data.id + " has less than 1 loss delay!");
                    CustomCapacitors.logger.warn("It will be set to 1, please change the loss delay to a positive number!");
                }
    
                eContainer = new EnergyManager(data.capacity, data.maxInputRate, data.maxOutputRate) {
                    @Override
                    public int receiveEnergy(int maxReceive, boolean simulate) {
                        switch (data.inputLossType) {
                            case CONSTANT:
                                maxReceive = maxReceive - (int) Math.floor(data.inputLossValue);
                                break;
                            case PERCENTAGE:
                                maxReceive = maxReceive - Math.round(maxReceive * data.inputLossValue);
                                break;
                            case PERCENTAGE_INVERTED:
                                maxReceive = maxReceive - (int) ((this.maxReceive - maxReceive) * data.inputLossValue);
                                break;
                            default:
                        }
                        return super.receiveEnergy(maxReceive, simulate);
                    }
                };
    
                eReceiver = new EnergyManager(0, data.maxInputRate) {
                    @Override
                    public boolean canExtract() {
                        return false;
                    }
    
                    @Override
                    public int receiveEnergy(int maxReceive, boolean simulate) {
                        return eContainer.receiveEnergy(maxReceive, simulate);
                    }
                };
    
                eExtractor = new EnergyManager(0, data.maxOutputRate) {
                    @Override
                    public boolean canReceive() {
                        return false;
                    }
    
                    @Override
                    public int extractEnergy(int maxExtract, boolean simulate) {
                        return eContainer.extractEnergy(maxExtract, simulate);
                    }
                };
            }
    
            eContainer.setEnergy(compound.getInteger("energy"));
    
            super.readFromNBT(compound);
        }
    }

     

     

    javaw_2019-03-19_22-44-01.png

  7. Currently, I have a tile entity that stores two colors within itself, and it gets that color from the nbt tag of its item form. However, the block only changes to the correct color when a block update happens - before that, it uses a fallback color that I manually defined. How would I make it so that it uses the correct color right away? I've tried forcing a block update in readFromNbt, but that didn't do anything.

  8. So from what I'm understanding, let's say my energy container class is named EnergyManager. I should make one primary EnergyManager instance, then have two other anonymous EnergyManager instances that override every method to only interact with the first instance. Am I going about this correctly?

  9. I have a tileentity that I want to play a sound after a certain time has passed, but I'm struggling to find the right event for this. I've looked at the world.playSound methods, but they seem to require a player while my tileentity doesn't interact with players in any way, and the one that actually doesn't require a player seems to do nothing. What would I do here?

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.