mirror of
https://github.com/GTNewHorizons/StructureLib.git
synced 2026-10-25 20:32:24 +00:00
Add javadoc for APIs (#10)
This commit is contained in:
1 parent
21198c4d39
commit
adc91bb1dd
19 files changed
+1476
-196
No files matched your search
@@ -0,0 +1,64 @@
|
||||
name: Deploy Javadoc
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- feature/doc
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
jobs:
|
||||
javadoc:
|
||||
concurrency: javadoc-publish
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
result_hash: ${{ steps.deploy.outputs.hash }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/setup-java@v2
|
||||
with:
|
||||
java-version: 8
|
||||
distribution: 'temurin'
|
||||
cache: gradle
|
||||
|
||||
- name: Grant execute permission for gradlew
|
||||
run: chmod +x gradlew
|
||||
|
||||
- name: Generate Javadoc
|
||||
run: ./gradlew --no-daemon spotlessCheck javadoc
|
||||
|
||||
- name: Deploy 🚀
|
||||
id: deploy
|
||||
shell: bash
|
||||
run: |
|
||||
mv build/docs $RUNNER_TEMP/docs_output
|
||||
rm build -rf
|
||||
git checkout gh-pages
|
||||
mkdir -p $TARGET_FOLDER
|
||||
rm -rf $TARGET_FOLDER
|
||||
mv $RUNNER_TEMP/docs_output $TARGET_FOLDER -v
|
||||
git add $TARGET_FOLDER
|
||||
if git diff --cached --exit-code > /dev/null ; then
|
||||
echo Nothing to deploy
|
||||
exit 0
|
||||
fi
|
||||
find . -name javadoc -type d -print | sed 's#^\./\(.*\)/javadoc$#\1#' > index.txt
|
||||
git add index.txt
|
||||
git config user.name "${GITHUB_ACTOR}"
|
||||
git config user.email "${GITHUB_ACTOR}@users.noreply.github.com"
|
||||
git commit -m "Deploy javadoc from ref $TARGET_FOLDER"
|
||||
git push
|
||||
echo "::set-output name=hash::$(git rev-parse HEAD)"
|
||||
env:
|
||||
TARGET_FOLDER: ${{ github.ref_name }}
|
||||
COMMIT_AUTHOR: ${{ github.pusher.name }}
|
||||
COMMIT_EMAIL: ${{ github.pusher.email }}
|
||||
@@ -0,0 +1,24 @@
|
||||
javadoc {
|
||||
inputs.file "src/main/javadoc/overview.html"
|
||||
|
||||
include "com/gtnewhorizon/structurelib/alignment/**"
|
||||
include "com/gtnewhorizon/structurelib/constructable/**"
|
||||
include "com/gtnewhorizon/structurelib/structure/**"
|
||||
include "com/gtnewhorizon/structurelib/util/**"
|
||||
include "com/gtnewhorizon/structurelib/StructureLibAPI.java"
|
||||
|
||||
options {
|
||||
overview "src/main/javadoc/overview.html"
|
||||
links 'https://docs.oracle.com/javase/8/docs/api/'
|
||||
links 'https://skmedix.github.io/ForgeJavaDocs/javadoc/forge/1.7.10-10.13.4.1614/'
|
||||
}
|
||||
}
|
||||
|
||||
task javadocJar(type: Jar, dependsOn: javadoc) {
|
||||
classifier = 'javadoc'
|
||||
from javadoc.destinationDir
|
||||
}
|
||||
|
||||
artifacts {
|
||||
archives javadocJar
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
# Constructable Tool
|
||||
|
||||
The convention is to use the stack size of tool stack to pass tier info.
|
||||
|
||||
## Channels
|
||||
|
||||
When one multi have multiple tiered component that can have interleaving tier, this becomes an obnoxious restriction, as
|
||||
one ItemStack cannot have two stack sizes at the same time.
|
||||
Here we use the item NBT to bypass this restriction.
|
||||
|
||||
Basically, one hologram can contain multiple channels.
|
||||
Each channel can be identified with lower case strings and has the value being one positive Java int.
|
||||
There will be one and only one master channel and 0 or more sub channel.
|
||||
|
||||
When a non-existent sub channel is queried, master channel will be used instead to fill its place.
|
||||
|
||||
Structure element designers will usually not need to consider channels, i.e. proceed as if this concept does not exist, unless it must take input from multiple channels.
|
||||
|
||||
Multi Designers will consider how to map each channel to each tiered component.
|
||||
He will be using `com.gtnewhorizon.structurelib.structure.StructureUtility.withChannel` to direct structure element on which channel to use.
|
||||
Conceptually, it will return an ItemStack with the master channel being the value of selected channel.
|
||||
In implementation, withChannel will return a new ItemStack with same item, nbt but different stack size.
|
||||
|
||||
In any case, it is NOT safe to mutate or query this ItemStack beyond its stack size.
|
||||
What information this carries (beyond the stack size) is an implementation detail and should not be relied on.
|
||||
__For the future of mankind please do not rely on this.__
|
||||
|
||||
### why is this called channel?
|
||||
|
||||
IDK man, just give me a better name and I'd do the renaming.
|
||||
|
||||
### Example: Multiblock Structure Designer
|
||||
|
||||
GT++ Chemical Plant is a multi with 4 distinctly tiered component.
|
||||
|
||||
It will use
|
||||
* master channel for its outer shell
|
||||
* channel `"casing"` for machine casings
|
||||
* channel `"pipe"` for pipe casings
|
||||
* channel `"coil"` for heating coils
|
||||
|
||||
Its structure code will then look like
|
||||
```java
|
||||
.addElement('a', shellStructureElement())
|
||||
.addElement('b', withChannel("casing", machineCasingStructureElement()))
|
||||
.addElement('c', withChannel("pipe", pipeCasingStructureElement()))
|
||||
.addElement('d', withChannel("coil", coilStructureElement()))
|
||||
```
|
||||
|
||||
whereas all these structure elements are designed without considering channels whatsoever
|
||||
|
||||
### Example: Multi channel input Structure Element
|
||||
|
||||
Suppose your hatch element has a required facing and can accept arbitrary meta tile entity, so it will need both meta id and facing input.
|
||||
|
||||
|
||||
It will use
|
||||
* master channel for its outer shell
|
||||
* channel `"casing"` for machine casings
|
||||
* channel `"pipe"` for pipe casings
|
||||
* channel `"coil"` for heating coils
|
||||
|
||||
Its structure code will then look like
|
||||
```java
|
||||
.addElement('a', shellStructureElement())
|
||||
.addElement('b', withChannel("casing", machineCasingStructureElement()))
|
||||
.addElement('c', withChannel("pipe", pipeCasingStructureElement()))
|
||||
.addElement('d', withChannel("coil", coilStructureElement()))
|
||||
```
|
||||
|
||||
whereas all these structure elements are designed without considering channels whatsoever
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
# StructureLib Developer Guide v0.1-SNAPSHOT
|
||||
|
||||
## `IStructureDefinition`
|
||||
|
||||
`IStructureDefinition` is the structure definition of your multi. You will have one `IStructureDefinition` for each multi.
|
||||
|
||||
### Caching?
|
||||
|
||||
You will construct this definition once per multi, either at class load or at first call to `getStructureDefinition()`.
|
||||
You can use a `ClassValue<IStructureDefinition<?>>` if you have a template for subclass.
|
||||
You can also use `StructureUtility.defer()` for simpler cases, but it is slightly less performant as it will allocate new
|
||||
objects on each structure check, whereas `ClassValue` will allocate once and cache it onwards.
|
||||
|
||||
### Constructing
|
||||
|
||||
IStructureDefinition is constructed using `IStructureDefinition#builder()`.
|
||||
|
||||
Builder has two main methods
|
||||
1. `addShape` is a 2d string array describing the layout of structure. You can optionally use `StructureUtility#transpose()`
|
||||
to transpose the array to make the structure look nicer in source code.
|
||||
2. `addElement`. It takes a char identifier (mapped to a char in any of `addShape()` calls) and a IStructureElement.
|
||||
|
||||
## `IStructureElement`
|
||||
|
||||
`IStructureElement` are how you define which block will be accepted.
|
||||
They are simple stateless classes. They will rely on the multiblock controller to store any states they need.
|
||||
If you don't want to store these transient states in multiblock controller, you can use `StructureUtility#withContext()`
|
||||
|
||||
They will usually come from `StructureUtility`.
|
||||
There is a vast library of `IStructureElement` there to cover basic needs.
|
||||
For more complex usage, you can define your own subclass, e.g. GregTech 5 Unofficial defines `ofHatchAdder()`, `ofCoil()`,
|
||||
`ofFrame()` and `buildHatchAdder()` in its `GT_StructureUtility` class.
|
||||
|
||||
Here we will detail a few more complex `IStructureElement` that comes with standard library.
|
||||
|
||||
### `ofBlocksTiered`
|
||||
|
||||
This assumes you have a series of block, e.g. T1 motor, T2 motor, etc. Your multi will accept any of them (__as long as
|
||||
player does not mix them (*)__), but would like to know which is used.
|
||||
|
||||
(*): Implementation wise, this structure element will only accept a block if its tier is the same as existing tier or
|
||||
if existing tier is unset (i.e. value of third argument)
|
||||
|
||||
The first argument is tier extractor.
|
||||
You will need to provide a function to convert block+meta to a tier.
|
||||
This tier cam be an Enum, an Integer, a String, or basically anything.
|
||||
It doesn't even have to implement `Comparable`.
|
||||
The choice is yours.
|
||||
The extractor can return null and will never be passed a null block or an invalid block meta.
|
||||
|
||||
The second argument is a list of all blocks you know that you will accept.
|
||||
This list is only for hint particle spawning and survival build.
|
||||
The hint/autoplace code will choose 1st pair to spawn/place if hologram has [channel data](./channels.md) of 1,
|
||||
2nd pair if 2, and so on.
|
||||
|
||||
The third argument is the value when the tier has not been set by structure code.
|
||||
This means getter (5th argument) will usually return this upon first invocation for each round of structure check.
|
||||
|
||||
The fourth argument will notify the multi of a tier change.
|
||||
|
||||
The fifth argument is how multi notify the structure element about current tier.
|
||||
This is necessary as all structure element are stateless themselves.
|
||||
@@ -2,6 +2,7 @@ package com.gtnewhorizon.structurelib;
|
||||
|
||||
import static com.gtnewhorizon.structurelib.StructureLib.proxy;
|
||||
|
||||
import com.gtnewhorizon.structurelib.alignment.IAlignment;
|
||||
import com.gtnewhorizon.structurelib.alignment.IAlignmentProvider;
|
||||
import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing;
|
||||
import com.gtnewhorizon.structurelib.net.AlignmentMessage;
|
||||
@@ -55,25 +56,66 @@ public class StructureLibAPI {
|
||||
proxy.endHinting(w);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a new hint particle on client side at given location using given textures with a tint.
|
||||
* @param w World to spawn. Usually the client world.
|
||||
* @param x x coord
|
||||
* @param y y coord
|
||||
* @param z z coord
|
||||
* @param icons 6 texture. in forge direction order.
|
||||
* @param RGBa a 4 short array. tint in rgba form. currently alpha channel is ignored, but we might change this later on.
|
||||
*/
|
||||
public static void hintParticleTinted(World w, int x, int y, int z, IIcon[] icons, short[] RGBa) {
|
||||
proxy.hintParticleTinted(w, x, y, z, icons, RGBa);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a new hint particle on client side at given location using textures from given block with a tint.
|
||||
* @param w World to spawn. Usually the client world.
|
||||
* @param x x coord
|
||||
* @param y y coord
|
||||
* @param z z coord
|
||||
* @param block block to take texture from
|
||||
* @param meta the meta of block to take texture from
|
||||
* @param RGBa a 4 short array. tint in rgba form. currently alpha channel is ignored, but we might change this later on.
|
||||
*/
|
||||
public static void hintParticleTinted(World w, int x, int y, int z, Block block, int meta, short[] RGBa) {
|
||||
proxy.hintParticleTinted(w, x, y, z, block, meta, RGBa);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a new hint particle on client side at given location using given textures.
|
||||
* @param w World to spawn. Usually the client world.
|
||||
* @param x x coord
|
||||
* @param y y coord
|
||||
* @param z z coord
|
||||
* @param icons 6 texture. in forge direction order.
|
||||
*/
|
||||
public static void hintParticle(World w, int x, int y, int z, IIcon[] icons) {
|
||||
proxy.hintParticle(w, x, y, z, icons);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a new hint particle on client side at given location using textures from given block.
|
||||
* @param w World to spawn. Usually the client world.
|
||||
* @param x x coord
|
||||
* @param y y coord
|
||||
* @param z z coord
|
||||
* @param block block to take texture from
|
||||
* @param meta the meta of block to take texture from
|
||||
*/
|
||||
public static void hintParticle(World w, int x, int y, int z, Block block, int meta) {
|
||||
proxy.hintParticle(w, x, y, z, block, meta);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the tint of given hint particle. Do nothing if particle not found.
|
||||
* @return false if nothing updated. true if updated.
|
||||
*
|
||||
* Can be called on either client side or server side.
|
||||
* Server side will schedule a network message to update it for this player only.
|
||||
* Will do nothing if no hint particle is found at given location.
|
||||
*
|
||||
* @return false if nothing updated. true if updated or update instruction sent.
|
||||
*/
|
||||
public static boolean markHintParticleError(EntityPlayer player, World w, int x, int y, int z) {
|
||||
return proxy.markHintParticleError(player, w, x, y, z);
|
||||
@@ -81,6 +123,7 @@ public class StructureLibAPI {
|
||||
|
||||
/**
|
||||
* Update the tint of given hint particle. Do nothing if particle not found.
|
||||
*
|
||||
* @return false if nothing updated. true if updated.
|
||||
*/
|
||||
public static boolean updateHintParticleTint(EntityPlayer player, World w, int x, int y, int z, short[] RGBa) {
|
||||
@@ -88,9 +131,11 @@ public class StructureLibAPI {
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the ExtendedFacing of this tile entity.
|
||||
* Query the ExtendedFacing of this tile entity from client side. Can be sent only on client side.
|
||||
* The ExtendedFacing will later be set onto given tile entity via {@link com.gtnewhorizon.structurelib.alignment.IAlignment#setExtendedFacing(ExtendedFacing)}
|
||||
* upon arrival of server reply.
|
||||
* <p>
|
||||
* The server side will query the {@link ExtendedFacing} of this provider using {@link IAlignment#getExtendedFacing()}
|
||||
*
|
||||
* @throws IllegalArgumentException if is not tile entity or provided a null alignment
|
||||
*/
|
||||
@@ -100,6 +145,8 @@ public class StructureLibAPI {
|
||||
|
||||
/**
|
||||
* Send the ExtendedFacing of this Tile Entity to all players. Can be called on server side only.
|
||||
* <p>
|
||||
* The receiving tile entity will receive the {@link ExtendedFacing} via its {@link com.gtnewhorizon.structurelib.alignment.IAlignment#setExtendedFacing(ExtendedFacing)} method.
|
||||
*
|
||||
* @throws IllegalArgumentException if is not tile entity or provided a null alignment
|
||||
*/
|
||||
@@ -109,6 +156,8 @@ public class StructureLibAPI {
|
||||
|
||||
/**
|
||||
* Send the ExtendedFacing of this Tile Entity to given player. Can be called on server side only.
|
||||
* <p>
|
||||
* The receiving tile entity will receive the {@link ExtendedFacing} via its {@link com.gtnewhorizon.structurelib.alignment.IAlignment#setExtendedFacing(ExtendedFacing)} method.
|
||||
*
|
||||
* @throws IllegalArgumentException if is not tile entity or provided a null alignment
|
||||
*/
|
||||
@@ -118,6 +167,8 @@ public class StructureLibAPI {
|
||||
|
||||
/**
|
||||
* Send the ExtendedFacing of this Tile Entity to all players around target point. Can be called on server side only.
|
||||
* <p>
|
||||
* The receiving tile entity will receive the {@link ExtendedFacing} via its {@link com.gtnewhorizon.structurelib.alignment.IAlignment#setExtendedFacing(ExtendedFacing)} method.
|
||||
*
|
||||
* @throws IllegalArgumentException if is not tile entity or provided a null alignment
|
||||
*/
|
||||
@@ -127,6 +178,8 @@ public class StructureLibAPI {
|
||||
|
||||
/**
|
||||
* Send the ExtendedFacing of this Tile Entity to all players in that dimension. Can be called on server side only.
|
||||
* <p>
|
||||
* The receiving tile entity will receive the {@link ExtendedFacing} via its {@link com.gtnewhorizon.structurelib.alignment.IAlignment#setExtendedFacing(ExtendedFacing)} method.
|
||||
*
|
||||
* @throws IllegalArgumentException if is not tile entity or provided a null alignment
|
||||
*/
|
||||
@@ -134,14 +187,25 @@ public class StructureLibAPI {
|
||||
StructureLib.net.sendToDimension(new AlignmentMessage.AlignmentData(provider), dimension.provider.dimensionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Block for StructureLib supplied hint block.
|
||||
*/
|
||||
public static Block getBlockHint() {
|
||||
return StructureLib.blockHint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ItemBlock for StructureLib supplied hint block.
|
||||
*/
|
||||
public static Item getItemBlockHint() {
|
||||
return StructureLib.itemBlockHint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if structure debug mode is on.
|
||||
*
|
||||
* @return true if debug mode is on
|
||||
*/
|
||||
public static boolean isDebugEnabled() {
|
||||
return StructureLib.DEBUG_MODE;
|
||||
}
|
||||
@@ -153,11 +217,12 @@ public class StructureLibAPI {
|
||||
/**
|
||||
* Determines if given block can be replaced without much effort. The exact predicate clauses is not stable and
|
||||
* will be changed, but the general idea will always stay the same.
|
||||
*
|
||||
* <p>
|
||||
* Use this in your {@link com.gtnewhorizon.structurelib.structure.IStructureElement#survivalPlaceBlock(Object, World, int, int, int, ItemStack, IItemSource, EntityPlayerMP, java.util.function.Consumer)}
|
||||
*/
|
||||
public static boolean isBlockTriviallyReplaceable(World w, int x, int y, int z, EntityPlayerMP actor) {
|
||||
// TODO extend this function a bit
|
||||
return w.getBlock(x, y, z).isReplaceable(w, x, y, z);
|
||||
Block block = w.getBlock(x, y, z);
|
||||
return block.isAir(w, x, y, z) || block.isReplaceable(w, x, y, z);
|
||||
}
|
||||
}
|
||||
+87
-10
@@ -3,7 +3,7 @@ package com.gtnewhorizon.structurelib.alignment.constructable;
|
||||
import static com.gtnewhorizon.structurelib.util.MiscUtils.getTagKeys;
|
||||
import static net.minecraftforge.common.util.Constants.NBT.TAG_COMPOUND;
|
||||
|
||||
import com.gtnewhorizon.structurelib.StructureLib;
|
||||
import com.gtnewhorizon.structurelib.StructureLibAPI;
|
||||
import java.util.Locale;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.stream.Stream;
|
||||
@@ -11,16 +11,38 @@ import net.minecraft.init.Items;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraftforge.common.util.Constants.NBT;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||
|
||||
/**
|
||||
* Provide accessor methods for channel data from trigger item.
|
||||
*
|
||||
* <a href="{@docRoot}/overview-summary.html#channels">Channels section on overview</a>
|
||||
*/
|
||||
public class ChannelDataAccessor {
|
||||
private static final String SECONDARY_HINT_TAG = "channels";
|
||||
|
||||
private ChannelDataAccessor() {}
|
||||
|
||||
/**
|
||||
* Return a trigger item that
|
||||
* <ul>
|
||||
* <li>Still carry all the subchannel in some unspecified ways</li>
|
||||
* <li>Have its master channel data replaced with specified subchannel's data</li>
|
||||
* </ul>
|
||||
*
|
||||
* If given subchannel does not exist, masterStack may or may not be returned to save performance.
|
||||
* Code within StructureLib can depend on this behavior, you cannot.
|
||||
*
|
||||
* @param masterStack trigger item. can be the return value of another {@link #withChannel(ItemStack, String)} call
|
||||
* @param channel subchannel to use. will use current master channel data instead if this channel does not exist
|
||||
* Note: all channel identifiers are supposed to be lower case and not empty.
|
||||
* @return a trigger item with new master channel
|
||||
*/
|
||||
public static ItemStack withChannel(ItemStack masterStack, String channel) {
|
||||
if (channel == null || channel.isEmpty()) throw new IllegalArgumentException();
|
||||
if (StructureLib.DEBUG_MODE && !channel.toLowerCase(Locale.ROOT).equals(channel))
|
||||
if (StringUtils.isEmpty(channel) || masterStack == null) throw new IllegalArgumentException();
|
||||
if (StructureLibAPI.isDebugEnabled()
|
||||
&& !channel.toLowerCase(Locale.ROOT).equals(channel))
|
||||
throw new IllegalArgumentException("Channel name can be lower case ONLY");
|
||||
if (!masterStack.hasTagCompound()
|
||||
|| !masterStack.stackTagCompound.hasKey(SECONDARY_HINT_TAG, TAG_COMPOUND)
|
||||
@@ -36,12 +58,27 @@ public class ChannelDataAccessor {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if given trigger item contains any subchannel
|
||||
* @param masterStack trigger stack to check
|
||||
* @return true if contains any subchannel
|
||||
*/
|
||||
public static boolean hasSubChannel(ItemStack masterStack) {
|
||||
if (masterStack == null) throw new IllegalArgumentException();
|
||||
return masterStack.hasTagCompound() && masterStack.stackTagCompound.hasKey(SECONDARY_HINT_TAG, TAG_COMPOUND);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if given trigger item contains specified subchannel
|
||||
* @param masterStack trigger stack to check
|
||||
* @param channel channel identifier.
|
||||
* Note: all channel identifiers are supposed to be lower case and not empty.
|
||||
* @return true if contains specified subchannel
|
||||
*/
|
||||
public static boolean hasSubChannel(ItemStack masterStack, String channel) {
|
||||
if (StructureLib.DEBUG_MODE && !channel.toLowerCase(Locale.ROOT).equals(channel))
|
||||
if (StringUtils.isEmpty(channel) || masterStack == null) throw new IllegalArgumentException();
|
||||
if (StructureLibAPI.isDebugEnabled()
|
||||
&& !channel.toLowerCase(Locale.ROOT).equals(channel))
|
||||
throw new IllegalArgumentException("Channel name can be lower case ONLY");
|
||||
return !channel.isEmpty()
|
||||
&& masterStack.hasTagCompound()
|
||||
@@ -52,9 +89,17 @@ public class ChannelDataAccessor {
|
||||
.hasKey(channel, NBT.TAG_INT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the subchannel data from given trigger item. Will use master channel instead if not present.
|
||||
* @param masterStack trigger stack to query from
|
||||
* @param channel channel identifier.
|
||||
* Note: all channel identifiers are supposed to be lower case and not empty.
|
||||
* @return channel data
|
||||
*/
|
||||
public static int getChannelData(ItemStack masterStack, String channel) {
|
||||
if (channel == null || channel.isEmpty()) throw new IllegalArgumentException();
|
||||
if (StructureLib.DEBUG_MODE && !channel.toLowerCase(Locale.ROOT).equals(channel))
|
||||
if (StringUtils.isEmpty(channel) || masterStack == null) throw new IllegalArgumentException();
|
||||
if (StructureLibAPI.isDebugEnabled()
|
||||
&& !channel.toLowerCase(Locale.ROOT).equals(channel))
|
||||
throw new IllegalArgumentException("Channel name can be lower case ONLY");
|
||||
if (!masterStack.hasTagCompound()
|
||||
|| !masterStack.stackTagCompound.hasKey(SECONDARY_HINT_TAG, TAG_COMPOUND)
|
||||
@@ -65,9 +110,17 @@ public class ChannelDataAccessor {
|
||||
return masterStack.stackTagCompound.getCompoundTag(SECONDARY_HINT_TAG).getInteger(channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the subchannel data on given trigger item
|
||||
* @param masterStack trigger stack to check
|
||||
* @param channel channel identifier.
|
||||
* Note: all channel identifiers are supposed to be lower case and not empty.
|
||||
* @param data subchannel data. should always be a positive value
|
||||
*/
|
||||
public static void setChannelData(ItemStack masterStack, String channel, int data) {
|
||||
if (channel == null || channel.isEmpty()) throw new IllegalArgumentException();
|
||||
if (StructureLib.DEBUG_MODE && !channel.toLowerCase(Locale.ROOT).equals(channel))
|
||||
if (StringUtils.isEmpty(channel) || masterStack == null) throw new IllegalArgumentException();
|
||||
if (StructureLibAPI.isDebugEnabled()
|
||||
&& !channel.toLowerCase(Locale.ROOT).equals(channel))
|
||||
throw new IllegalArgumentException("Channel name can be lower case ONLY");
|
||||
if (data <= 0) throw new IllegalArgumentException();
|
||||
if (masterStack.stackTagCompound == null) masterStack.stackTagCompound = new NBTTagCompound();
|
||||
@@ -76,9 +129,16 @@ public class ChannelDataAccessor {
|
||||
main.getCompoundTag(SECONDARY_HINT_TAG).setInteger(channel, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the given subchannel from given trigger item, if it exists
|
||||
* @param masterStack trigger stack to unset
|
||||
* @param channel channel identifier.
|
||||
* Note: all channel identifiers are supposed to be lower case and not empty.
|
||||
*/
|
||||
public static void unsetChannelData(ItemStack masterStack, String channel) {
|
||||
if (channel == null || channel.isEmpty()) throw new IllegalArgumentException();
|
||||
if (StructureLib.DEBUG_MODE && !channel.toLowerCase(Locale.ROOT).equals(channel))
|
||||
if (StringUtils.isEmpty(channel) || masterStack == null) throw new IllegalArgumentException();
|
||||
if (StructureLibAPI.isDebugEnabled()
|
||||
&& !channel.toLowerCase(Locale.ROOT).equals(channel))
|
||||
throw new IllegalArgumentException("Channel name can be lower case ONLY");
|
||||
if (masterStack.stackTagCompound == null) masterStack.stackTagCompound = new NBTTagCompound();
|
||||
NBTTagCompound main = masterStack.stackTagCompound;
|
||||
@@ -89,16 +149,33 @@ public class ChannelDataAccessor {
|
||||
if (main.hasNoTags()) masterStack.stackTagCompound = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wipe all subchannel data on given trigger item
|
||||
* @param masterStack trigger stack to wipe
|
||||
*/
|
||||
public static void wipeChannelData(ItemStack masterStack) {
|
||||
if (masterStack == null) throw new IllegalArgumentException();
|
||||
if (masterStack.stackTagCompound != null) masterStack.stackTagCompound.removeTag(SECONDARY_HINT_TAG);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate over all subchannel data on trigger stack. Does not include master channel!!
|
||||
* @param masterStack trigger stack to check
|
||||
* @return A java8 stream of pairs. Key is channel identifier and value is channel data. Pairs do not support
|
||||
* mutation nor removal. Can still cause {@link java.util.ConcurrentModificationException} if underlying channel
|
||||
* data is modified while stream is working.
|
||||
*/
|
||||
public static Stream<Entry<String, Integer>> iterateChannelData(ItemStack masterStack) {
|
||||
if (!hasSubChannel(masterStack)) return Stream.empty();
|
||||
NBTTagCompound tag = masterStack.stackTagCompound.getCompoundTag(SECONDARY_HINT_TAG);
|
||||
return getTagKeys(tag).stream().map(s -> new ImmutablePair<>(s, tag.getInteger(s)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of subchannels present on given trigger item. Does not include master channel.
|
||||
* @param masterStack trigger stack to query from
|
||||
* @return subchannel count
|
||||
*/
|
||||
public static int countChannelData(ItemStack masterStack) {
|
||||
if (!hasSubChannel(masterStack)) return 0;
|
||||
NBTTagCompound tag = masterStack.stackTagCompound.getCompoundTag(SECONDARY_HINT_TAG);
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* This package contains interfaces and utility methods for autobuilding a structure.
|
||||
*/
|
||||
package com.gtnewhorizon.structurelib.alignment.constructable;
|
||||
+2
-2
@@ -335,7 +335,7 @@ public enum ExtendedFacing {
|
||||
/**
|
||||
* Translates relative to front facing offset to world offset
|
||||
*
|
||||
* @param abcOffset A,B,C offset (facing relative L-->R,U-->D,F-->B)
|
||||
* @param abcOffset A,B,C offset (facing relative {@code L-->R,U-->D,F-->B})
|
||||
* @return X, Y, Z offset in world
|
||||
*/
|
||||
public Vec3 getWorldOffset(Vec3 abcOffset) {
|
||||
@@ -358,7 +358,7 @@ public enum ExtendedFacing {
|
||||
* Translates world offset to relative front facing offset
|
||||
*
|
||||
* @param xyzOffset X,Y,Z offset in world
|
||||
* @return A, B, C offset (facing relative L-->R,U-->D,F-->B)
|
||||
* @return A, B, C offset (facing relative {@code L-->R,U-->D,F-->B})
|
||||
*/
|
||||
public Vec3 getOffsetABC(Vec3 xyzOffset) {
|
||||
return integerAxisSwap.translate(xyzOffset);
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/**
|
||||
* This package provide a framework for rotating a given block, or a multiblock structure.
|
||||
* <p>
|
||||
* All public stuff in this package and its subpackages are considered part of the public API.
|
||||
* Backwards compatibility is maintained to the maximum extend possible.
|
||||
*/
|
||||
|
||||
@@ -45,6 +45,10 @@ public abstract class AlignmentMessage implements IMessage {
|
||||
ByteBufUtils.writeTag(pBuffer, tFXTag);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link com.gtnewhorizon.structurelib.structure.IStructureDefinition#check(Object, String, World, ExtendedFacing, int, int, int, int, int, int, boolean)}
|
||||
* @param provider
|
||||
*/
|
||||
private AlignmentMessage(IAlignmentProvider provider) {
|
||||
if (!(provider instanceof TileEntity)) throw new IllegalArgumentException("Provider must be a TileEntity");
|
||||
IAlignment alignment = provider.getAlignment();
|
||||
|
||||
@@ -41,7 +41,7 @@ public class ErrorHintParticleMessage implements IMessage {
|
||||
public IMessage onMessage(ErrorHintParticleMessage msg, MessageContext ctx) {
|
||||
boolean updateResult = StructureLibAPI.markHintParticleError(
|
||||
StructureLib.getCurrentPlayer(), StructureLib.getCurrentPlayer().worldObj, msg.x, msg.y, msg.z);
|
||||
if (StructureLib.DEBUG_MODE)
|
||||
if (StructureLibAPI.isDebugEnabled())
|
||||
LOGGER.debug(
|
||||
"Server instructed to mark hint particle at ({}, {}, {}) error, result {}!",
|
||||
msg.x,
|
||||
|
||||
@@ -64,7 +64,7 @@ public class UpdateHintParticleMessage implements IMessage {
|
||||
new short[] {
|
||||
msg.r, msg.g, msg.b, msg.a,
|
||||
});
|
||||
if (StructureLib.DEBUG_MODE)
|
||||
if (StructureLibAPI.isDebugEnabled())
|
||||
LOGGER.debug(
|
||||
"Server instructed to update hint particle at ({}, {}, {}), result {}!",
|
||||
msg.x,
|
||||
|
||||
@@ -1,15 +1,48 @@
|
||||
package com.gtnewhorizon.structurelib.structure;
|
||||
|
||||
import static com.gtnewhorizon.structurelib.StructureLib.DEBUG_MODE;
|
||||
import static com.gtnewhorizon.structurelib.structure.IStructureWalker.ignoreBlockUnloaded;
|
||||
import static com.gtnewhorizon.structurelib.structure.IStructureWalker.skipBlockUnloaded;
|
||||
|
||||
import com.gtnewhorizon.structurelib.StructureLib;
|
||||
import com.gtnewhorizon.structurelib.StructureLibAPI;
|
||||
import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing;
|
||||
import java.util.function.Function;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
/**
|
||||
* This is the structure definition of your multi. You will have one of these for each multi.
|
||||
*
|
||||
* <h2>Cache the instances of this class</h2>
|
||||
* <p>
|
||||
* You will construct this definition once per multi, either at class load or at first call to your variant of {@code getStructureDefinition()}.
|
||||
* You can use a {@link ClassValue ClassValue<IStructureDefinition<?>>} if you have a template for subclass.
|
||||
* You can also use {@link StructureUtility#defer(Function) defer()} or its overloads for simpler cases, but it is
|
||||
* slightly less performant as it will allocate new objects on each structure check, whereas {@link ClassValue} will
|
||||
* allocate once and cache it onwards.
|
||||
* <p>
|
||||
* <h2>Constructing</h2>
|
||||
* <p>
|
||||
* {@linkplain IStructureDefinition} is constructed using {@link IStructureDefinition#builder()}
|
||||
* <p>
|
||||
* Builder has two main methods:
|
||||
* <ul>
|
||||
* <li>{@link com.gtnewhorizon.structurelib.structure.StructureDefinition.Builder#addShape(String, String[][]) addShape()}
|
||||
* is a 2d string array describing the layout of structure. You can optionally use `StructureUtility#transpose()`
|
||||
* to transpose the array to make the structure look nicer in source code.
|
||||
* <li>{@link com.gtnewhorizon.structurelib.structure.StructureDefinition.Builder#addElement(Character, IStructureElement) addElement()}. It takes a char identifier (mapped to a char in any of {@link com.gtnewhorizon.structurelib.structure.StructureDefinition.Builder#addShape(String, String[][]) addShape()} calls) and a {@link IStructureElement}.
|
||||
* </ul>
|
||||
* <h2>Position A, B and C</h2>
|
||||
*
|
||||
* Imagine you stand in front of the controller, with controller facing towards you not rotated or flipped.
|
||||
* <ul>
|
||||
* <li>The "A" position would be the number of blocks on the left side of the controller, not counting controller itself.</li>
|
||||
* <li>The "B" position would be the number of blocks on the top side of the controller, not counting controller itself.</li>
|
||||
* <li>The "C" position would be the number of blocks between you and controller, not counting controller itself.</li>
|
||||
* </ul>
|
||||
* @param <T> Type of the context object. Usually this will be the multiblock controller.
|
||||
*/
|
||||
public interface IStructureDefinition<T> {
|
||||
/**
|
||||
* Used internally
|
||||
@@ -22,6 +55,21 @@ public interface IStructureDefinition<T> {
|
||||
*/
|
||||
IStructureElement<T>[] getStructureFor(String name);
|
||||
|
||||
/**
|
||||
* Run a structure check.
|
||||
* @param object context object. usually multiblock controller.
|
||||
* @param piece the structure piece's string identifier.
|
||||
* @param world the world object this check takes place in.
|
||||
* @param extendedFacing the current structure's orientation.
|
||||
* @param basePositionX X location of the structure
|
||||
* @param basePositionY Y location of the structure
|
||||
* @param basePositionZ Z location of the structure
|
||||
* @param basePositionA see class javadoc
|
||||
* @param basePositionB see class javadoc
|
||||
* @param basePositionC see class javadoc
|
||||
* @param forceCheckAllBlocks check all location even if chunk not currently loaded.
|
||||
* @return true if successful, false otherwise
|
||||
*/
|
||||
default boolean check(
|
||||
T object,
|
||||
String piece,
|
||||
@@ -50,6 +98,20 @@ public interface IStructureDefinition<T> {
|
||||
forceCheckAllBlocks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawn hint particles. Should not be called on server side.
|
||||
* @param object context object. usually multiblock controller.
|
||||
* @param piece the structure piece's string identifier.
|
||||
* @param world the world object this check takes place in.
|
||||
* @param extendedFacing the current structure's orientation.
|
||||
* @param basePositionX X location of the structure
|
||||
* @param basePositionY Y location of the structure
|
||||
* @param basePositionZ Z location of the structure
|
||||
* @param basePositionA see class javadoc
|
||||
* @param basePositionB see class javadoc
|
||||
* @param basePositionC see class javadoc
|
||||
* @return true if successful, false otherwise
|
||||
*/
|
||||
default boolean hints(
|
||||
T object,
|
||||
ItemStack trigger,
|
||||
@@ -78,6 +140,23 @@ public interface IStructureDefinition<T> {
|
||||
null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the multi in creative mode on a best effort basis. Does not guarantee the structure is correct after a
|
||||
* successful call.
|
||||
*
|
||||
* @param object context object. usually multiblock controller.
|
||||
* @param trigger The trigger item that contains channel data.
|
||||
* @param piece the structure piece's string identifier.
|
||||
* @param world the world object this check takes place in.
|
||||
* @param extendedFacing the current structure's orientation.
|
||||
* @param basePositionX X location of the structure
|
||||
* @param basePositionY Y location of the structure
|
||||
* @param basePositionZ Z location of the structure
|
||||
* @param basePositionA see class javadoc
|
||||
* @param basePositionB see class javadoc
|
||||
* @param basePositionC see class javadoc
|
||||
* @return true if sucessful, false otherwise
|
||||
*/
|
||||
default boolean build(
|
||||
T object,
|
||||
ItemStack trigger,
|
||||
@@ -106,6 +185,26 @@ public interface IStructureDefinition<T> {
|
||||
null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call {@link #build(Object, ItemStack, String, World, ExtendedFacing, int, int, int, int, int, int)} if {@code hintsOnly},
|
||||
* call {@link #hints(Object, ItemStack, String, World, ExtendedFacing, int, int, int, int, int, int)} otherwise.
|
||||
*
|
||||
* @param object context object. usually multiblock controller.
|
||||
* @param trigger The trigger item that contains channel data.
|
||||
* @param piece the structure piece's string identifier.
|
||||
* @param world the world object this check takes place in.
|
||||
* @param extendedFacing the current structure's orientation.
|
||||
* @param basePositionX X location of the structure
|
||||
* @param basePositionY Y location of the structure
|
||||
* @param basePositionZ Z location of the structure
|
||||
* @param basePositionA see class javadoc
|
||||
* @param basePositionB see class javadoc
|
||||
* @param basePositionC see class javadoc
|
||||
* @param hintsOnly whether to spawn hints or do creative build.
|
||||
* @return true if sucessful, false otherwise
|
||||
* @see #hints(Object, ItemStack, String, World, ExtendedFacing, int, int, int, int, int, int)
|
||||
* @see #build(Object, ItemStack, String, World, ExtendedFacing, int, int, int, int, int, int)
|
||||
*/
|
||||
default boolean buildOrHints(
|
||||
T object,
|
||||
ItemStack trigger,
|
||||
@@ -136,6 +235,19 @@ public interface IStructureDefinition<T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Cause a survival build.
|
||||
*
|
||||
* @param object context object. usually multiblock controller.
|
||||
* @param trigger The trigger item that contains channel data.
|
||||
* @param piece the structure piece's string identifier.
|
||||
* @param world the world object this check takes place in.
|
||||
* @param extendedFacing the current structure's orientation.
|
||||
* @param basePositionX X location of the structure
|
||||
* @param basePositionY Y location of the structure
|
||||
* @param basePositionZ Z location of the structure
|
||||
* @param basePositionA see class javadoc
|
||||
* @param basePositionB see class javadoc
|
||||
* @param basePositionC see class javadoc
|
||||
* @param elementBudget build up to this many elements
|
||||
* @param source from where to drain resource
|
||||
* @param actor source of action
|
||||
@@ -179,6 +291,25 @@ public interface IStructureDefinition<T> {
|
||||
return walker.getBuilt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Low level utility.
|
||||
* @param object context object. usually multiblock controller.
|
||||
* @param trigger The trigger item that contains channel data.
|
||||
* @param elements the structure piece
|
||||
* @param world the world object this check takes place in.
|
||||
* @param extendedFacing the current structure's orientation.
|
||||
* @param basePositionX X location of the structure
|
||||
* @param basePositionY Y location of the structure
|
||||
* @param basePositionZ Z location of the structure
|
||||
* @param basePositionA see class javadoc
|
||||
* @param basePositionB see class javadoc
|
||||
* @param basePositionC see class javadoc
|
||||
* @param hintsOnly whether to spawn hints or do creative build. no effect if {@code checkBlocksIfNotNullForceCheckAllIfTrue} is not null.
|
||||
* @param checkBlocksIfNotNullForceCheckAllIfTrue creative build or spawn hints if null. Force check not loaded chunk
|
||||
* if true. Check only loaded chunk is false.
|
||||
* @return true if iteration completed successfully.
|
||||
* @param <T> type of context object.
|
||||
*/
|
||||
static <T> boolean iterate(
|
||||
T object,
|
||||
ItemStack trigger,
|
||||
@@ -226,7 +357,7 @@ public interface IStructureDefinition<T> {
|
||||
skipBlockUnloaded((e, w, x, y, z) -> e.check(object, w, x, y, z)),
|
||||
"check force");
|
||||
}
|
||||
if (DEBUG_MODE && success) {
|
||||
if (StructureLibAPI.isDebugEnabled() && success) {
|
||||
StructureLib.LOGGER.info(
|
||||
"Multi [" + basePositionX + ", " + basePositionY + ", " + basePositionZ + "] pass");
|
||||
}
|
||||
@@ -269,6 +400,11 @@ public interface IStructureDefinition<T> {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of builder.
|
||||
* @return
|
||||
* @param <T> type of context object
|
||||
*/
|
||||
static <T> StructureDefinition.Builder<T> builder() {
|
||||
return StructureDefinition.builder();
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package com.gtnewhorizon.structurelib.structure;
|
||||
|
||||
import static com.gtnewhorizon.structurelib.StructureLib.DEBUG_MODE;
|
||||
import static com.gtnewhorizon.structurelib.StructureLib.LOGGER;
|
||||
import static com.gtnewhorizon.structurelib.StructureLib.PANIC_MODE;
|
||||
|
||||
import com.gtnewhorizon.structurelib.StructureLibAPI;
|
||||
import java.util.function.Consumer;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.IChatComponent;
|
||||
@@ -23,10 +23,16 @@ public interface IStructureElement<T> {
|
||||
|
||||
/**
|
||||
* Try place the block by taking resource from given IItemSource.
|
||||
* <p>
|
||||
* You might want to use {@link StructureUtility#survivalPlaceBlock(Block, int, World, int, int, int, IItemSource, EntityPlayerMP)}
|
||||
* or its overloads to implement this.
|
||||
*
|
||||
* @param trigger trigger item
|
||||
* @param s drain resources from this place
|
||||
* @param actor source of action.
|
||||
* @param chatter
|
||||
* @param actor source of action. for very critical errors you can also just send the error messages here, bypassing
|
||||
* any filter that chatter might have.
|
||||
* @param chatter send error messages here. Caller will choose an appropriate way to forward it to player if the
|
||||
* other fallbacks also fails.
|
||||
*/
|
||||
default PlaceResult survivalPlaceBlock(
|
||||
T t,
|
||||
@@ -39,7 +45,7 @@ public interface IStructureElement<T> {
|
||||
EntityPlayerMP actor,
|
||||
Consumer<IChatComponent> chatter) {
|
||||
if (PANIC_MODE) throw new RuntimeException("Panic Tripwire hit");
|
||||
if (DEBUG_MODE)
|
||||
if (StructureLibAPI.isDebugEnabled())
|
||||
LOGGER.error(
|
||||
"Default implementation of survivalPlaceBlock hit! Things aren't going to work well! IStructureElement class: {}",
|
||||
getClass().getName());
|
||||
@@ -115,7 +121,7 @@ public interface IStructureElement<T> {
|
||||
ACCEPT,
|
||||
/**
|
||||
* Combination of ACCEPT and STOP.
|
||||
*
|
||||
* <p>
|
||||
* Element placed successfully. To proceed further would require stopping the placement and wait for next round.
|
||||
*/
|
||||
ACCEPT_STOP;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.gtnewhorizon.structurelib.structure;
|
||||
|
||||
import static com.gtnewhorizon.structurelib.StructureLib.DEBUG_MODE;
|
||||
import static com.gtnewhorizon.structurelib.structure.StructureUtility.*;
|
||||
|
||||
import com.gtnewhorizon.structurelib.StructureLibAPI;
|
||||
import com.gtnewhorizon.structurelib.util.Vec3Impl;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -130,7 +130,7 @@ public class StructureDefinition<T> implements IStructureDefinition<T> {
|
||||
|
||||
public IStructureDefinition<T> build() {
|
||||
Map<String, IStructureElement<T>[]> structures = compileStructureMap();
|
||||
if (DEBUG_MODE) {
|
||||
if (StructureLibAPI.isDebugEnabled()) {
|
||||
return new StructureDefinition<>(new HashMap<>(elements), new HashMap<>(shapes), structures);
|
||||
} else {
|
||||
return structures::get;
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Adder interfaces used in various standard structure elements.
|
||||
*/
|
||||
package com.gtnewhorizon.structurelib.structure.adders;
|
||||
@@ -1,4 +1,6 @@
|
||||
/**
|
||||
* This package provide support for multiblock structure checking.
|
||||
* <p>
|
||||
* All public stuff in this package and its subpackages are considered part of the public API.
|
||||
* Backwards compatibility is maintained to the maximum extend possible.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,235 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>API Overview</TITLE>
|
||||
</HEAD>
|
||||
<BODY>
|
||||
StructureLib API documentation.
|
||||
|
||||
<h1>Key API class outline</h1>
|
||||
<p>
|
||||
Here we outline a few key API classes/interfaces.
|
||||
</p>
|
||||
|
||||
<h2> {@link com.gtnewhorizon.structurelib.structure.IStructureDefinition}</h2>
|
||||
<p>
|
||||
This is the structure definition of your multi.
|
||||
You will have one `IStructureDefinition` for each multi.
|
||||
</p>
|
||||
|
||||
<h2> {@link com.gtnewhorizon.structurelib.structure.IStructureElement}</h2>
|
||||
<p>
|
||||
These are how you define which block will be accepted.
|
||||
</p>
|
||||
|
||||
<h2> {@link com.gtnewhorizon.structurelib.structure.StructureUtility}</h2>
|
||||
<p>
|
||||
This is the standard library of {@link com.gtnewhorizon.structurelib.structure.IStructureElement
|
||||
IStructureElement}s.
|
||||
The Standard Library contains structure elements that handle basic block element and elements that allow composing
|
||||
these basic elements.
|
||||
</p>
|
||||
|
||||
<h2> {@link com.gtnewhorizon.structurelib.alignment.constructable.IConstructable}</h2>
|
||||
<p>
|
||||
This interface should be implemented by tile entities that support creative autoplacing and hint particle emitting.
|
||||
You will usually want to have a backing {@link com.gtnewhorizon.structurelib.structure.IStructureDefinition
|
||||
IStructureDefinition}
|
||||
and call its {@link com.gtnewhorizon.structurelib.structure.IStructureDefinition#build(Object, ItemStack, String,
|
||||
World, ExtendedFacing, int, int, int, int, int, int) build()}
|
||||
or {@link com.gtnewhorizon.structurelib.structure.IStructureDefinition#hints(Object, ItemStack, String, World,
|
||||
ExtendedFacing, int, int, int, int, int, int) hints()} method here.
|
||||
</p>
|
||||
|
||||
<h2> {@link com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable}</h2>
|
||||
<p>
|
||||
This interface is an enhancement over {@link com.gtnewhorizon.structurelib.alignment.constructable.IConstructable
|
||||
IConstructable}.
|
||||
If your tile entities also support survival autoplacing then you should implement this.
|
||||
You will usually want to have a backing {@link com.gtnewhorizon.structurelib.structure.IStructureDefinition
|
||||
IStructureDefinition}
|
||||
and call its {@link com.gtnewhorizon.structurelib.structure.IStructureDefinition#survivalBuild(Object, ItemStack,
|
||||
String, World, ExtendedFacing, int, int, int, int, int, int, int, IItemSource, EntityPlayerMP, boolean)
|
||||
survivalBuild()}.
|
||||
</p>
|
||||
|
||||
<h2>{@link com.gtnewhorizon.structurelib.alignment.constructable.IConstructableProvider}</h2>
|
||||
<p>
|
||||
This interface should be implemented on tile entities that will delegate all constructable or survival construable
|
||||
functionality to some other class.
|
||||
This is mostly only to support gregtech meta tile entity system.
|
||||
</p>
|
||||
<p>
|
||||
Return null if the delegate does not exist.
|
||||
</p>
|
||||
|
||||
<h2>{@link com.gtnewhorizon.structurelib.util.InventoryUtility}</h2>
|
||||
<p>
|
||||
This class backs the standard implementations of {@link com.gtnewhorizon.structurelib.structure.IItemSource}.
|
||||
You might want to register new inventory provider or inventory extractor there to facilitate survival auto place.
|
||||
</p>
|
||||
|
||||
<h2>{@link com.gtnewhorizon.structurelib.alignment.IAlignmentProvider}, {@link
|
||||
com.gtnewhorizon.structurelib.alignment.IAlignment} and {@link
|
||||
com.gtnewhorizon.structurelib.alignment.IAlignmentLimits}</h2>
|
||||
<p>
|
||||
These interfaces will be used to implement rotation.
|
||||
Provide a framework to rotate the block.
|
||||
You can skip this if you store ExtendedFacing and do rotation in other means.
|
||||
</p>
|
||||
|
||||
<h2>{@link com.gtnewhorizon.structurelib.alignment.constructable.ChannelDataAccessor}</h2>
|
||||
<p>
|
||||
This class contains the accessors for channel data held on a trigger item. See <a href="#channels">below</a> for more
|
||||
information.
|
||||
</p>
|
||||
|
||||
<h2>{@link com.gtnewhorizon.structurelib.StructureLibAPI}</h2>
|
||||
<p>
|
||||
This class contains the low level utility used for implementing new {@link
|
||||
com.gtnewhorizon.structurelib.structure.IStructureElement}.
|
||||
You will also need methods in this class to while implementing rotation.
|
||||
</p>
|
||||
<p>
|
||||
<b>IF THERE IS A SAME NAMED METHOD IN OTHER CLASS, ONLY USE METHODS FOUND IN THIS CLASS, NOT OTHER CLASS.</b>
|
||||
This abstraction is necessary so we can change how underlying code work (e.g. how hint particles are rendered)
|
||||
without
|
||||
breaking client code.
|
||||
</p>
|
||||
|
||||
<h1>Important Concepts</h1>
|
||||
<h2>Context Object</h2>
|
||||
<p>
|
||||
Context Object are what you pass to {@link
|
||||
com.gtnewhorizon.structurelib.structure.IStructureDefinition#check(Object, String, World, ExtendedFacing, int, int,
|
||||
int, int, int, int, boolean)} and alike as first parameter. It will hold the necessary states for {@link
|
||||
com.gtnewhorizon.structurelib.structure.IStructureElement}. It's usually, but not necessarily, the multiblock controller.
|
||||
</p>
|
||||
<p>
|
||||
Standard structure element library offers method to switch context objects if needed.
|
||||
</p>
|
||||
|
||||
<h2>Trigger Item</h2>
|
||||
<p>
|
||||
Trigger Item is the item used to trigger hint spawn, creative build and survival auto place.
|
||||
The trigger item will be passed to relevant classes as an indicator of structure tier.
|
||||
The item type and stack tag compound of this item stack are opaque objects that should not be parsed.
|
||||
</p>
|
||||
<p>
|
||||
StructureLib comes with a trigger item implementation.
|
||||
It does register it to the game registries, but does not come with a recipe.
|
||||
Usually there is no reason to reimplement this on your own.
|
||||
</p>
|
||||
|
||||
<h2><a href="#channels" id="channels">Channels</a></h2>
|
||||
|
||||
<p>
|
||||
Trigger item carries the player's choice of structure tier by its stack size.
|
||||
When one multi have multiple tiered component that can have interleaving tier, this becomes an obnoxious
|
||||
restriction, as one ItemStack cannot have two stack sizes at the same time.
|
||||
Here we use the <i>channels</i> to bypass this restriction.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Basically, channels are information stored on the trigger item's NBT tags.
|
||||
One trigger item can carry multiple channels.
|
||||
Each channel can be identified with <b>lower case</b> strings and has the value being one positive Java int.
|
||||
There will be one and only one master channel and 0 or more sub channel.
|
||||
When a non-existent sub channel is queried, master channel will be used instead to fill its place.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Structure Definition Author and/or Structure Element Author can choose whether they use a channel and which channel
|
||||
to use.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Structure Element Author will usually not need to consider channels, i.e. proceed as if this concept does not exist,
|
||||
unless it must take input from multiple channels.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Structure Definition Author will consider how to map each channel to each tiered component.
|
||||
He will be using `com.gtnewhorizon.structurelib.structure.StructureUtility.withChannel` to direct structure element
|
||||
on which channel to use.
|
||||
Conceptually, it will return an ItemStack with the master channel being the value of selected channel.
|
||||
In implementation, withChannel will return a new ItemStack with same item, nbt but different stack size.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
It's worth mentioning that the returned new ItemStack will still have all the channel data on it, so a multi-channel
|
||||
structure element can still query the channel it wants just fine. It is however impossible to recover the original
|
||||
master channel.
|
||||
</p>
|
||||
|
||||
<h3>why is this called channel?</h3>
|
||||
|
||||
Just give me a better name and I'd do the renaming.
|
||||
|
||||
<h3>Examples</h3>
|
||||
|
||||
<h4>For Structure Definition Author</h4>
|
||||
|
||||
<p>GT++ Chemical Plant is a multi with 4 distinctly tiered component.</p>
|
||||
|
||||
<p>It will use
|
||||
<ul>
|
||||
<li>master channel for its outer shell</li>
|
||||
<li>channel `"casing"` for machine casings</li>
|
||||
<li>channel `"pipe"` for pipe casings</li>
|
||||
<li>channel `"coil"` for heating coils</li>
|
||||
</ul>
|
||||
Its structure code will then look like
|
||||
<pre>
|
||||
.addElement('a', shellStructureElement())
|
||||
.addElement('b', withChannel("casing", machineCasingStructureElement()))
|
||||
.addElement('c', withChannel("pipe", pipeCasingStructureElement()))
|
||||
.addElement('d', withChannel("coil", coilStructureElement()))
|
||||
</pre>
|
||||
whereas all these structure elements are designed without considering channels whatsoever
|
||||
|
||||
<h4> Multi channel input Structure Element</h4>
|
||||
|
||||
<p>
|
||||
Suppose your hatch element has a required facing and can accept arbitrary meta tile entity, so it will need both
|
||||
meta id
|
||||
and facing input.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
It will use
|
||||
<ul>
|
||||
<li>master channel for its facing</li>
|
||||
<li>channel `"id"` for meta tile entity id</li>
|
||||
</ul>
|
||||
<p>
|
||||
Its code will then look like
|
||||
<pre>
|
||||
import com.gtnewhorizon.structurelib.structure.IStructureElement;
|
||||
|
||||
public class MyHatchElement<T> implements IStructureElement<T> {
|
||||
//...
|
||||
@Override
|
||||
public PlaceResult survivalPlaceBlock(
|
||||
Object o,
|
||||
World world,
|
||||
int x,
|
||||
int y,
|
||||
int z,
|
||||
ItemStack trigger,
|
||||
IItemSource s,
|
||||
EntityPlayerMP actor,
|
||||
Consumer chatter) {
|
||||
if (shouldSkip(o, world, x, y, z)) return PlaceResult.SKIP;
|
||||
if (!StructureLibAPI.isBlockTriviallyReplaceable(world, x, y, z, actor)) return PlaceResult.REJECT;
|
||||
ItemStack taken = s.takeOne(filterByID(ChannelDataAccessor.getChannelData(trigger, "id")).andThen(filterByFacing(trigger.stackSize)));
|
||||
if (taken == null) return PlaceResult.REJECT;
|
||||
return StructureUtility.survivalPlaceBlock(taken, ItemStackPredicate.NBTMode.IGNORE, null, true, world, x, y, z, s, actor);
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
|
||||
The code for placeBlock() and spawnHint() will be left as an exercise for the reader.
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
||||
Reference in new issue
Block a user