Skip to content

Commit 2910038

Browse files
committedDec 15, 2015
Merge branch 'master' of github.com:MightyPirates/TIS-3D into master-MC1.7.10
Conflicts: src/main/java/li/cil/tis3d/client/render/TextureLoader.java src/main/java/li/cil/tis3d/client/render/tile/TileEntitySpecialRendererCasing.java src/main/java/li/cil/tis3d/common/ProxyCommon.java
2 parents aa8ba54 + 27c47a6 commit 2910038

File tree

13 files changed

+233
-3
lines changed

13 files changed

+233
-3
lines changed
 

‎src/main/java/li/cil/tis3d/client/render/TextureLoader.java

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ public final class TextureLoader {
1010
public static final ResourceLocation LOCATION_MODULE_EXECUTION_OVERLAY_ERROR = new ResourceLocation(API.MOD_ID, "overlay/moduleExecutionError");
1111
public static final ResourceLocation LOCATION_MODULE_EXECUTION_OVERLAY_RUNNING = new ResourceLocation(API.MOD_ID, "overlay/moduleExecutionRunning");
1212
public static final ResourceLocation LOCATION_MODULE_EXECUTION_OVERLAY_WAITING = new ResourceLocation(API.MOD_ID, "overlay/moduleExecutionWaiting");
13+
public static final ResourceLocation LOCATION_MODULE_AUDIO_OVERLAY = new ResourceLocation(API.MOD_ID, "overlay/moduleAudio");
1314
public static final ResourceLocation LOCATION_MODULE_INFRARED_OVERLAY = new ResourceLocation(API.MOD_ID, "overlay/moduleInfrared");
1415
public static final ResourceLocation LOCATION_MODULE_RANDOM_OVERLAY = new ResourceLocation(API.MOD_ID, "overlay/moduleRandom");
1516
private static final ResourceLocation LOCATION_CASING_MODULE = new ResourceLocation(API.MOD_ID, "casingModule");
@@ -26,6 +27,7 @@ public void onTextureStitchPre(final TextureStitchEvent.Pre event) {
2627
event.map.registerIcon(LOCATION_MODULE_EXECUTION_OVERLAY_ERROR.toString());
2728
event.map.registerIcon(LOCATION_MODULE_EXECUTION_OVERLAY_RUNNING.toString());
2829
event.map.registerIcon(LOCATION_MODULE_EXECUTION_OVERLAY_WAITING.toString());
30+
event.map.registerIcon(LOCATION_MODULE_AUDIO_OVERLAY.toString());
2931
event.map.registerIcon(LOCATION_MODULE_INFRARED_OVERLAY.toString());
3032
event.map.registerIcon(LOCATION_MODULE_RANDOM_OVERLAY.toString());
3133
ICON_CASING_MODULE = event.map.registerIcon(LOCATION_CASING_MODULE.toString());

‎src/main/java/li/cil/tis3d/client/render/tile/TileEntitySpecialRendererCasing.java

+14
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@
44
import li.cil.tis3d.api.module.Module;
55
import li.cil.tis3d.common.TIS3D;
66
import li.cil.tis3d.common.tile.TileEntityCasing;
7+
import net.minecraft.client.renderer.OpenGlHelper;
8+
import net.minecraft.client.renderer.RenderHelper;
79
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
810
import net.minecraft.tileentity.TileEntity;
11+
import net.minecraft.util.EnumFacing;
912
import org.lwjgl.opengl.GL11;
1013

1114
import java.util.HashSet;
@@ -64,13 +67,24 @@ public void renderTileEntityAt(final TileEntity tileEntity, final double x, fina
6467
GL11.glTranslatef(0.5f, 0.5f, -0.505f);
6568
GL11.glScalef(-1, -1, 1);
6669

70+
final EnumFacing facing = Face.toEnumFacing(face);
71+
final int neighborX = casing.getPositionX() + facing.getFrontOffsetX();
72+
final int neighborY = casing.getPositionY() + facing.getFrontOffsetY();
73+
final int neighborZ = casing.getPositionZ() + facing.getFrontOffsetZ();
74+
final int brightness = casing.getWorldObj().getLightBrightnessForSkyBlocks(neighborX, neighborY, neighborZ, 0);
75+
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, brightness % 65536, brightness / 65536);
76+
77+
RenderHelper.disableStandardItemLighting();
78+
6779
try {
6880
module.render(casing.isEnabled(), partialTicks);
6981
} catch (final Exception e) {
7082
BLACKLIST.add(module.getClass());
7183
TIS3D.getLog().error("A module threw an exception while rendering, won't render again!", e);
7284
}
7385

86+
RenderHelper.enableStandardItemLighting();
87+
7488
GL11.glPopMatrix();
7589
}
7690

‎src/main/java/li/cil/tis3d/common/Constants.java

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public final class Constants {
1919
public static final String NAME_BLOCK_CONTROLLER = "controller";
2020
public static final String NAME_ITEM_BOOK_CODE = "bookCode";
2121
public static final String NAME_ITEM_BOOK_MANUAL = "bookManual";
22+
public static final String NAME_ITEM_MODULE_AUDIO = "moduleAudio";
2223
public static final String NAME_ITEM_MODULE_EXECUTION = "moduleExecution";
2324
public static final String NAME_ITEM_MODULE_INFRARED = "moduleInfrared";
2425
public static final String NAME_ITEM_MODULE_REDSTONE = "moduleRedstone";

‎src/main/java/li/cil/tis3d/common/ProxyCommon.java

+12
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import li.cil.tis3d.common.item.ItemBookManual;
2424
import li.cil.tis3d.common.item.ItemModule;
2525
import li.cil.tis3d.common.network.Network;
26+
import li.cil.tis3d.common.provider.ModuleProviderAudio;
2627
import li.cil.tis3d.common.provider.ModuleProviderExecution;
2728
import li.cil.tis3d.common.provider.ModuleProviderInfrared;
2829
import li.cil.tis3d.common.provider.ModuleProviderRandom;
@@ -79,6 +80,7 @@ public void onPreInit(final FMLPreInitializationEvent event) {
7980
registerBlock(Constants.NAME_BLOCK_CASING, BlockCasing::new, TileEntityCasing.class);
8081
registerBlock(Constants.NAME_BLOCK_CONTROLLER, BlockController::new, TileEntityController.class);
8182

83+
registerModule(Constants.NAME_ITEM_MODULE_AUDIO);
8284
registerModule(Constants.NAME_ITEM_MODULE_EXECUTION);
8385
registerModule(Constants.NAME_ITEM_MODULE_INFRARED);
8486
registerModule(Constants.NAME_ITEM_MODULE_RANDOM);
@@ -96,6 +98,7 @@ public void onInit(final FMLInitializationEvent event) {
9698
OreDictionary.registerOre("book", GameRegistry.findItem(API.MOD_ID, Constants.NAME_ITEM_BOOK_CODE));
9799
OreDictionary.registerOre("book", GameRegistry.findItem(API.MOD_ID, Constants.NAME_ITEM_BOOK_MANUAL));
98100

101+
OreDictionary.registerOre(API.MOD_ID + ":module", GameRegistry.findItem(API.MOD_ID, Constants.NAME_ITEM_MODULE_AUDIO));
99102
OreDictionary.registerOre(API.MOD_ID + ":module", GameRegistry.findItem(API.MOD_ID, Constants.NAME_ITEM_MODULE_EXECUTION));
100103
OreDictionary.registerOre(API.MOD_ID + ":module", GameRegistry.findItem(API.MOD_ID, Constants.NAME_ITEM_MODULE_INFRARED));
101104
OreDictionary.registerOre(API.MOD_ID + ":module", GameRegistry.findItem(API.MOD_ID, Constants.NAME_ITEM_MODULE_RANDOM));
@@ -118,6 +121,14 @@ public void onInit(final FMLInitializationEvent event) {
118121
'R', "dustRedstone",
119122
'D', "gemDiamond"));
120123

124+
GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(GameRegistry.findItem(API.MOD_ID, Constants.NAME_ITEM_MODULE_AUDIO), 2),
125+
"PPP",
126+
"INI",
127+
" R ",
128+
'P', "paneGlassColorless",
129+
'I', "ingotIron",
130+
'R', "dustRedstone",
131+
'N', Blocks.noteblock));
121132
GameRegistry.addRecipe(new ShapedOreRecipe(new ItemStack(GameRegistry.findItem(API.MOD_ID, Constants.NAME_ITEM_MODULE_EXECUTION), 2),
122133
"PPP",
123134
"IGI",
@@ -169,6 +180,7 @@ public void onInit(final FMLInitializationEvent event) {
169180
FMLCommonHandler.instance().bus().register(TickHandlerInfraredPacket.INSTANCE);
170181

171182
// Register providers for built-in modules.
183+
ModuleAPI.addProvider(new ModuleProviderAudio());
172184
ModuleAPI.addProvider(new ModuleProviderExecution());
173185
ModuleAPI.addProvider(new ModuleProviderInfrared());
174186
ModuleAPI.addProvider(new ModuleProviderStack());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
package li.cil.tis3d.common.module;
2+
3+
import cpw.mods.fml.common.network.NetworkRegistry;
4+
import cpw.mods.fml.relauncher.Side;
5+
import cpw.mods.fml.relauncher.SideOnly;
6+
import li.cil.tis3d.api.machine.Casing;
7+
import li.cil.tis3d.api.machine.Face;
8+
import li.cil.tis3d.api.machine.Pipe;
9+
import li.cil.tis3d.api.machine.Port;
10+
import li.cil.tis3d.api.prefab.module.AbstractModule;
11+
import li.cil.tis3d.api.util.RenderUtil;
12+
import li.cil.tis3d.client.render.TextureLoader;
13+
import li.cil.tis3d.common.network.Network;
14+
import li.cil.tis3d.common.network.message.MessageParticleEffect;
15+
import net.minecraft.client.Minecraft;
16+
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
17+
import net.minecraft.client.renderer.texture.TextureMap;
18+
import net.minecraft.util.EnumFacing;
19+
import net.minecraft.world.World;
20+
import net.minecraftforge.common.MinecraftForge;
21+
import net.minecraftforge.event.world.NoteBlockEvent;
22+
import org.lwjgl.opengl.GL11;
23+
24+
/**
25+
* The audio module, emitting sounds like none other.
26+
*/
27+
public final class ModuleAudio extends AbstractModule {
28+
// --------------------------------------------------------------------- //
29+
// Computed data
30+
31+
/**
32+
* Resolve instrument ID to name of sound used for instrument.
33+
*/
34+
private static final String[] INSTRUMENT_SOUND_NAMES = new String[]{"note.harp", "note.bd", "note.snare", "note.hat", "note.bassattack"};
35+
36+
/**
37+
* The last tick we made a sound. Used to avoid emitting multiple sounds
38+
* per tick when overclocked, because that could quickly spam a lot of
39+
* packets, and sound horrible, too.
40+
*/
41+
private long lastStep = 0L;
42+
43+
// --------------------------------------------------------------------- //
44+
45+
public ModuleAudio(final Casing casing, final Face face) {
46+
super(casing, face);
47+
}
48+
49+
// --------------------------------------------------------------------- //
50+
// Module
51+
52+
@Override
53+
public void step() {
54+
stepInput();
55+
56+
lastStep = getCasing().getCasingWorld().getTotalWorldTime();
57+
}
58+
59+
@SideOnly(Side.CLIENT)
60+
@Override
61+
public void render(final boolean enabled, final float partialTicks) {
62+
if (!enabled) {
63+
return;
64+
}
65+
66+
GL11.glEnable(GL11.GL_BLEND);
67+
68+
Minecraft.getMinecraft().getTextureManager().bindTexture(TextureMap.locationBlocksTexture);
69+
final TextureAtlasSprite icon = Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite(TextureLoader.LOCATION_MODULE_AUDIO_OVERLAY.toString());
70+
RenderUtil.drawQuad(icon.getMinU(), icon.getMinV(), icon.getMaxU(), icon.getMaxV());
71+
72+
GL11.glDisable(GL11.GL_BLEND);
73+
}
74+
75+
// --------------------------------------------------------------------- //
76+
77+
/**
78+
* Update the input of the module, reading the type of note to play.
79+
*/
80+
private void stepInput() {
81+
for (final Port port : Port.VALUES) {
82+
// Continuously read from all ports, emit packet when receiving a value.
83+
final Pipe receivingPipe = getCasing().getReceivingPipe(getFace(), port);
84+
if (!receivingPipe.isReading()) {
85+
receivingPipe.beginRead();
86+
}
87+
if (receivingPipe.canTransfer()) {
88+
// Don't actually read more values if we already sent a packet this tick.
89+
if (getCasing().getCasingWorld().getTotalWorldTime() > lastStep) {
90+
playNote(receivingPipe.read());
91+
92+
// Start reading again right away to read as fast as possible.
93+
receivingPipe.beginRead();
94+
}
95+
}
96+
}
97+
}
98+
99+
/**
100+
* Decode the specified value into instrument, note and volume and play it.
101+
*
102+
* @param value the value defining the sound to play.
103+
*/
104+
private void playNote(final int value) {
105+
final int noteId = (value & 0xFF00) >>> 8;
106+
final int volume = Math.min(4, (value & 0x00F0) >>> 4);
107+
final int instrumentId = value & 0x000F;
108+
109+
// Skip mute sounds.
110+
if (volume < 1) {
111+
return;
112+
}
113+
114+
// Send event to check if the sound may be played / should be modulated.
115+
final World world = getCasing().getCasingWorld();
116+
final int posX = getCasing().getPositionX();
117+
final int posY = getCasing().getPositionY();
118+
final int posZ = getCasing().getPositionZ();
119+
final NoteBlockEvent.Play event = new NoteBlockEvent.Play(world, posX, posY, posZ, world.getBlockMetadata(posX, posY, posZ), noteId, instrumentId);
120+
if (!MinecraftForge.EVENT_BUS.post(event)) {
121+
// Not cancelled, get pitch, sound effect name.
122+
final int note = event.getVanillaNoteId();
123+
final float pitch = (float) Math.pow(2, (note - 12) / 12.0);
124+
final String sound = INSTRUMENT_SOUND_NAMES[event.instrument.ordinal()];
125+
126+
// Offset to have the actual origin be in front of the module.
127+
final EnumFacing facing = Face.toEnumFacing(getFace());
128+
final double x = posX + 0.5 + facing.getFrontOffsetX() * 0.6;
129+
final double y = posY + 0.5 + facing.getFrontOffsetY() * 0.6;
130+
final double z = posZ + 0.5 + facing.getFrontOffsetZ() * 0.6;
131+
132+
// Let there be sound!
133+
world.playSoundEffect(x, y, z, sound, volume, pitch);
134+
final MessageParticleEffect message = new MessageParticleEffect(world, "note", x, y, z);
135+
final NetworkRegistry.TargetPoint target = Network.getTargetPoint(world, x, y, z, Network.RANGE_LOW);
136+
Network.INSTANCE.getWrapper().sendToAllAround(message, target);
137+
}
138+
}
139+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package li.cil.tis3d.common.provider;
2+
3+
import cpw.mods.fml.common.registry.GameRegistry;
4+
import li.cil.tis3d.api.API;
5+
import li.cil.tis3d.api.machine.Casing;
6+
import li.cil.tis3d.api.machine.Face;
7+
import li.cil.tis3d.api.module.Module;
8+
import li.cil.tis3d.api.module.ModuleProvider;
9+
import li.cil.tis3d.common.Constants;
10+
import li.cil.tis3d.common.module.ModuleAudio;
11+
import net.minecraft.item.Item;
12+
import net.minecraft.item.ItemStack;
13+
14+
/**
15+
* The provider for the audio module.
16+
*/
17+
public final class ModuleProviderAudio implements ModuleProvider {
18+
private final Item item = GameRegistry.findItem(API.MOD_ID, Constants.NAME_ITEM_MODULE_AUDIO);
19+
20+
@Override
21+
public boolean worksWith(final ItemStack stack, final Casing casing, final Face face) {
22+
return stack.getItem() == item;
23+
}
24+
25+
@Override
26+
public Module createModule(final ItemStack stack, final Casing casing, final Face face) {
27+
return new ModuleAudio(casing, face);
28+
}
29+
}

‎src/main/java/li/cil/tis3d/common/tile/TileEntityController.java

+10-3
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,8 @@ private void scan() {
252252
final Set<TileEntity> processed = new HashSet<>();
253253
// List of pending tile entities that still need to be scanned.
254254
final Queue<TileEntity> queue = new ArrayDeque<>();
255+
// List of new found casings.
256+
final List<TileEntityCasing> newCasings = new ArrayList<>(Settings.maxCasingsPerController);
255257

256258
// Start at our location, keep going until there's nothing left to do.
257259
processed.add(this);
@@ -275,19 +277,24 @@ private void scan() {
275277
}
276278
} else /* if (tileEntity instanceof TileEntityCasing) */ {
277279
// We only allow a certain number of casings per multi-block.
278-
if (casings.size() + 1 > Settings.maxCasingsPerController) {
280+
if (newCasings.size() + 1 > Settings.maxCasingsPerController) {
279281
clear(ControllerState.TOO_COMPLEX);
280282
return;
281283
}
282284

283285
// Register as the controller with the casing and add neighbors.
284286
final TileEntityCasing casing = (TileEntityCasing) tileEntity;
285287
casing.setController(this);
286-
casings.add(casing);
288+
newCasings.add(casing);
287289
addNeighbors(casing, processed, queue);
288290
}
289291
}
290292

293+
// Replace old list of casings with the new found ones, now that we're
294+
// sure we don't have to disable our old ones.
295+
casings.clear();
296+
casings.addAll(newCasings);
297+
291298
// Ensure our casings know their neighbors.
292299
casings.forEach(TileEntityCasing::checkNeighbors);
293300

@@ -345,7 +352,7 @@ private void clear(final ControllerState toState) {
345352
// Disable modules if we're in an errored state. If we're in an
346353
// incomplete state or rescanning, leave the state as is to avoid
347354
// unnecessarily resetting the computer.
348-
if (state != ControllerState.INCOMPLETE && state != ControllerState.SCANNING) {
355+
if (toState != ControllerState.INCOMPLETE && toState != ControllerState.SCANNING) {
349356
casings.forEach(TileEntityCasing::onDisabled);
350357
}
351358
casings.clear();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Audio Module
2+
3+
![Beep boop](item:tis3d:moduleAudio)
4+
5+
The audio module synthesizes sounds based on numeric triggers. The emitted sound is defined by the value transmitted to the audio module as defined below. If a volume of zero is specified the signal will be discarded.
6+
7+
The audio module continuously reads values from all four of its ports and emits a sound based on the read value. The read value is a packed value consisting of the properties of the sound to generate. This compact representation allows triggering sounds in a very responsive fashion.
8+
9+
## Signal Specification
10+
Each value received by the audio module is interpreted as a packed value with the components: instrument, volume and pitch. The corresponding masks are as follows:
11+
- `0xFF00` contains the pitch.
12+
- `0x00F0` contains the volume, clamped to [0, 5].
13+
- `0x000F` contains the instrument, one of {0, 1, 2, 3, 4}.
14+
15+
When generating sounds the bitwise operations of the [execution module](moduleExecution.md) will prove useful in combining the individual values into one.

‎src/main/resources/assets/tis3d/lang/en_US.lang

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ itemGroup.tis3d=TIS-3D
22

33
item.tis3d.bookCode.name=Code Bible
44
item.tis3d.bookManual.name=TIS-3D Reference Manual
5+
item.tis3d.moduleAudio.name=Audio Module
56
item.tis3d.moduleExecution.name=Execution Module
67
item.tis3d.moduleInfrared.name=Infrared Module
78
item.tis3d.moduleRandom.name=Random Module
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"animation": {
3+
"frametime": 1
4+
}
5+
}
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"animation": {
3+
"frametime": 1
4+
}
5+
}

0 commit comments

Comments
 (0)
Please sign in to comment.