Compare commits

...
21 Commits
Author SHA1 Message Date
Ruling-0 448406b81f Drop the bartworks werkstoff block lookup 2026-10-12 15:23:58 -05:00
Ruling-0 f5e8fcd0a3 Crate GregTech's MaterialLib parts instead of IndustrialCraft 2 copies 2026-10-12 15:23:57 -05:00
Ruling-0 e78b80e21d Doc and code style pass 2026-10-12 15:23:57 -05:00
Ruling-0 4e430e718b Skip fluid block creation for pre-registered fluids that already have one 2026-10-12 15:23:57 -05:00
Ruling-0 0a2726ac88 Create Forestry fluid blocks for pre-registered fluids except milk 2026-10-12 15:23:56 -05:00
Ruling-0 383b78435d Clean up MaterialLib stack string docs and comments 2026-10-12 15:23:56 -05:00
Ruling-0 c2caa8c0d3 Support ml: MaterialLib entries in stack strings 2026-10-12 15:23:55 -05:00
Ruling-0 cc67010033 Add MaterialLib dependency 2026-10-12 15:23:55 -05:00
Ruling-0 384336f416 Fix bartworks block detection against the unified material system 2026-10-12 15:23:45 -05:00
Ruling-0 96b8f60f87 Remove full-name invocations 2026-10-12 15:23:44 -05:00
Ruling-0 a2a1f8eca9 Transform mail boxes through Postea's custom data API 2026-10-12 15:23:44 -05:00
Worive f2e85073d3 Fix alveary inventory drops on chunk unload (#134) 2026-10-03 12:46:01 -05:00
ABKQPO 0bd9a7978a Expose mutation resource condition values (#135) 2026-09-15 21:06:15 +02:00
boubou19 e47fc90433 reduce allocations of arrays to once per call (#133) 2026-08-25 19:19:42 -04:00
boubou19 452064ef1d More enum .values() caching (#131) 2026-08-14 01:10:34 +02:00
boubou19 59c8c36520 Cache enum .values() (#130) 2026-08-10 20:56:48 +02:00
Ryan Nasers ea1c4edae4 Fixes the display of blocks in NEI for the double slab blocks (#129) 2026-08-10 08:22:57 +07:00
Firewooddoge 4c46626cdb Fix Japanese block names showing as unlocalized .name keys (#128) 2026-08-08 14:30:36 +07:00
Alex VermetteandAlex Vermette d6fa8d8b74 fix: implement stacked block slab (#127)
Co-authored-by: Alex Vermette <[email protected]>
2026-07-27 13:20:40 -04:00
UltraProdigy 704861b666 Delete Forestry CONTRIBUTING.md (#126) 2026-07-04 19:02:06 +00:00
Algent db25dcce48 Dupe Fix - Make bag logic more lag resistant (#121) 2026-07-04 18:57:41 +00:00
22 changed files with 202 additions and 86 deletions

No files matched your search

-29
View File
@@ -1,29 +0,0 @@
How to submit a bug report to Forestry
====================================
Please make sure the bug has not already been reported by [searching the issues](https://github.com/ForestryMC/ForestryMC/issues?q=is%3Aissue).
If you can, see if the bug still happens with the latest unstable build.
[The latest unstable builds are available here](http://jenkins.ic2.player.to/job/Forestry_Dev/)
For crashes, you must post a link to the full crash report.
[gist.github.com](gist.github.com) or [pastebin.com](www.pastebin.com) are good places to upload them.
Full crash reports are located in [the minecraft data folder](http://hopper.minecraft.net/help/finding-minecraft-data-folder/), in "crash-reports".
Thank you for reporting bugs!
How to contribute to Forestry
====================================
### Contributor License Agreement
Before pull requests can be accepted, the contributor needs to sign a contributor license agreement. (Essentially giving a license for using his code and/or media and for re-licensing it, for details read the agreement linked below.)
### How do I sign?
To keep the hassle for everyone involved to a minimum, Forestry uses CLAHub to manage the agreements. To get started, <a href="https://www.clahub.com/agreements/ForestryMC/ForestryMC">sign the Contributor License Agreement</a>.
### Why is this needed?
Without CLAs it at some point becomes essentially impossible to change the license of a project which accepts contributions from third parties. Without an explicit agreement every contributor would still own the copyright to his code. So as long as it (or parts of it) remain in the code base, he would have to agree to every license change. If enough time has passed, there may be dozens, perhaps even hundreds of contributors involved and it will be very hard to track down each and every one of them and get them to agree on a new license.
This would make it impossible to change the license to a more permissive one at a later date, so the code would be locked into CC BY-NC-ND 3.0 until it passes into the public domain about a hundred years from now. This situation is to be avoided and that’s why you are being bothered with this CLA.
+2
View File
@@ -9,5 +9,7 @@ dependencies {
compileOnly('com.github.GTNewHorizons:BuildCraft:7.1.57:api')
compileOnly('net.industrial-craft:industrialcraft-2:2.2.828-experimental:dev')
compileOnly('curse.maven:craftguide-75557:2459320')
compileOnly('com.ruling_0:MaterialLib:0.24.0-mu:dev')
compileOnly('com.github.GTNewHorizons:Postea:1.4.0-mu:dev')
devOnlyNonPublishable('net.xonich.mc:NoHotbarNeeded:0.0.3:dev')
}
+2 -1
View File
@@ -63,7 +63,8 @@ import forestry.plugins.PluginManager;
+ "after:BiomesOPlenty;"
+ "after:IC2@[2.0.140,);"
+ "after:Natura@[2.2.0,);"
+ "after:HardcoreEnderExpansion;")
+ "after:HardcoreEnderExpansion;"
+ "after:materiallib;")
public class Forestry {
@Mod.Instance(Constants.MOD)
@@ -111,6 +111,14 @@ public class AlvearyController extends RectangularMultiblockControllerBase
this.readFromNBT(data);
}
@Override
public void detachBlock(IMultiblockComponent part, boolean chunkUnloading) {
if (!chunkUnloading) {
inventory.dumpInventoryIntoWorld(this.worldObj, part.getCoordinates());
}
super.detachBlock(part, chunkUnloading);
}
@Override
protected void onBlockAdded(IMultiblockComponent newPart) {
if (newPart instanceof IAlvearyComponent) {
@@ -159,8 +167,6 @@ public class AlvearyController extends RectangularMultiblockControllerBase
activeComponents.remove(oldPart);
}
}
inventory.dumpInventoryIntoWorld(this.worldObj, oldPart.getCoordinates());
}
@Override
@@ -16,8 +16,8 @@ import net.minecraft.block.material.Material;
import net.minecraft.client.particle.EffectRenderer;
import net.minecraft.client.renderer.texture.IIconRegister;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
@@ -72,7 +72,7 @@ public class BlockSlab extends net.minecraft.block.BlockSlab implements IWoodTyp
@SideOnly(Side.CLIENT)
@Override
public IIcon getIcon(int side, int meta) {
return IconProviderWood.getPlankIcon(EnumWoodType.LARCH);
return IconProviderWood.getPlankIcon(EnumWoodType.VALUES[meta]);
}
@Override
@@ -84,7 +84,8 @@ public class BlockSlab extends net.minecraft.block.BlockSlab implements IWoodTyp
@Override
protected ItemStack createStackedBlock(int meta) {
return new ItemStack(Blocks.wooden_slab, 2, meta & 7);
Item item = Item.getItemFromBlock(this);
return item != null ? new ItemStack(item, 2, 0) : null;
}
@Override
@@ -107,6 +108,18 @@ public class BlockSlab extends net.minecraft.block.BlockSlab implements IWoodTyp
return new TileWood();
}
@Override
public void onBlockPlacedBy(World world, int x, int y, int z, EntityLivingBase entity, ItemStack stack) {
// Special case for double slabs placed by building mods (e.g., MatterManipulator)
if (stack == null) return;
int damage = stack.getItemDamage();
if (damage < 0 || damage >= EnumWoodType.VALUES.length) return;
TileWood tile = TileWood.getWoodTile(world, x, y, z);
if (tile != null) {
tile.setWoodType(EnumWoodType.VALUES[damage]);
}
}
/* PROPERTIES */
@Override
public final ItemStack getPickBlock(MovingObjectPosition target, World world, int x, int y, int z) {
@@ -202,7 +202,8 @@ public abstract class Genome implements IGenome {
private static IChromosome[] getChromosomes(NBTTagCompound genomeNBT, ISpeciesRoot speciesRoot) {
NBTTagList chromosomesNBT = genomeNBT.getTagList("Chromosomes", 10);
IChromosome[] chromosomes = new IChromosome[speciesRoot.getDefaultTemplate().length];
IAllele[] defaultTemplate = speciesRoot.getDefaultTemplate();
IChromosome[] chromosomes = new IChromosome[defaultTemplate.length];
for (int i = 0; i < chromosomesNBT.tagCount(); i++) {
NBTTagCompound chromosomeNBT = chromosomesNBT.getCompoundTagAt(i);
@@ -213,7 +214,7 @@ public abstract class Genome implements IGenome {
chromosomes[chromosomeOrdinal] = chromosome;
if (Config.clearInvalidChromosomes) {
IAllele template = speciesRoot.getDefaultTemplate()[chromosomeOrdinal];
IAllele template = defaultTemplate[chromosomeOrdinal];
Class<? extends IAllele> chromosomeClass = speciesRoot.getKaryotype()[chromosomeOrdinal]
.getAlleleClass();
if (chromosome.overrideInvalidAlleles(template, chromosomeClass)) {
@@ -32,6 +32,10 @@ public class MutationConditionRequiresResource implements IMutationCondition {
blockRequired = new ItemStack(block, 1, meta);
}
public ItemStack getBlockRequired() {
return blockRequired.copy();
}
@Override
public float getChance(World world, int x, int y, int z, IAllele allele0, IAllele allele1, IGenome genome0,
IGenome genome1, IClimateProvider climate) {
@@ -39,6 +39,10 @@ public class MutationConditionRequiresResourceOreDict implements IMutationCondit
}
}
public int getOreDictId() {
return oreDictId;
}
@Override
public float getChance(World world, int x, int y, int z, IAllele allele0, IAllele allele1, IGenome genome0,
IGenome genome1, IClimateProvider climate) {
@@ -87,7 +87,7 @@ public abstract class ItemInventory implements IInventory, IFilterSlotDelegate {
public boolean isParentItemEquipped() {
return switch (location.type()) {
case HELD_BY_PLAYER, UNKNOWN -> isSameItemInventory(player.getCurrentEquippedItem(), parent);
case PLAYER_INVENTORY -> true;
case PLAYER_INVENTORY -> isSameItemInventory(player.inventory.getStackInSlot(location.slotIdx()), parent);
};
}
@@ -95,6 +95,10 @@ public abstract class ItemInventory implements IInventory, IFilterSlotDelegate {
return player;
}
public ItemLocation getLocation() {
return location;
}
public boolean isParentItemInventory(ItemStack itemStack) {
ItemStack parent = getParent();
return isSameItemInventory(parent, itemStack);
@@ -33,7 +33,7 @@ public abstract class ItemWithGui extends ItemForestry implements IGuiHandlerIte
}
protected void openGui(EntityPlayer entityplayer) {
GuiHandler.openGui(entityplayer, this);
GuiHandler.openGui(entityplayer, this, (short) 0, entityplayer.inventory.currentItem);
}
@Override
@@ -230,23 +230,11 @@ public abstract class BlockUtil {
return vec != null && (vec.xCoord >= minX && vec.xCoord <= maxX && vec.yCoord >= minY && vec.yCoord <= maxY);
}
private static Class<? extends Block> BW_MetaGenerated_WerkstoffBlocksClass;
private static Block BWBlocks;
private static Class<? extends Block> GTBlockMachines_Class;
private static Block GTBlockMachines;
private static final boolean bw = Loader.isModLoaded("bartworks");
private static final boolean gt = Loader.isModLoaded("gregtech") && !Loader.isModLoaded("gregapi");
static {
if (bw) try {
// noinspection unchecked
BW_MetaGenerated_WerkstoffBlocksClass = (Class<? extends Block>) Class
.forName("bartworks.system.material.BWMetaGeneratedWerkstoffBlocks");
BWBlocks = (Block) Class.forName("bartworks.system.material.WerkstoffLoader").getField("BWBlocks")
.get(null);
} catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
if (gt) try {
// noinspection unchecked
GTBlockMachines_Class = (Class<? extends Block>) Class.forName("gregtech.common.blocks.BlockMachines");
@@ -268,12 +256,6 @@ public abstract class BlockUtil {
} while (stillInside.test(tile));
block = world.getBlock(x, y - depth, z);
if (bw && BW_MetaGenerated_WerkstoffBlocksClass != null
&& BWBlocks != null
&& BW_MetaGenerated_WerkstoffBlocksClass.isInstance(block)) {
return new ItemStack(BWBlocks, 1, block.getDamageValue(world, x, y - depth, z));
}
if (gt && GTBlockMachines_Class != null && GTBlockMachines != null && GTBlockMachines_Class.isInstance(block)) {
return new ItemStack(GTBlockMachines, 1, block.getDamageValue(world, x, y - depth, z));
}
@@ -0,0 +1,42 @@
package forestry.core.utils;
import net.minecraft.item.ItemStack;
import com.ruling_0.materiallib.api.StackResolver;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.registry.GameRegistry.UniqueIdentifier;
/// Resolves the `ml:<Material>:<shape>` stack string form, which names a MaterialLib item by material and shape.
///
/// MaterialLib types are named only here, so [Stack] can gate loading this class on `materiallib` being present.
public abstract class MaterialLibStacks {
public static Stack parse(String mlString) {
String[] parts = mlString.split(":+");
if (parts.length != 3) {
Log.warning(
"Stack string (" + mlString
+ ") isn't formatted properly. The MaterialLib format is ml:<Material>:<shape>, e.g. ml:Aluminium:ore_stone");
return null;
}
ItemStack stack = StackResolver.getStack(parts[1], parts[2], 1);
if (stack == null) {
return null;
}
UniqueIdentifier id = GameRegistry.findUniqueIdentifierFor(stack.getItem());
if (id == null) {
Log.warning("Stack string (" + mlString + ") resolved to an item with no registry name.");
return null;
}
return new Stack(id.toString(), stack.getItemDamage());
}
/// The named material's item in the named shape, or null when MaterialLib serves no such pair.
public static ItemStack getStack(String material, String shape) {
return StackResolver.getStack(material, shape, 1);
}
}
@@ -0,0 +1,38 @@
package forestry.core.utils;
import net.minecraft.nbt.NBTTagCompound;
import com.gtnewhorizons.postea.api.CustomDataReplacementManager;
import cpw.mods.fml.common.Loader;
/// Offers Forestry's mail boxes to Postea's custom world data API, so versioned transformers rewrite
/// their stacks exactly once per content version change. Safe to call without Postea installed: the Postea types
/// live in the inner holder, which only loads when the mod is present.
public final class PosteaCompat {
private static final boolean POSTEA = Loader.isModLoaded("postea");
private PosteaCompat() {}
/// Transforms a root read from disk in place; call before consuming it.
public static void transform(String storageId, NBTTagCompound root) {
if (POSTEA) Impl.transform(storageId, root);
}
/// Stamps a freshly built root about to be written to disk.
public static void stamp(NBTTagCompound root) {
if (POSTEA) Impl.stamp(root);
}
private static final class Impl {
static void transform(String storageId, NBTTagCompound root) {
CustomDataReplacementManager.transform(storageId, root);
}
static void stamp(NBTTagCompound root) {
CustomDataReplacementManager.stamp(root);
}
}
}
+9 -1
View File
@@ -58,12 +58,20 @@ public class Stack {
return null;
}
if (stackString.startsWith("ml:")) {
if (!ModUtil.isModLoaded("materiallib")) {
Log.warning("Stack string (" + stackString + ") needs MaterialLib, which is not loaded. Ignoring it.");
return null;
}
return MaterialLibStacks.parse(stackString);
}
String[] parts = stackString.split(":+");
if (parts.length != 2 && parts.length != 3) {
Log.warning(
"Stack string (" + stackString
+ ") isn't formatted properly. Suitable formats are <modId>:<name>, <modId>:<name>:<meta> or <modId>:<name>:*, e.g. IC2:blockWall:*");
+ ") isn't formatted properly. Suitable formats are <modId>:<name>, <modId>:<name>:<meta>, <modId>:<name>:* or ml:<Material>:<shape>, e.g. IC2:blockWall:*");
return null;
}
@@ -25,16 +25,22 @@ import forestry.plugins.PluginMail;
public class LetterProperties {
private enum State {
FRESH,
STAMPED,
OPENED,
EMPTIED
EMPTIED;
public static final State[] VALUES = values();
}
private enum Size {
EMPTY,
SMALL,
BIG
BIG;
public static final Size[] VALUES = values();
}
public static ItemStack createStampedLetterStack(ILetter letter) {
@@ -98,8 +104,8 @@ public class LetterProperties {
@SuppressWarnings("unchecked")
public static void getSubItems(Item item, CreativeTabs tab, @SuppressWarnings("rawtypes") List list) {
for (State state : State.values()) {
for (Size size : Size.values()) {
for (State state : State.VALUES) {
for (Size size : Size.VALUES) {
int meta = encodeMeta(state, size);
ItemStack letter = new ItemStack(item, 1, meta);
list.add(letter);
@@ -117,7 +123,7 @@ public class LetterProperties {
private static State getState(int meta) {
int ordinal = meta & 0x0f;
State[] values = State.values();
State[] values = State.VALUES;
if (ordinal >= values.length) {
ordinal = 0;
}
@@ -126,7 +132,7 @@ public class LetterProperties {
private static Size getSize(int meta) {
int ordinal = meta >> 4;
Size[] values = Size.values();
Size[] values = Size.VALUES;
if (ordinal >= values.length) {
ordinal = 0;
}
+3
View File
@@ -19,6 +19,7 @@ import forestry.api.mail.IMailAddress;
import forestry.api.mail.PostManager;
import forestry.core.inventory.InventoryAdapter;
import forestry.core.utils.InventoryUtil;
import forestry.core.utils.PosteaCompat;
public class POBox extends WorldSavedData implements IInventory {
@@ -42,6 +43,7 @@ public class POBox extends WorldSavedData implements IInventory {
@Override
public void readFromNBT(NBTTagCompound nbttagcompound) {
PosteaCompat.transform("forestry:" + mapName, nbttagcompound);
if (nbttagcompound.hasKey("address")) {
this.address = MailAddress.loadFromNBT(nbttagcompound.getCompoundTag("address"));
}
@@ -56,6 +58,7 @@ public class POBox extends WorldSavedData implements IInventory {
nbttagcompound.setTag("address", nbt);
}
letters.writeToNBT(nbttagcompound);
PosteaCompat.stamp(nbttagcompound);
}
public boolean storeLetter(ItemStack letterstack) {
@@ -59,14 +59,25 @@ public class PluginFluids extends ForestryPlugin {
public static ItemRegistryFluids items;
private static void createFluid(Fluids forestryFluid) {
if (forestryFluid.getFluid() == null && Config.isFluidEnabled(forestryFluid)) {
String fluidName = forestryFluid.getTag();
if (!FluidRegistry.isFluidRegistered(fluidName)) {
Fluid fluid = new Fluid(fluidName).setDensity(forestryFluid.getDensity())
.setViscosity(forestryFluid.getViscosity()).setTemperature(forestryFluid.getTemperature());
FluidRegistry.registerFluid(fluid);
createBlock(forestryFluid);
}
if (!Config.isFluidEnabled(forestryFluid)) {
return;
}
String fluidName = forestryFluid.getTag();
boolean preRegistered = FluidRegistry.isFluidRegistered(fluidName);
if (!preRegistered) {
Fluid fluid = new Fluid(fluidName).setDensity(forestryFluid.getDensity())
.setViscosity(forestryFluid.getViscosity()).setTemperature(forestryFluid.getTemperature());
FluidRegistry.registerFluid(fluid);
}
// Milk is deliberately left blockless once another mod owns the fluid.
if (preRegistered && (forestryFluid == Fluids.MILK || forestryFluid.getBlock() != null)) {
return;
}
if (forestryFluid.getFluid() != null) {
createBlock(forestryFluid);
}
}
@@ -48,6 +48,7 @@ import forestry.core.items.EnumElectronTube;
import forestry.core.recipes.RecipeUtil;
import forestry.core.utils.ItemStackUtil;
import forestry.core.utils.Log;
import forestry.core.utils.MaterialLibStacks;
import forestry.core.utils.ModUtil;
import forestry.energy.blocks.BlockEngineType;
import forestry.energy.blocks.BlockRegistryEnergy;
@@ -227,7 +228,7 @@ public class PluginIC2 extends ForestryPlugin {
}
if (rubber != null) {
crateRegistry.registerCrate(rubber, "cratedRubber");
crateRegistry.registerCrate(cratedPart(rubber, "Rubber", "ingot"), "cratedRubber");
}
if (scrap != null) {
@@ -239,14 +240,24 @@ public class PluginIC2 extends ForestryPlugin {
}
if (silver != null) {
crateRegistry.registerCrateUsingOreDict(silver, "cratedSilver");
crateRegistry.registerCrateUsingOreDict(cratedPart(silver, "Silver", "ingot"), "cratedSilver");
}
if (brass != null) {
crateRegistry.registerCrateUsingOreDict(brass, "cratedBrass");
crateRegistry.registerCrateUsingOreDict(cratedPart(brass, "Bronze", "ingot"), "cratedBrass");
}
}
/// GregTech's MaterialLib part in place of IndustrialCraft 2's copy of it, so uncrating hands out the part that
/// GregTech's recipes produce.
private static ItemStack cratedPart(ItemStack ic2Part, String material, String shape) {
if (!ModUtil.isModLoaded("gregtech")) {
return ic2Part;
}
ItemStack part = MaterialLibStacks.getStack(material, shape);
return part != null ? part : ic2Part;
}
@Optional.Method(modid = "IC2")
protected void registerRecipes() {
@@ -28,6 +28,11 @@ public class ItemInventoryBackpackPaged extends ItemInventoryBackpack implements
@Override
public void flipPage(EntityPlayer player, short page) {
GuiHandler.openGui(player, backpackNaturalist, page);
ItemLocation loc = getLocation();
if (loc.type() == ItemLocation.Type.PLAYER_INVENTORY) {
GuiHandler.openGui(player, backpackNaturalist, page, loc.slotIdx());
} else {
GuiHandler.openGui(player, backpackNaturalist, page);
}
}
}
@@ -72,7 +72,7 @@ public class ItemBackpack extends ItemWithGui implements ActivatableFromInventor
@Override
protected void openGui(EntityPlayer entityplayer) {
GuiHandler.openGui(entityplayer, this, (short) type.ordinal());
GuiHandler.openGui(entityplayer, this, (short) type.ordinal(), entityplayer.inventory.currentItem);
}
@Override
@@ -34,7 +34,7 @@ public class ItemBackpackNaturalist extends ItemBackpack {
@Override
protected void openGui(EntityPlayer entityplayer) {
GuiHandler.openGui(entityplayer, this);
GuiHandler.openGui(entityplayer, this, (short) 0, entityplayer.inventory.currentItem);
}
@Override
@@ -501,10 +501,10 @@ tile.for.log1=原木
tile.for.log2=原木
tile.for.log3=原木
tile.for.log4=原木
tile.for.planks=木材
tile.for.planks.name=木材
tile.for.slabs1=木材ハーフブロック
tile.for.slabs2=木材ハーフブロック
tile.for.fences=フェンス
tile.for.fences.name=フェンス
tile.harvester.0=伐採機
tile.harvester.1=収穫機
tile.harvester.2=ゴムの木収穫機
@@ -757,9 +757,11 @@ tile.candle.dyed.stump=Unlit Dyed Candle
tile.candle.lit=Lit Candle
tile.candle.dyed.lit=Lit Dyed Candle
tile.stump.0=Candle Stump
tile.for.apiculture.0=Apiary
tile.for.apiculture.1=Apiarist's Chest
tile.for.apiculture.2=Bee House
tile.for.apiculture.name=養蜂箱
tile.for.apiculture.0.name=養蜂箱
tile.for.apicultureChest.name=養蜂家のチェスト
tile.for.apicultureChest.0.name=養蜂家のチェスト
tile.for.apiculture.2.name=ビーハウス
item.for.beeQueenGE.name=Unknown Queen
####################
@@ -808,7 +810,7 @@ tile.log=Wood
tile.planks=Wood Planks
tile.slab=Wood Slab
tile.fences=Fence
tile.for.stairs=Stairs
tile.for.stairs.name=階段
wood.0=Larch
wood.1=Teak
wood.2=Acacia
@@ -833,7 +835,8 @@ wood.20=Pine
wood.21=Plum
wood.22=Maple
wood.23=Citrus
tile.for.arboriculture.0=Arborist's Chest
tile.for.arboriculture.name=樹医のチェスト
tile.for.arboriculture.0.name=樹医のチェスト
####################
# FARMING
@@ -906,7 +909,8 @@ item.butterfly=Butterfly
item.moth=Moth
item.flutterlyzer=Flutterlyzer
storage.backpack.lepidopterist=Lepidopterist's Backpack
tile.for.lepidopterology.0=Lepidopterist's Chest
tile.for.lepidopterology.name=鱗翅類学者のチェスト
tile.for.lepidopterology.0.name=鱗翅類学者のチェスト
####################
# MAIL