Normalize the repo
This commit is contained in:
parent
3a0a329c77
commit
c21dca182c
64 changed files with 66091 additions and 66090 deletions
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
* text=auto
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,2 +1,2 @@
|
|||
/*
|
||||
/*
|
||||
!/forge
|
8
forge/.gitignore
vendored
8
forge/.gitignore
vendored
|
@ -1,4 +1,4 @@
|
|||
/fml/
|
||||
/logs/
|
||||
/*.pyc
|
||||
/forge-*/
|
||||
/fml/
|
||||
/logs/
|
||||
/*.pyc
|
||||
/forge-*/
|
||||
|
|
Binary file not shown.
15236
forge/conf/client.exc
15236
forge/conf/client.exc
File diff suppressed because it is too large
Load diff
23378
forge/conf/client.srg
23378
forge/conf/client.srg
File diff suppressed because it is too large
Load diff
11840
forge/conf/fields.csv
11840
forge/conf/fields.csv
File diff suppressed because it is too large
Load diff
10018
forge/conf/methods.csv
10018
forge/conf/methods.csv
File diff suppressed because it is too large
Load diff
26438
forge/conf/params.csv
26438
forge/conf/params.csv
File diff suppressed because it is too large
Load diff
|
@ -1,10 +1,10 @@
|
|||
// this is needed for the sound engine to work with deobfuscated sourcecode without crashing
|
||||
|
||||
public class gk
|
||||
{
|
||||
public static int c(double d)
|
||||
{
|
||||
int i = (int)d;
|
||||
return d >= (double)i ? i : i - 1;
|
||||
}
|
||||
}
|
||||
// this is needed for the sound engine to work with deobfuscated sourcecode without crashing
|
||||
|
||||
public class gk
|
||||
{
|
||||
public static int c(double d)
|
||||
{
|
||||
int i = (int)d;
|
||||
return d >= (double)i ? i : i - 1;
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,117 +1,117 @@
|
|||
diff -r -U 3 minecraft\net\minecraft\client\Minecraft.java minecraft_patched\net\minecraft\client\Minecraft.java
|
||||
--- minecraft\net\minecraft\client\Minecraft.java Fri Mar 30 23:25:51 2012
|
||||
+++ minecraft_patched\net\minecraft\client\Minecraft.java Fri Mar 30 23:38:36 2012
|
||||
@@ -1618,11 +1618,13 @@
|
||||
|
||||
this.field_6324_e.func_600_a(var6.field_22395_a + var10, 64, var6.field_22396_c + var8);
|
||||
if(!this.field_6327_b.func_35643_e()) {
|
||||
+/*
|
||||
while(true) {
|
||||
if(this.field_6324_e.func_6465_g()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
+*/
|
||||
}
|
||||
}
|
||||
}
|
||||
diff -r -U 3 minecraft\net\minecraft\src\CodecMus.java minecraft_patched\net\minecraft\src\CodecMus.java
|
||||
--- minecraft\net\minecraft\src\CodecMus.java Fri Mar 30 23:25:52 2012
|
||||
+++ minecraft_patched\net\minecraft\src\CodecMus.java Fri Mar 30 23:38:36 2012
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.minecraft.src;
|
||||
|
||||
+import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import net.minecraft.src.MusInputStream;
|
||||
import paulscode.sound.codecs.CodecJOrbis;
|
||||
@@ -7,6 +8,11 @@
|
||||
public class CodecMus extends CodecJOrbis {
|
||||
|
||||
protected InputStream openInputStream() {
|
||||
+ try {
|
||||
return new MusInputStream(this, this.url, this.urlConnection.getInputStream());
|
||||
+ }
|
||||
+ catch (IOException e) {
|
||||
+ return null;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
diff -r -U 3 minecraft\net\minecraft\src\ItemMap.java minecraft_patched\net\minecraft\src\ItemMap.java
|
||||
--- minecraft\net\minecraft\src\ItemMap.java Fri Mar 30 23:25:53 2012
|
||||
+++ minecraft_patched\net\minecraft\src\ItemMap.java Fri Mar 30 23:38:36 2012
|
||||
@@ -19,7 +19,6 @@
|
||||
}
|
||||
|
||||
public static MapData func_28013_a(short p_28013_0_, World p_28013_1_) {
|
||||
- "map_" + p_28013_0_;
|
||||
MapData var3 = (MapData)p_28013_1_.func_28103_a(MapData.class, "map_" + p_28013_0_);
|
||||
if(var3 == null) {
|
||||
int var4 = p_28013_1_.func_28101_b("map");
|
||||
@@ -32,7 +31,6 @@
|
||||
}
|
||||
|
||||
public MapData func_28012_a(ItemStack p_28012_1_, World p_28012_2_) {
|
||||
- "map_" + p_28012_1_.func_21181_i();
|
||||
MapData var4 = (MapData)p_28012_2_.func_28103_a(MapData.class, "map_" + p_28012_1_.func_21181_i());
|
||||
if(var4 == null) {
|
||||
p_28012_1_.func_28156_b(p_28012_2_.func_28101_b("map"));
|
||||
diff -r -U 3 minecraft\net\minecraft\src\MusInputStream.java minecraft_patched\net\minecraft\src\MusInputStream.java
|
||||
--- minecraft\net\minecraft\src\MusInputStream.java Fri Mar 30 23:25:54 2012
|
||||
+++ minecraft_patched\net\minecraft\src\MusInputStream.java Fri Mar 30 23:38:36 2012
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.minecraft.src;
|
||||
|
||||
+import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import net.minecraft.src.CodecMus;
|
||||
@@ -27,7 +28,12 @@
|
||||
}
|
||||
|
||||
public int read(byte[] p_read_1_, int p_read_2_, int p_read_3_) {
|
||||
+ try {
|
||||
p_read_3_ = this.field_1515_d.read(p_read_1_, p_read_2_, p_read_3_);
|
||||
+ }
|
||||
+ catch (IOException e) {
|
||||
+ return 0;
|
||||
+ }
|
||||
|
||||
for(int var4 = 0; var4 < p_read_3_; ++var4) {
|
||||
byte var5 = p_read_1_[p_read_2_ + var4] = (byte)(p_read_1_[p_read_2_ + var4] ^ this.field_1516_c >> 8);
|
||||
diff -r -U 3 minecraft\net\minecraft\src\NetworkMasterThread.java minecraft_patched\net\minecraft\src\NetworkMasterThread.java
|
||||
--- minecraft\net\minecraft\src\NetworkMasterThread.java Fri Mar 30 23:25:54 2012
|
||||
+++ minecraft_patched\net\minecraft\src\NetworkMasterThread.java Fri Mar 30 23:38:36 2012
|
||||
@@ -11,6 +11,7 @@
|
||||
this.field_1086_a = p_i570_1_;
|
||||
}
|
||||
|
||||
+ @SuppressWarnings("deprecation")
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep(5000L);
|
||||
diff -r -U 3 minecraft\net\minecraft\src\RenderGlobal.java minecraft_patched\net\minecraft\src\RenderGlobal.java
|
||||
--- minecraft\net\minecraft\src\RenderGlobal.java Fri Mar 30 23:25:54 2012
|
||||
+++ minecraft_patched\net\minecraft\src\RenderGlobal.java Fri Mar 30 23:38:36 2012
|
||||
@@ -1458,7 +1458,7 @@
|
||||
double var15 = this.field_1439_t.field_22009_h.field_611_ak - p_40193_2_;
|
||||
double var17 = this.field_1439_t.field_22009_h.field_610_al - p_40193_4_;
|
||||
double var19 = this.field_1439_t.field_22009_h.field_609_am - p_40193_6_;
|
||||
- Object var21 = null;
|
||||
+ EntityFX var21 = null;
|
||||
if(p_40193_1_.equals("hugeexplosion")) {
|
||||
this.field_1439_t.field_6321_h.func_1192_a(var21 = new EntityHugeExplodeFX(this.field_1448_k, p_40193_2_, p_40193_4_, p_40193_6_, p_40193_8_, p_40193_10_, p_40193_12_));
|
||||
} else if(p_40193_1_.equals("largeexplode")) {
|
||||
diff -r -U 3 minecraft\net\minecraft\src\ThreadedFileIOBase.java minecraft_patched\net\minecraft\src\ThreadedFileIOBase.java
|
||||
--- minecraft\net\minecraft\src\ThreadedFileIOBase.java Fri Mar 30 23:25:55 2012
|
||||
+++ minecraft_patched\net\minecraft\src\ThreadedFileIOBase.java Fri Mar 30 23:38:36 2012
|
||||
@@ -20,7 +20,9 @@
|
||||
}
|
||||
|
||||
public void run() {
|
||||
+ while (true) {
|
||||
this.func_40568_b();
|
||||
+ }
|
||||
}
|
||||
|
||||
private void func_40568_b() {
|
||||
diff -r -U 3 minecraft\net\minecraft\client\Minecraft.java minecraft_patched\net\minecraft\client\Minecraft.java
|
||||
--- minecraft\net\minecraft\client\Minecraft.java Fri Mar 30 23:25:51 2012
|
||||
+++ minecraft_patched\net\minecraft\client\Minecraft.java Fri Mar 30 23:38:36 2012
|
||||
@@ -1618,11 +1618,13 @@
|
||||
|
||||
this.field_6324_e.func_600_a(var6.field_22395_a + var10, 64, var6.field_22396_c + var8);
|
||||
if(!this.field_6327_b.func_35643_e()) {
|
||||
+/*
|
||||
while(true) {
|
||||
if(this.field_6324_e.func_6465_g()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
+*/
|
||||
}
|
||||
}
|
||||
}
|
||||
diff -r -U 3 minecraft\net\minecraft\src\CodecMus.java minecraft_patched\net\minecraft\src\CodecMus.java
|
||||
--- minecraft\net\minecraft\src\CodecMus.java Fri Mar 30 23:25:52 2012
|
||||
+++ minecraft_patched\net\minecraft\src\CodecMus.java Fri Mar 30 23:38:36 2012
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.minecraft.src;
|
||||
|
||||
+import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import net.minecraft.src.MusInputStream;
|
||||
import paulscode.sound.codecs.CodecJOrbis;
|
||||
@@ -7,6 +8,11 @@
|
||||
public class CodecMus extends CodecJOrbis {
|
||||
|
||||
protected InputStream openInputStream() {
|
||||
+ try {
|
||||
return new MusInputStream(this, this.url, this.urlConnection.getInputStream());
|
||||
+ }
|
||||
+ catch (IOException e) {
|
||||
+ return null;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
diff -r -U 3 minecraft\net\minecraft\src\ItemMap.java minecraft_patched\net\minecraft\src\ItemMap.java
|
||||
--- minecraft\net\minecraft\src\ItemMap.java Fri Mar 30 23:25:53 2012
|
||||
+++ minecraft_patched\net\minecraft\src\ItemMap.java Fri Mar 30 23:38:36 2012
|
||||
@@ -19,7 +19,6 @@
|
||||
}
|
||||
|
||||
public static MapData func_28013_a(short p_28013_0_, World p_28013_1_) {
|
||||
- "map_" + p_28013_0_;
|
||||
MapData var3 = (MapData)p_28013_1_.func_28103_a(MapData.class, "map_" + p_28013_0_);
|
||||
if(var3 == null) {
|
||||
int var4 = p_28013_1_.func_28101_b("map");
|
||||
@@ -32,7 +31,6 @@
|
||||
}
|
||||
|
||||
public MapData func_28012_a(ItemStack p_28012_1_, World p_28012_2_) {
|
||||
- "map_" + p_28012_1_.func_21181_i();
|
||||
MapData var4 = (MapData)p_28012_2_.func_28103_a(MapData.class, "map_" + p_28012_1_.func_21181_i());
|
||||
if(var4 == null) {
|
||||
p_28012_1_.func_28156_b(p_28012_2_.func_28101_b("map"));
|
||||
diff -r -U 3 minecraft\net\minecraft\src\MusInputStream.java minecraft_patched\net\minecraft\src\MusInputStream.java
|
||||
--- minecraft\net\minecraft\src\MusInputStream.java Fri Mar 30 23:25:54 2012
|
||||
+++ minecraft_patched\net\minecraft\src\MusInputStream.java Fri Mar 30 23:38:36 2012
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.minecraft.src;
|
||||
|
||||
+import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import net.minecraft.src.CodecMus;
|
||||
@@ -27,7 +28,12 @@
|
||||
}
|
||||
|
||||
public int read(byte[] p_read_1_, int p_read_2_, int p_read_3_) {
|
||||
+ try {
|
||||
p_read_3_ = this.field_1515_d.read(p_read_1_, p_read_2_, p_read_3_);
|
||||
+ }
|
||||
+ catch (IOException e) {
|
||||
+ return 0;
|
||||
+ }
|
||||
|
||||
for(int var4 = 0; var4 < p_read_3_; ++var4) {
|
||||
byte var5 = p_read_1_[p_read_2_ + var4] = (byte)(p_read_1_[p_read_2_ + var4] ^ this.field_1516_c >> 8);
|
||||
diff -r -U 3 minecraft\net\minecraft\src\NetworkMasterThread.java minecraft_patched\net\minecraft\src\NetworkMasterThread.java
|
||||
--- minecraft\net\minecraft\src\NetworkMasterThread.java Fri Mar 30 23:25:54 2012
|
||||
+++ minecraft_patched\net\minecraft\src\NetworkMasterThread.java Fri Mar 30 23:38:36 2012
|
||||
@@ -11,6 +11,7 @@
|
||||
this.field_1086_a = p_i570_1_;
|
||||
}
|
||||
|
||||
+ @SuppressWarnings("deprecation")
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep(5000L);
|
||||
diff -r -U 3 minecraft\net\minecraft\src\RenderGlobal.java minecraft_patched\net\minecraft\src\RenderGlobal.java
|
||||
--- minecraft\net\minecraft\src\RenderGlobal.java Fri Mar 30 23:25:54 2012
|
||||
+++ minecraft_patched\net\minecraft\src\RenderGlobal.java Fri Mar 30 23:38:36 2012
|
||||
@@ -1458,7 +1458,7 @@
|
||||
double var15 = this.field_1439_t.field_22009_h.field_611_ak - p_40193_2_;
|
||||
double var17 = this.field_1439_t.field_22009_h.field_610_al - p_40193_4_;
|
||||
double var19 = this.field_1439_t.field_22009_h.field_609_am - p_40193_6_;
|
||||
- Object var21 = null;
|
||||
+ EntityFX var21 = null;
|
||||
if(p_40193_1_.equals("hugeexplosion")) {
|
||||
this.field_1439_t.field_6321_h.func_1192_a(var21 = new EntityHugeExplodeFX(this.field_1448_k, p_40193_2_, p_40193_4_, p_40193_6_, p_40193_8_, p_40193_10_, p_40193_12_));
|
||||
} else if(p_40193_1_.equals("largeexplode")) {
|
||||
diff -r -U 3 minecraft\net\minecraft\src\ThreadedFileIOBase.java minecraft_patched\net\minecraft\src\ThreadedFileIOBase.java
|
||||
--- minecraft\net\minecraft\src\ThreadedFileIOBase.java Fri Mar 30 23:25:55 2012
|
||||
+++ minecraft_patched\net\minecraft\src\ThreadedFileIOBase.java Fri Mar 30 23:38:36 2012
|
||||
@@ -20,7 +20,9 @@
|
||||
}
|
||||
|
||||
public void run() {
|
||||
+ while (true) {
|
||||
this.func_40568_b();
|
||||
+ }
|
||||
}
|
||||
|
||||
private void func_40568_b() {
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,35 +1,35 @@
|
|||
diff -r -U 3 minecraft_server\net\minecraft\src\ItemMap.java minecraft_server_patched\net\minecraft\src\ItemMap.java
|
||||
--- minecraft_server\net\minecraft\src\ItemMap.java Fri Mar 30 23:27:06 2012
|
||||
+++ minecraft_server_patched\net\minecraft\src\ItemMap.java Fri Mar 30 23:40:00 2012
|
||||
@@ -22,7 +22,6 @@
|
||||
}
|
||||
|
||||
public MapData func_28023_a(ItemStack p_28023_1_, World p_28023_2_) {
|
||||
- "map_" + p_28023_1_.func_21125_h();
|
||||
MapData var4 = (MapData)p_28023_2_.func_28103_a(MapData.class, "map_" + p_28023_1_.func_21125_h());
|
||||
if(var4 == null) {
|
||||
p_28023_1_.func_28145_b(p_28023_2_.func_28104_b("map"));
|
||||
diff -r -U 3 minecraft_server\net\minecraft\src\NetworkMasterThread.java minecraft_server_patched\net\minecraft\src\NetworkMasterThread.java
|
||||
--- minecraft_server\net\minecraft\src\NetworkMasterThread.java Fri Mar 30 23:27:07 2012
|
||||
+++ minecraft_server_patched\net\minecraft\src\NetworkMasterThread.java Fri Mar 30 23:40:00 2012
|
||||
@@ -11,6 +11,7 @@
|
||||
this.field_829_a = p_i577_1_;
|
||||
}
|
||||
|
||||
+ @SuppressWarnings("deprecation")
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep(5000L);
|
||||
diff -r -U 3 minecraft_server\net\minecraft\src\ThreadedFileIOBase.java minecraft_server_patched\net\minecraft\src\ThreadedFileIOBase.java
|
||||
--- minecraft_server\net\minecraft\src\ThreadedFileIOBase.java Fri Mar 30 23:27:07 2012
|
||||
+++ minecraft_server_patched\net\minecraft\src\ThreadedFileIOBase.java Fri Mar 30 23:40:00 2012
|
||||
@@ -20,7 +20,9 @@
|
||||
}
|
||||
|
||||
public void run() {
|
||||
+ while (true) {
|
||||
this.func_40509_b();
|
||||
+ }
|
||||
}
|
||||
|
||||
private void func_40509_b() {
|
||||
diff -r -U 3 minecraft_server\net\minecraft\src\ItemMap.java minecraft_server_patched\net\minecraft\src\ItemMap.java
|
||||
--- minecraft_server\net\minecraft\src\ItemMap.java Fri Mar 30 23:27:06 2012
|
||||
+++ minecraft_server_patched\net\minecraft\src\ItemMap.java Fri Mar 30 23:40:00 2012
|
||||
@@ -22,7 +22,6 @@
|
||||
}
|
||||
|
||||
public MapData func_28023_a(ItemStack p_28023_1_, World p_28023_2_) {
|
||||
- "map_" + p_28023_1_.func_21125_h();
|
||||
MapData var4 = (MapData)p_28023_2_.func_28103_a(MapData.class, "map_" + p_28023_1_.func_21125_h());
|
||||
if(var4 == null) {
|
||||
p_28023_1_.func_28145_b(p_28023_2_.func_28104_b("map"));
|
||||
diff -r -U 3 minecraft_server\net\minecraft\src\NetworkMasterThread.java minecraft_server_patched\net\minecraft\src\NetworkMasterThread.java
|
||||
--- minecraft_server\net\minecraft\src\NetworkMasterThread.java Fri Mar 30 23:27:07 2012
|
||||
+++ minecraft_server_patched\net\minecraft\src\NetworkMasterThread.java Fri Mar 30 23:40:00 2012
|
||||
@@ -11,6 +11,7 @@
|
||||
this.field_829_a = p_i577_1_;
|
||||
}
|
||||
|
||||
+ @SuppressWarnings("deprecation")
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep(5000L);
|
||||
diff -r -U 3 minecraft_server\net\minecraft\src\ThreadedFileIOBase.java minecraft_server_patched\net\minecraft\src\ThreadedFileIOBase.java
|
||||
--- minecraft_server\net\minecraft\src\ThreadedFileIOBase.java Fri Mar 30 23:27:07 2012
|
||||
+++ minecraft_server_patched\net\minecraft\src\ThreadedFileIOBase.java Fri Mar 30 23:40:00 2012
|
||||
@@ -20,7 +20,9 @@
|
||||
}
|
||||
|
||||
public void run() {
|
||||
+ while (true) {
|
||||
this.func_40509_b();
|
||||
+ }
|
||||
}
|
||||
|
||||
private void func_40509_b() {
|
||||
|
|
11160
forge/conf/server.exc
11160
forge/conf/server.exc
File diff suppressed because it is too large
Load diff
16728
forge/conf/server.srg
16728
forge/conf/server.srg
File diff suppressed because it is too large
Load diff
|
@ -1,4 +1,4 @@
|
|||
[VERSION]
|
||||
MCPVersion = 6.2
|
||||
ClientVersion = 1.2.5
|
||||
ServerVersion = 1.2.5
|
||||
[VERSION]
|
||||
MCPVersion = 6.2
|
||||
ClientVersion = 1.2.5
|
||||
ServerVersion = 1.2.5
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="forge_common"/>
|
||||
<classpathentry kind="src" path="minecraft"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
|
||||
<classpathentry kind="lib" path="../../jars/bin/jinput.jar">
|
||||
<attributes>
|
||||
<attribute name="org.eclipse.jdt.launching.CLASSPATH_ATTR_LIBRARY_PATH_ENTRY" value="forge_client/jars/bin/natives"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="lib" path="../../jars/bin/lwjgl.jar">
|
||||
<attributes>
|
||||
<attribute name="org.eclipse.jdt.launching.CLASSPATH_ATTR_LIBRARY_PATH_ENTRY" value="forge_client/jars/bin/natives"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="lib" path="../../jars/bin/lwjgl_util.jar">
|
||||
<attributes>
|
||||
<attribute name="org.eclipse.jdt.launching.CLASSPATH_ATTR_LIBRARY_PATH_ENTRY" value="forge_client/jars/bin/natives"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="lib" path="../../jars/bin/minecraft.jar"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="forge_common"/>
|
||||
<classpathentry kind="src" path="minecraft"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
|
||||
<classpathentry kind="lib" path="../../jars/bin/jinput.jar">
|
||||
<attributes>
|
||||
<attribute name="org.eclipse.jdt.launching.CLASSPATH_ATTR_LIBRARY_PATH_ENTRY" value="forge_client/jars/bin/natives"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="lib" path="../../jars/bin/lwjgl.jar">
|
||||
<attributes>
|
||||
<attribute name="org.eclipse.jdt.launching.CLASSPATH_ATTR_LIBRARY_PATH_ENTRY" value="forge_client/jars/bin/natives"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="lib" path="../../jars/bin/lwjgl_util.jar">
|
||||
<attributes>
|
||||
<attribute name="org.eclipse.jdt.launching.CLASSPATH_ATTR_LIBRARY_PATH_ENTRY" value="forge_client/jars/bin/natives"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="lib" path="../../jars/bin/minecraft.jar"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
|
|
2
forge/forge_client/.gitignore
vendored
2
forge/forge_client/.gitignore
vendored
|
@ -1 +1 @@
|
|||
/bin/
|
||||
/bin/
|
||||
|
|
|
@ -1,69 +1,69 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>forge_client</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
<linkedResources>
|
||||
<link>
|
||||
<name>forge_common</name>
|
||||
<type>2</type>
|
||||
<locationURI>PARENT-1-PROJECT_LOC/forge_common</locationURI>
|
||||
</link>
|
||||
<link>
|
||||
<name>jars</name>
|
||||
<type>2</type>
|
||||
<locationURI>MCP_LOC/jars</locationURI>
|
||||
</link>
|
||||
<link>
|
||||
<name>minecraft</name>
|
||||
<type>2</type>
|
||||
<locationURI>PARENT-1-WORKSPACE_LOC/src_work/minecraft</locationURI>
|
||||
</link>
|
||||
</linkedResources>
|
||||
<filteredResources>
|
||||
<filter>
|
||||
<id>1324024223159</id>
|
||||
<name>jars</name>
|
||||
<type>9</type>
|
||||
<matcher>
|
||||
<id>org.eclipse.ui.ide.multiFilter</id>
|
||||
<arguments>1.0-name-matches-false-false-bin</arguments>
|
||||
</matcher>
|
||||
</filter>
|
||||
<filter>
|
||||
<id>1324024223163</id>
|
||||
<name>jars</name>
|
||||
<type>6</type>
|
||||
<matcher>
|
||||
<id>org.eclipse.ui.ide.multiFilter</id>
|
||||
<arguments>1.0-name-matches-false-false-*</arguments>
|
||||
</matcher>
|
||||
</filter>
|
||||
<filter>
|
||||
<id>1324024144075</id>
|
||||
<name>jars/bin</name>
|
||||
<type>5</type>
|
||||
<matcher>
|
||||
<id>org.eclipse.ui.ide.multiFilter</id>
|
||||
<arguments>1.0-name-matches-false-false-*.jar</arguments>
|
||||
</matcher>
|
||||
</filter>
|
||||
</filteredResources>
|
||||
<variableList>
|
||||
<variable>
|
||||
<name>MCP_LOC</name>
|
||||
<value>$%7BPARENT-1-WORKSPACE_LOC%7D</value>
|
||||
</variable>
|
||||
</variableList>
|
||||
</projectDescription>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>forge_client</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
<linkedResources>
|
||||
<link>
|
||||
<name>forge_common</name>
|
||||
<type>2</type>
|
||||
<locationURI>PARENT-1-PROJECT_LOC/forge_common</locationURI>
|
||||
</link>
|
||||
<link>
|
||||
<name>jars</name>
|
||||
<type>2</type>
|
||||
<locationURI>MCP_LOC/jars</locationURI>
|
||||
</link>
|
||||
<link>
|
||||
<name>minecraft</name>
|
||||
<type>2</type>
|
||||
<locationURI>PARENT-1-WORKSPACE_LOC/src_work/minecraft</locationURI>
|
||||
</link>
|
||||
</linkedResources>
|
||||
<filteredResources>
|
||||
<filter>
|
||||
<id>1324024223159</id>
|
||||
<name>jars</name>
|
||||
<type>9</type>
|
||||
<matcher>
|
||||
<id>org.eclipse.ui.ide.multiFilter</id>
|
||||
<arguments>1.0-name-matches-false-false-bin</arguments>
|
||||
</matcher>
|
||||
</filter>
|
||||
<filter>
|
||||
<id>1324024223163</id>
|
||||
<name>jars</name>
|
||||
<type>6</type>
|
||||
<matcher>
|
||||
<id>org.eclipse.ui.ide.multiFilter</id>
|
||||
<arguments>1.0-name-matches-false-false-*</arguments>
|
||||
</matcher>
|
||||
</filter>
|
||||
<filter>
|
||||
<id>1324024144075</id>
|
||||
<name>jars/bin</name>
|
||||
<type>5</type>
|
||||
<matcher>
|
||||
<id>org.eclipse.ui.ide.multiFilter</id>
|
||||
<arguments>1.0-name-matches-false-false-*.jar</arguments>
|
||||
</matcher>
|
||||
</filter>
|
||||
</filteredResources>
|
||||
<variableList>
|
||||
<variable>
|
||||
<name>MCP_LOC</name>
|
||||
<value>$%7BPARENT-1-WORKSPACE_LOC%7D</value>
|
||||
</variable>
|
||||
</variableList>
|
||||
</projectDescription>
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,111 +1,111 @@
|
|||
|
||||
package ibxm;
|
||||
|
||||
public class Envelope {
|
||||
public boolean sustain, looped;
|
||||
private int sustain_tick, loop_start_tick, loop_end_tick;
|
||||
private int[] ticks, ampls;
|
||||
|
||||
public Envelope() {
|
||||
set_num_points( 1 );
|
||||
}
|
||||
|
||||
public void set_num_points( int num_points ) {
|
||||
int point;
|
||||
if( num_points <= 0 ) {
|
||||
num_points = 1;
|
||||
}
|
||||
ticks = new int[ num_points ];
|
||||
ampls = new int[ num_points ];
|
||||
set_point( 0, 0, 0, false );
|
||||
}
|
||||
|
||||
/* When you set a point, all subsequent points are reset. */
|
||||
public void set_point( int point, int tick, int ampl, boolean delta ) {
|
||||
if( point >= 0 && point < ticks.length ) {
|
||||
if( point == 0 ) {
|
||||
tick = 0;
|
||||
}
|
||||
if( point > 0 ) {
|
||||
if( delta ) tick += ticks[ point - 1 ];
|
||||
if( tick <= ticks[ point - 1 ] ) {
|
||||
System.out.println( "Envelope: Point not valid (" + tick + " <= " + ticks[ point - 1 ] + ")");
|
||||
tick = ticks[ point - 1 ] + 1;
|
||||
}
|
||||
}
|
||||
ticks[ point ] = tick;
|
||||
ampls[ point ] = ampl;
|
||||
point += 1;
|
||||
while( point < ticks.length ) {
|
||||
ticks[ point ] = ticks[ point - 1 ] + 1;
|
||||
ampls[ point ] = 0;
|
||||
point += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void set_sustain_point( int point ) {
|
||||
if( point < 0 ) {
|
||||
point = 0;
|
||||
}
|
||||
if( point >= ticks.length ) {
|
||||
point = ticks.length - 1;
|
||||
}
|
||||
sustain_tick = ticks[ point ];
|
||||
}
|
||||
|
||||
public void set_loop_points( int start, int end ) {
|
||||
if( start < 0 ) {
|
||||
start = 0;
|
||||
}
|
||||
if( start >= ticks.length ) {
|
||||
start = ticks.length - 1;
|
||||
}
|
||||
if( end < start || end >= ticks.length ) {
|
||||
end = start;
|
||||
}
|
||||
loop_start_tick = ticks[ start ];
|
||||
loop_end_tick = ticks[ end ];
|
||||
}
|
||||
|
||||
public int next_tick( int tick, boolean key_on ) {
|
||||
tick = tick + 1;
|
||||
if( looped && tick >= loop_end_tick ) {
|
||||
tick = loop_start_tick;
|
||||
}
|
||||
if( sustain && key_on && tick >= sustain_tick ) {
|
||||
tick = sustain_tick;
|
||||
}
|
||||
return tick;
|
||||
}
|
||||
|
||||
public int calculate_ampl( int tick ) {
|
||||
int idx, point, delta_t, delta_a, ampl;
|
||||
ampl = ampls[ ticks.length - 1 ];
|
||||
if( tick < ticks[ ticks.length - 1 ] ) {
|
||||
point = 0;
|
||||
for( idx = 1; idx < ticks.length; idx++ ) {
|
||||
if( ticks[ idx ] <= tick ) {
|
||||
point = idx;
|
||||
}
|
||||
}
|
||||
delta_t = ticks[ point + 1 ] - ticks[ point ];
|
||||
delta_a = ampls[ point + 1 ] - ampls[ point ];
|
||||
ampl = ( delta_a << IBXM.FP_SHIFT ) / delta_t;
|
||||
ampl = ampl * ( tick - ticks[ point ] ) >> IBXM.FP_SHIFT;
|
||||
ampl = ampl + ampls[ point ];
|
||||
}
|
||||
return ampl;
|
||||
}
|
||||
|
||||
public void dump() {
|
||||
int idx, tick;
|
||||
for( idx = 0; idx < ticks.length; idx++ ) {
|
||||
System.out.println( ticks[ idx ] + ", " + ampls[ idx ] );
|
||||
}
|
||||
for( tick = 0; tick < 222; tick++ ) {
|
||||
System.out.print( calculate_ampl( tick ) + ", " );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
package ibxm;
|
||||
|
||||
public class Envelope {
|
||||
public boolean sustain, looped;
|
||||
private int sustain_tick, loop_start_tick, loop_end_tick;
|
||||
private int[] ticks, ampls;
|
||||
|
||||
public Envelope() {
|
||||
set_num_points( 1 );
|
||||
}
|
||||
|
||||
public void set_num_points( int num_points ) {
|
||||
int point;
|
||||
if( num_points <= 0 ) {
|
||||
num_points = 1;
|
||||
}
|
||||
ticks = new int[ num_points ];
|
||||
ampls = new int[ num_points ];
|
||||
set_point( 0, 0, 0, false );
|
||||
}
|
||||
|
||||
/* When you set a point, all subsequent points are reset. */
|
||||
public void set_point( int point, int tick, int ampl, boolean delta ) {
|
||||
if( point >= 0 && point < ticks.length ) {
|
||||
if( point == 0 ) {
|
||||
tick = 0;
|
||||
}
|
||||
if( point > 0 ) {
|
||||
if( delta ) tick += ticks[ point - 1 ];
|
||||
if( tick <= ticks[ point - 1 ] ) {
|
||||
System.out.println( "Envelope: Point not valid (" + tick + " <= " + ticks[ point - 1 ] + ")");
|
||||
tick = ticks[ point - 1 ] + 1;
|
||||
}
|
||||
}
|
||||
ticks[ point ] = tick;
|
||||
ampls[ point ] = ampl;
|
||||
point += 1;
|
||||
while( point < ticks.length ) {
|
||||
ticks[ point ] = ticks[ point - 1 ] + 1;
|
||||
ampls[ point ] = 0;
|
||||
point += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void set_sustain_point( int point ) {
|
||||
if( point < 0 ) {
|
||||
point = 0;
|
||||
}
|
||||
if( point >= ticks.length ) {
|
||||
point = ticks.length - 1;
|
||||
}
|
||||
sustain_tick = ticks[ point ];
|
||||
}
|
||||
|
||||
public void set_loop_points( int start, int end ) {
|
||||
if( start < 0 ) {
|
||||
start = 0;
|
||||
}
|
||||
if( start >= ticks.length ) {
|
||||
start = ticks.length - 1;
|
||||
}
|
||||
if( end < start || end >= ticks.length ) {
|
||||
end = start;
|
||||
}
|
||||
loop_start_tick = ticks[ start ];
|
||||
loop_end_tick = ticks[ end ];
|
||||
}
|
||||
|
||||
public int next_tick( int tick, boolean key_on ) {
|
||||
tick = tick + 1;
|
||||
if( looped && tick >= loop_end_tick ) {
|
||||
tick = loop_start_tick;
|
||||
}
|
||||
if( sustain && key_on && tick >= sustain_tick ) {
|
||||
tick = sustain_tick;
|
||||
}
|
||||
return tick;
|
||||
}
|
||||
|
||||
public int calculate_ampl( int tick ) {
|
||||
int idx, point, delta_t, delta_a, ampl;
|
||||
ampl = ampls[ ticks.length - 1 ];
|
||||
if( tick < ticks[ ticks.length - 1 ] ) {
|
||||
point = 0;
|
||||
for( idx = 1; idx < ticks.length; idx++ ) {
|
||||
if( ticks[ idx ] <= tick ) {
|
||||
point = idx;
|
||||
}
|
||||
}
|
||||
delta_t = ticks[ point + 1 ] - ticks[ point ];
|
||||
delta_a = ampls[ point + 1 ] - ampls[ point ];
|
||||
ampl = ( delta_a << IBXM.FP_SHIFT ) / delta_t;
|
||||
ampl = ampl * ( tick - ticks[ point ] ) >> IBXM.FP_SHIFT;
|
||||
ampl = ampl + ampls[ point ];
|
||||
}
|
||||
return ampl;
|
||||
}
|
||||
|
||||
public void dump() {
|
||||
int idx, tick;
|
||||
for( idx = 0; idx < ticks.length; idx++ ) {
|
||||
System.out.println( ticks[ idx ] + ", " + ampls[ idx ] );
|
||||
}
|
||||
for( tick = 0; tick < 222; tick++ ) {
|
||||
System.out.print( calculate_ampl( tick ) + ", " );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,256 +1,256 @@
|
|||
|
||||
package ibxm;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public class FastTracker2 {
|
||||
public static boolean is_xm( byte[] header_60_bytes ) {
|
||||
String xm_identifier;
|
||||
xm_identifier = ascii_text( header_60_bytes, 0, 17 );
|
||||
return xm_identifier.equals( "Extended Module: " );
|
||||
}
|
||||
|
||||
public static Module load_xm( byte[] header_60_bytes, DataInput data_input ) throws IOException {
|
||||
int xm_version, song_header_length, sequence_length;
|
||||
int num_channels, num_patterns, num_instruments, xm_flags, idx;
|
||||
byte[] structure_header, song_header;
|
||||
boolean delta_env;
|
||||
String tracker_name;
|
||||
Instrument instrument;
|
||||
Module module;
|
||||
if( !is_xm( header_60_bytes ) ) {
|
||||
throw new IllegalArgumentException( "Not an XM file!" );
|
||||
}
|
||||
xm_version = unsigned_short_le( header_60_bytes, 58 );
|
||||
if( xm_version != 0x0104 ) {
|
||||
throw new IllegalArgumentException( "Sorry, XM version " + xm_version + " is not supported!" );
|
||||
}
|
||||
module = new Module();
|
||||
module.song_title = ascii_text( header_60_bytes, 17, 20 );
|
||||
tracker_name = ascii_text( header_60_bytes, 38, 20 );
|
||||
delta_env = tracker_name.startsWith( "DigiBooster Pro" );
|
||||
structure_header = new byte[ 4 ];
|
||||
data_input.readFully( structure_header );
|
||||
song_header_length = int_le( structure_header, 0 );
|
||||
song_header = new byte[ song_header_length ];
|
||||
data_input.readFully( song_header, 4, song_header_length - 4 );
|
||||
sequence_length = unsigned_short_le( song_header, 4 );
|
||||
module.restart_sequence_index = unsigned_short_le( song_header, 6 );
|
||||
num_channels = unsigned_short_le( song_header, 8 );
|
||||
num_patterns = unsigned_short_le( song_header, 10 );
|
||||
num_instruments = unsigned_short_le( song_header, 12 );
|
||||
xm_flags = unsigned_short_le( song_header, 14 );
|
||||
module.linear_periods = ( xm_flags & 0x1 ) == 0x1;
|
||||
module.global_volume = 64;
|
||||
module.channel_gain = IBXM.FP_ONE * 3 / 8;
|
||||
module.default_speed = unsigned_short_le( song_header, 16 );
|
||||
module.default_tempo = unsigned_short_le( song_header, 18 );
|
||||
module.set_num_channels( num_channels );
|
||||
for( idx = 0; idx < num_channels; idx++ ) {
|
||||
module.set_initial_panning( idx, 128 );
|
||||
}
|
||||
module.set_sequence_length( sequence_length );
|
||||
for( idx = 0; idx < sequence_length; idx++ ) {
|
||||
module.set_sequence( idx, song_header[ 20 + idx ] & 0xFF );
|
||||
}
|
||||
module.set_num_patterns( num_patterns );
|
||||
for( idx = 0; idx < num_patterns; idx++ ) {
|
||||
module.set_pattern( idx, read_xm_pattern( data_input, num_channels ) );
|
||||
}
|
||||
module.set_num_instruments( num_instruments );
|
||||
for( idx = 1; idx <= num_instruments; idx++ ) {
|
||||
try {
|
||||
instrument = read_xm_instrument( data_input, delta_env );
|
||||
module.set_instrument( idx, instrument );
|
||||
} catch( EOFException e ) {
|
||||
System.out.println( "Instrument " + idx + " is missing!" );
|
||||
}
|
||||
}
|
||||
return module;
|
||||
}
|
||||
|
||||
private static Pattern read_xm_pattern( DataInput data_input, int num_channels ) throws IOException {
|
||||
int pattern_header_length, packing_type, num_rows, pattern_data_length;
|
||||
byte[] structure_header, pattern_header, pattern_data;
|
||||
Pattern pattern;
|
||||
structure_header = new byte[ 4 ];
|
||||
data_input.readFully( structure_header );
|
||||
pattern_header_length = int_le( structure_header, 0 );
|
||||
pattern_header = new byte[ pattern_header_length ];
|
||||
data_input.readFully( pattern_header, 4, pattern_header_length - 4 );
|
||||
packing_type = pattern_header[ 4 ];
|
||||
if( packing_type != 0 ) {
|
||||
throw new IllegalArgumentException( "Pattern packing type " + packing_type + " is not supported!" );
|
||||
}
|
||||
pattern = new Pattern();
|
||||
pattern.num_rows = unsigned_short_le( pattern_header, 5 );
|
||||
pattern_data_length = unsigned_short_le( pattern_header, 7 );
|
||||
pattern_data = new byte[ pattern_data_length ];
|
||||
data_input.readFully( pattern_data );
|
||||
pattern.set_pattern_data( pattern_data );
|
||||
return pattern;
|
||||
}
|
||||
|
||||
private static Instrument read_xm_instrument( DataInput data_input, boolean delta_env ) throws IOException {
|
||||
int instrument_header_length, num_samples, idx;
|
||||
int env_tick, env_ampl, env_num_points, flags;
|
||||
byte[] structure_header, instrument_header, sample_headers;
|
||||
Instrument instrument;
|
||||
Envelope envelope;
|
||||
structure_header = new byte[ 4 ];
|
||||
data_input.readFully( structure_header );
|
||||
instrument_header_length = int_le( structure_header, 0 );
|
||||
instrument_header = new byte[ instrument_header_length ];
|
||||
data_input.readFully( instrument_header, 4, instrument_header_length - 4 );
|
||||
instrument = new Instrument();
|
||||
instrument.name = ascii_text( instrument_header, 4, 22 );
|
||||
num_samples = unsigned_short_le( instrument_header, 27 );
|
||||
if( num_samples > 0 ) {
|
||||
instrument.set_num_samples( num_samples );
|
||||
for( idx = 0; idx < 96; idx++ ) {
|
||||
instrument.set_key_to_sample( idx + 1, instrument_header[ 33 + idx ] & 0xFF );
|
||||
}
|
||||
envelope = new Envelope();
|
||||
env_num_points = instrument_header[ 225 ] & 0xFF;
|
||||
envelope.set_num_points( env_num_points );
|
||||
for( idx = 0; idx < env_num_points; idx++ ) {
|
||||
env_tick = unsigned_short_le( instrument_header, 129 + idx * 4 );
|
||||
env_ampl = unsigned_short_le( instrument_header, 131 + idx * 4 );
|
||||
envelope.set_point( idx, env_tick, env_ampl, delta_env );
|
||||
}
|
||||
envelope.set_sustain_point( instrument_header[ 227 ] & 0xFF );
|
||||
envelope.set_loop_points( instrument_header[ 228 ] & 0xFF, instrument_header[ 229 ] & 0xFF );
|
||||
flags = instrument_header[ 233 ] & 0xFF;
|
||||
instrument.volume_envelope_active = ( flags & 0x1 ) == 0x1;
|
||||
envelope.sustain = ( flags & 0x2 ) == 0x2;
|
||||
envelope.looped = ( flags & 0x4 ) == 0x4;
|
||||
instrument.set_volume_envelope( envelope );
|
||||
envelope = new Envelope();
|
||||
env_num_points = instrument_header[ 226 ] & 0xFF;
|
||||
envelope.set_num_points( env_num_points );
|
||||
for( idx = 0; idx < env_num_points; idx++ ) {
|
||||
env_tick = unsigned_short_le( instrument_header, 177 + idx * 4 );
|
||||
env_ampl = unsigned_short_le( instrument_header, 179 + idx * 4 );
|
||||
envelope.set_point( idx, env_tick, env_ampl, delta_env );
|
||||
}
|
||||
envelope.set_sustain_point( instrument_header[ 230 ] & 0xFF );
|
||||
envelope.set_loop_points( instrument_header[ 231 ] & 0xFF, instrument_header[ 232 ] & 0xFF );
|
||||
flags = instrument_header[ 234 ] & 0xFF;
|
||||
instrument.panning_envelope_active = ( flags & 0x1 ) == 0x1;
|
||||
envelope.sustain = ( flags & 0x2 ) == 0x2;
|
||||
envelope.looped = ( flags & 0x4 ) == 0x4;
|
||||
instrument.set_panning_envelope( envelope );
|
||||
instrument.vibrato_type = instrument_header[ 235 ] & 0xFF;
|
||||
instrument.vibrato_sweep = instrument_header[ 236 ] & 0xFF;
|
||||
instrument.vibrato_depth = instrument_header[ 237 ] & 0xFF;
|
||||
instrument.vibrato_rate = instrument_header[ 238 ] & 0xFF;
|
||||
instrument.volume_fade_out = unsigned_short_le( instrument_header, 239 );
|
||||
sample_headers = new byte[ num_samples * 40 ];
|
||||
data_input.readFully( sample_headers );
|
||||
for( idx = 0; idx < num_samples; idx++ ) {
|
||||
instrument.set_sample( idx, read_xm_sample( sample_headers, idx, data_input ) );
|
||||
}
|
||||
}
|
||||
return instrument;
|
||||
}
|
||||
|
||||
private static Sample read_xm_sample( byte[] sample_headers, int sample_idx, DataInput data_input ) throws IOException {
|
||||
int header_offset, sample_length, loop_start, loop_length;
|
||||
int flags, in_idx, out_idx, sam, last_sam;
|
||||
int fine_tune, relative_note;
|
||||
boolean sixteen_bit, ping_pong;
|
||||
byte[] raw_sample_data;
|
||||
short[] decoded_sample_data;
|
||||
Sample sample;
|
||||
header_offset = sample_idx * 40;
|
||||
sample = new Sample();
|
||||
sample_length = int_le( sample_headers, header_offset );
|
||||
loop_start = int_le( sample_headers, header_offset + 4 );
|
||||
loop_length = int_le( sample_headers, header_offset + 8 );
|
||||
sample.volume = sample_headers[ header_offset + 12 ] & 0xFF;
|
||||
fine_tune = sample_headers[ header_offset + 13 ];
|
||||
fine_tune = ( fine_tune << IBXM.FP_SHIFT ) / 1536;
|
||||
sample.set_panning = true;
|
||||
flags = sample_headers[ header_offset + 14 ] & 0xFF;
|
||||
if( ( flags & 0x03 ) == 0 ) {
|
||||
loop_length = 0;
|
||||
}
|
||||
ping_pong = ( flags & 0x02 ) == 0x02;
|
||||
sixteen_bit = ( flags & 0x10 ) == 0x10;
|
||||
sample.panning = sample_headers[ header_offset + 15 ] & 0xFF;
|
||||
relative_note = sample_headers[ header_offset + 16 ];
|
||||
relative_note = ( relative_note << IBXM.FP_SHIFT ) / 12;
|
||||
sample.transpose = relative_note + fine_tune;
|
||||
sample.name = ascii_text( sample_headers, header_offset + 18, 22 );
|
||||
raw_sample_data = new byte[ sample_length ];
|
||||
try {
|
||||
data_input.readFully( raw_sample_data );
|
||||
} catch( EOFException e ) {
|
||||
System.out.println( "Sample has been truncated!" );
|
||||
}
|
||||
in_idx = 0;
|
||||
out_idx = 0;
|
||||
sam = 0;
|
||||
last_sam = 0;
|
||||
if( sixteen_bit ) {
|
||||
decoded_sample_data = new short[ sample_length >> 1 ];
|
||||
while( in_idx < raw_sample_data.length ) {
|
||||
sam = raw_sample_data[ in_idx ] & 0xFF;
|
||||
sam = sam | ( ( raw_sample_data[ in_idx + 1 ] & 0xFF ) << 8 );
|
||||
last_sam = last_sam + sam;
|
||||
decoded_sample_data[ out_idx ] = ( short ) last_sam;
|
||||
in_idx += 2;
|
||||
out_idx += 1;
|
||||
}
|
||||
sample.set_sample_data( decoded_sample_data, loop_start >> 1, loop_length >> 1, ping_pong );
|
||||
} else {
|
||||
decoded_sample_data = new short[ sample_length ];
|
||||
while( in_idx < raw_sample_data.length ) {
|
||||
sam = raw_sample_data[ in_idx ] & 0xFF;
|
||||
last_sam = last_sam + sam;
|
||||
decoded_sample_data[ out_idx ] = ( short ) ( last_sam << 8 );
|
||||
in_idx += 1;
|
||||
out_idx += 1;
|
||||
}
|
||||
sample.set_sample_data( decoded_sample_data, loop_start, loop_length, ping_pong );
|
||||
}
|
||||
return sample;
|
||||
}
|
||||
|
||||
private static int unsigned_short_le( byte[] buffer, int offset ) {
|
||||
int value;
|
||||
value = buffer[ offset ] & 0xFF;
|
||||
value = value | ( ( buffer[ offset + 1 ] & 0xFF ) << 8 );
|
||||
return value;
|
||||
}
|
||||
|
||||
private static int int_le( byte[] buffer, int offset ) {
|
||||
int value;
|
||||
value = buffer[ offset ] & 0xFF;
|
||||
value = value | ( ( buffer[ offset + 1 ] & 0xFF ) << 8 );
|
||||
value = value | ( ( buffer[ offset + 2 ] & 0xFF ) << 16 );
|
||||
value = value | ( ( buffer[ offset + 3 ] & 0x7F ) << 24 );
|
||||
return value;
|
||||
}
|
||||
|
||||
private static String ascii_text( byte[] buffer, int offset, int length ) {
|
||||
int idx, chr;
|
||||
byte[] string_buffer;
|
||||
String string;
|
||||
string_buffer = new byte[ length ];
|
||||
for( idx = 0; idx < length; idx++ ) {
|
||||
chr = buffer[ offset + idx ];
|
||||
if( chr < 32 ) {
|
||||
chr = 32;
|
||||
}
|
||||
string_buffer[ idx ] = ( byte ) chr;
|
||||
}
|
||||
try {
|
||||
string = new String( string_buffer, 0, length, "ISO-8859-1" );
|
||||
} catch( UnsupportedEncodingException e ) {
|
||||
string = "";
|
||||
}
|
||||
return string;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
package ibxm;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public class FastTracker2 {
|
||||
public static boolean is_xm( byte[] header_60_bytes ) {
|
||||
String xm_identifier;
|
||||
xm_identifier = ascii_text( header_60_bytes, 0, 17 );
|
||||
return xm_identifier.equals( "Extended Module: " );
|
||||
}
|
||||
|
||||
public static Module load_xm( byte[] header_60_bytes, DataInput data_input ) throws IOException {
|
||||
int xm_version, song_header_length, sequence_length;
|
||||
int num_channels, num_patterns, num_instruments, xm_flags, idx;
|
||||
byte[] structure_header, song_header;
|
||||
boolean delta_env;
|
||||
String tracker_name;
|
||||
Instrument instrument;
|
||||
Module module;
|
||||
if( !is_xm( header_60_bytes ) ) {
|
||||
throw new IllegalArgumentException( "Not an XM file!" );
|
||||
}
|
||||
xm_version = unsigned_short_le( header_60_bytes, 58 );
|
||||
if( xm_version != 0x0104 ) {
|
||||
throw new IllegalArgumentException( "Sorry, XM version " + xm_version + " is not supported!" );
|
||||
}
|
||||
module = new Module();
|
||||
module.song_title = ascii_text( header_60_bytes, 17, 20 );
|
||||
tracker_name = ascii_text( header_60_bytes, 38, 20 );
|
||||
delta_env = tracker_name.startsWith( "DigiBooster Pro" );
|
||||
structure_header = new byte[ 4 ];
|
||||
data_input.readFully( structure_header );
|
||||
song_header_length = int_le( structure_header, 0 );
|
||||
song_header = new byte[ song_header_length ];
|
||||
data_input.readFully( song_header, 4, song_header_length - 4 );
|
||||
sequence_length = unsigned_short_le( song_header, 4 );
|
||||
module.restart_sequence_index = unsigned_short_le( song_header, 6 );
|
||||
num_channels = unsigned_short_le( song_header, 8 );
|
||||
num_patterns = unsigned_short_le( song_header, 10 );
|
||||
num_instruments = unsigned_short_le( song_header, 12 );
|
||||
xm_flags = unsigned_short_le( song_header, 14 );
|
||||
module.linear_periods = ( xm_flags & 0x1 ) == 0x1;
|
||||
module.global_volume = 64;
|
||||
module.channel_gain = IBXM.FP_ONE * 3 / 8;
|
||||
module.default_speed = unsigned_short_le( song_header, 16 );
|
||||
module.default_tempo = unsigned_short_le( song_header, 18 );
|
||||
module.set_num_channels( num_channels );
|
||||
for( idx = 0; idx < num_channels; idx++ ) {
|
||||
module.set_initial_panning( idx, 128 );
|
||||
}
|
||||
module.set_sequence_length( sequence_length );
|
||||
for( idx = 0; idx < sequence_length; idx++ ) {
|
||||
module.set_sequence( idx, song_header[ 20 + idx ] & 0xFF );
|
||||
}
|
||||
module.set_num_patterns( num_patterns );
|
||||
for( idx = 0; idx < num_patterns; idx++ ) {
|
||||
module.set_pattern( idx, read_xm_pattern( data_input, num_channels ) );
|
||||
}
|
||||
module.set_num_instruments( num_instruments );
|
||||
for( idx = 1; idx <= num_instruments; idx++ ) {
|
||||
try {
|
||||
instrument = read_xm_instrument( data_input, delta_env );
|
||||
module.set_instrument( idx, instrument );
|
||||
} catch( EOFException e ) {
|
||||
System.out.println( "Instrument " + idx + " is missing!" );
|
||||
}
|
||||
}
|
||||
return module;
|
||||
}
|
||||
|
||||
private static Pattern read_xm_pattern( DataInput data_input, int num_channels ) throws IOException {
|
||||
int pattern_header_length, packing_type, num_rows, pattern_data_length;
|
||||
byte[] structure_header, pattern_header, pattern_data;
|
||||
Pattern pattern;
|
||||
structure_header = new byte[ 4 ];
|
||||
data_input.readFully( structure_header );
|
||||
pattern_header_length = int_le( structure_header, 0 );
|
||||
pattern_header = new byte[ pattern_header_length ];
|
||||
data_input.readFully( pattern_header, 4, pattern_header_length - 4 );
|
||||
packing_type = pattern_header[ 4 ];
|
||||
if( packing_type != 0 ) {
|
||||
throw new IllegalArgumentException( "Pattern packing type " + packing_type + " is not supported!" );
|
||||
}
|
||||
pattern = new Pattern();
|
||||
pattern.num_rows = unsigned_short_le( pattern_header, 5 );
|
||||
pattern_data_length = unsigned_short_le( pattern_header, 7 );
|
||||
pattern_data = new byte[ pattern_data_length ];
|
||||
data_input.readFully( pattern_data );
|
||||
pattern.set_pattern_data( pattern_data );
|
||||
return pattern;
|
||||
}
|
||||
|
||||
private static Instrument read_xm_instrument( DataInput data_input, boolean delta_env ) throws IOException {
|
||||
int instrument_header_length, num_samples, idx;
|
||||
int env_tick, env_ampl, env_num_points, flags;
|
||||
byte[] structure_header, instrument_header, sample_headers;
|
||||
Instrument instrument;
|
||||
Envelope envelope;
|
||||
structure_header = new byte[ 4 ];
|
||||
data_input.readFully( structure_header );
|
||||
instrument_header_length = int_le( structure_header, 0 );
|
||||
instrument_header = new byte[ instrument_header_length ];
|
||||
data_input.readFully( instrument_header, 4, instrument_header_length - 4 );
|
||||
instrument = new Instrument();
|
||||
instrument.name = ascii_text( instrument_header, 4, 22 );
|
||||
num_samples = unsigned_short_le( instrument_header, 27 );
|
||||
if( num_samples > 0 ) {
|
||||
instrument.set_num_samples( num_samples );
|
||||
for( idx = 0; idx < 96; idx++ ) {
|
||||
instrument.set_key_to_sample( idx + 1, instrument_header[ 33 + idx ] & 0xFF );
|
||||
}
|
||||
envelope = new Envelope();
|
||||
env_num_points = instrument_header[ 225 ] & 0xFF;
|
||||
envelope.set_num_points( env_num_points );
|
||||
for( idx = 0; idx < env_num_points; idx++ ) {
|
||||
env_tick = unsigned_short_le( instrument_header, 129 + idx * 4 );
|
||||
env_ampl = unsigned_short_le( instrument_header, 131 + idx * 4 );
|
||||
envelope.set_point( idx, env_tick, env_ampl, delta_env );
|
||||
}
|
||||
envelope.set_sustain_point( instrument_header[ 227 ] & 0xFF );
|
||||
envelope.set_loop_points( instrument_header[ 228 ] & 0xFF, instrument_header[ 229 ] & 0xFF );
|
||||
flags = instrument_header[ 233 ] & 0xFF;
|
||||
instrument.volume_envelope_active = ( flags & 0x1 ) == 0x1;
|
||||
envelope.sustain = ( flags & 0x2 ) == 0x2;
|
||||
envelope.looped = ( flags & 0x4 ) == 0x4;
|
||||
instrument.set_volume_envelope( envelope );
|
||||
envelope = new Envelope();
|
||||
env_num_points = instrument_header[ 226 ] & 0xFF;
|
||||
envelope.set_num_points( env_num_points );
|
||||
for( idx = 0; idx < env_num_points; idx++ ) {
|
||||
env_tick = unsigned_short_le( instrument_header, 177 + idx * 4 );
|
||||
env_ampl = unsigned_short_le( instrument_header, 179 + idx * 4 );
|
||||
envelope.set_point( idx, env_tick, env_ampl, delta_env );
|
||||
}
|
||||
envelope.set_sustain_point( instrument_header[ 230 ] & 0xFF );
|
||||
envelope.set_loop_points( instrument_header[ 231 ] & 0xFF, instrument_header[ 232 ] & 0xFF );
|
||||
flags = instrument_header[ 234 ] & 0xFF;
|
||||
instrument.panning_envelope_active = ( flags & 0x1 ) == 0x1;
|
||||
envelope.sustain = ( flags & 0x2 ) == 0x2;
|
||||
envelope.looped = ( flags & 0x4 ) == 0x4;
|
||||
instrument.set_panning_envelope( envelope );
|
||||
instrument.vibrato_type = instrument_header[ 235 ] & 0xFF;
|
||||
instrument.vibrato_sweep = instrument_header[ 236 ] & 0xFF;
|
||||
instrument.vibrato_depth = instrument_header[ 237 ] & 0xFF;
|
||||
instrument.vibrato_rate = instrument_header[ 238 ] & 0xFF;
|
||||
instrument.volume_fade_out = unsigned_short_le( instrument_header, 239 );
|
||||
sample_headers = new byte[ num_samples * 40 ];
|
||||
data_input.readFully( sample_headers );
|
||||
for( idx = 0; idx < num_samples; idx++ ) {
|
||||
instrument.set_sample( idx, read_xm_sample( sample_headers, idx, data_input ) );
|
||||
}
|
||||
}
|
||||
return instrument;
|
||||
}
|
||||
|
||||
private static Sample read_xm_sample( byte[] sample_headers, int sample_idx, DataInput data_input ) throws IOException {
|
||||
int header_offset, sample_length, loop_start, loop_length;
|
||||
int flags, in_idx, out_idx, sam, last_sam;
|
||||
int fine_tune, relative_note;
|
||||
boolean sixteen_bit, ping_pong;
|
||||
byte[] raw_sample_data;
|
||||
short[] decoded_sample_data;
|
||||
Sample sample;
|
||||
header_offset = sample_idx * 40;
|
||||
sample = new Sample();
|
||||
sample_length = int_le( sample_headers, header_offset );
|
||||
loop_start = int_le( sample_headers, header_offset + 4 );
|
||||
loop_length = int_le( sample_headers, header_offset + 8 );
|
||||
sample.volume = sample_headers[ header_offset + 12 ] & 0xFF;
|
||||
fine_tune = sample_headers[ header_offset + 13 ];
|
||||
fine_tune = ( fine_tune << IBXM.FP_SHIFT ) / 1536;
|
||||
sample.set_panning = true;
|
||||
flags = sample_headers[ header_offset + 14 ] & 0xFF;
|
||||
if( ( flags & 0x03 ) == 0 ) {
|
||||
loop_length = 0;
|
||||
}
|
||||
ping_pong = ( flags & 0x02 ) == 0x02;
|
||||
sixteen_bit = ( flags & 0x10 ) == 0x10;
|
||||
sample.panning = sample_headers[ header_offset + 15 ] & 0xFF;
|
||||
relative_note = sample_headers[ header_offset + 16 ];
|
||||
relative_note = ( relative_note << IBXM.FP_SHIFT ) / 12;
|
||||
sample.transpose = relative_note + fine_tune;
|
||||
sample.name = ascii_text( sample_headers, header_offset + 18, 22 );
|
||||
raw_sample_data = new byte[ sample_length ];
|
||||
try {
|
||||
data_input.readFully( raw_sample_data );
|
||||
} catch( EOFException e ) {
|
||||
System.out.println( "Sample has been truncated!" );
|
||||
}
|
||||
in_idx = 0;
|
||||
out_idx = 0;
|
||||
sam = 0;
|
||||
last_sam = 0;
|
||||
if( sixteen_bit ) {
|
||||
decoded_sample_data = new short[ sample_length >> 1 ];
|
||||
while( in_idx < raw_sample_data.length ) {
|
||||
sam = raw_sample_data[ in_idx ] & 0xFF;
|
||||
sam = sam | ( ( raw_sample_data[ in_idx + 1 ] & 0xFF ) << 8 );
|
||||
last_sam = last_sam + sam;
|
||||
decoded_sample_data[ out_idx ] = ( short ) last_sam;
|
||||
in_idx += 2;
|
||||
out_idx += 1;
|
||||
}
|
||||
sample.set_sample_data( decoded_sample_data, loop_start >> 1, loop_length >> 1, ping_pong );
|
||||
} else {
|
||||
decoded_sample_data = new short[ sample_length ];
|
||||
while( in_idx < raw_sample_data.length ) {
|
||||
sam = raw_sample_data[ in_idx ] & 0xFF;
|
||||
last_sam = last_sam + sam;
|
||||
decoded_sample_data[ out_idx ] = ( short ) ( last_sam << 8 );
|
||||
in_idx += 1;
|
||||
out_idx += 1;
|
||||
}
|
||||
sample.set_sample_data( decoded_sample_data, loop_start, loop_length, ping_pong );
|
||||
}
|
||||
return sample;
|
||||
}
|
||||
|
||||
private static int unsigned_short_le( byte[] buffer, int offset ) {
|
||||
int value;
|
||||
value = buffer[ offset ] & 0xFF;
|
||||
value = value | ( ( buffer[ offset + 1 ] & 0xFF ) << 8 );
|
||||
return value;
|
||||
}
|
||||
|
||||
private static int int_le( byte[] buffer, int offset ) {
|
||||
int value;
|
||||
value = buffer[ offset ] & 0xFF;
|
||||
value = value | ( ( buffer[ offset + 1 ] & 0xFF ) << 8 );
|
||||
value = value | ( ( buffer[ offset + 2 ] & 0xFF ) << 16 );
|
||||
value = value | ( ( buffer[ offset + 3 ] & 0x7F ) << 24 );
|
||||
return value;
|
||||
}
|
||||
|
||||
private static String ascii_text( byte[] buffer, int offset, int length ) {
|
||||
int idx, chr;
|
||||
byte[] string_buffer;
|
||||
String string;
|
||||
string_buffer = new byte[ length ];
|
||||
for( idx = 0; idx < length; idx++ ) {
|
||||
chr = buffer[ offset + idx ];
|
||||
if( chr < 32 ) {
|
||||
chr = 32;
|
||||
}
|
||||
string_buffer[ idx ] = ( byte ) chr;
|
||||
}
|
||||
try {
|
||||
string = new String( string_buffer, 0, length, "ISO-8859-1" );
|
||||
} catch( UnsupportedEncodingException e ) {
|
||||
string = "";
|
||||
}
|
||||
return string;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,343 +1,343 @@
|
|||
|
||||
package ibxm;
|
||||
|
||||
public class IBXM {
|
||||
public static final String VERSION = "ibxm alpha 51 (c)2008 mumart@gmail.com";
|
||||
|
||||
public static final int FP_SHIFT = 15;
|
||||
public static final int FP_ONE = 1 << FP_SHIFT;
|
||||
public static final int FP_MASK = FP_ONE - 1;
|
||||
|
||||
private int sampling_rate, resampling_quality, volume_ramp_length;
|
||||
private int tick_length_samples, current_tick_samples;
|
||||
private int[] mixing_buffer, volume_ramp_buffer;
|
||||
|
||||
private Module module;
|
||||
private Channel[] channels;
|
||||
private int[] global_volume, note;
|
||||
private int current_sequence_index, next_sequence_index;
|
||||
private int current_row, next_row;
|
||||
private int tick_counter, ticks_per_row;
|
||||
private int pattern_loop_count, pattern_loop_channel;
|
||||
|
||||
public IBXM( int sample_rate ) {
|
||||
|
||||
/** MODIFIED 13 Oct 2009 by Paul Lamb **/
|
||||
// System.out.println( VERSION );
|
||||
/***************************************/
|
||||
|
||||
if( sample_rate < 8000 ) {
|
||||
sample_rate = 8000;
|
||||
}
|
||||
sampling_rate = sample_rate;
|
||||
volume_ramp_length = sampling_rate >> 10;
|
||||
volume_ramp_buffer = new int[ volume_ramp_length * 2 ];
|
||||
mixing_buffer = new int[ sampling_rate / 6 ];
|
||||
global_volume = new int[ 1 ];
|
||||
note = new int[ 5 ];
|
||||
set_module( new Module() );
|
||||
set_resampling_quality( 1 );
|
||||
}
|
||||
|
||||
public void set_module( Module m ) {
|
||||
int channel_idx;
|
||||
module = m;
|
||||
channels = new Channel[ module.get_num_channels() ];
|
||||
for( channel_idx = 0; channel_idx < channels.length; channel_idx++ ) {
|
||||
channels[ channel_idx ] = new Channel( module, sampling_rate, global_volume );
|
||||
}
|
||||
set_sequence_index( 0, 0 );
|
||||
}
|
||||
|
||||
public void set_resampling_quality( int quality ) {
|
||||
resampling_quality = quality;
|
||||
}
|
||||
|
||||
public int calculate_song_duration() {
|
||||
int song_duration;
|
||||
set_sequence_index( 0, 0 );
|
||||
next_tick();
|
||||
song_duration = tick_length_samples;
|
||||
while( !next_tick() ) {
|
||||
song_duration += tick_length_samples;
|
||||
}
|
||||
set_sequence_index( 0, 0 );
|
||||
return song_duration;
|
||||
}
|
||||
|
||||
public void set_sequence_index( int sequence_index, int row ) {
|
||||
int channel_idx;
|
||||
global_volume[ 0 ] = 64;
|
||||
for( channel_idx = 0; channel_idx < channels.length; channel_idx++ ) {
|
||||
channels[ channel_idx ].reset();
|
||||
channels[ channel_idx ].set_panning( module.get_initial_panning( channel_idx ) );
|
||||
}
|
||||
set_global_volume( module.global_volume );
|
||||
set_speed( 6 );
|
||||
set_speed( module.default_speed );
|
||||
set_tempo( 125 );
|
||||
set_tempo( module.default_tempo );
|
||||
pattern_loop_count = -1;
|
||||
next_sequence_index = sequence_index;
|
||||
next_row = row;
|
||||
tick_counter = 0;
|
||||
current_tick_samples = tick_length_samples;
|
||||
clear_vol_ramp_buffer();
|
||||
}
|
||||
|
||||
public void seek( int sample_position ) {
|
||||
int idx;
|
||||
set_sequence_index( 0, 0 );
|
||||
next_tick();
|
||||
while( sample_position > tick_length_samples ) {
|
||||
sample_position -= tick_length_samples;
|
||||
next_tick();
|
||||
}
|
||||
mix_tick();
|
||||
current_tick_samples = sample_position;
|
||||
}
|
||||
|
||||
public void get_audio( byte[] output_buffer, int frames ) {
|
||||
int output_idx, mix_idx, mix_end, count, amplitude;
|
||||
output_idx = 0;
|
||||
while( frames > 0 ) {
|
||||
count = tick_length_samples - current_tick_samples;
|
||||
if( count > frames ) {
|
||||
count = frames;
|
||||
}
|
||||
mix_idx = current_tick_samples << 1;
|
||||
mix_end = mix_idx + ( count << 1 ) - 1;
|
||||
while( mix_idx <= mix_end ) {
|
||||
amplitude = mixing_buffer[ mix_idx ];
|
||||
if( amplitude > 32767 ) {
|
||||
amplitude = 32767;
|
||||
}
|
||||
if( amplitude < -32768 ) {
|
||||
amplitude = -32768;
|
||||
}
|
||||
output_buffer[ output_idx ] = ( byte ) ( amplitude >> 8 );
|
||||
output_buffer[ output_idx + 1 ] = ( byte ) ( amplitude & 0xFF );
|
||||
output_idx += 2;
|
||||
mix_idx += 1;
|
||||
}
|
||||
current_tick_samples = mix_idx >> 1;
|
||||
frames -= count;
|
||||
if( frames > 0 ) {
|
||||
next_tick();
|
||||
mix_tick();
|
||||
current_tick_samples = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void mix_tick() {
|
||||
int channel_idx, mix_idx, mix_len;
|
||||
mix_idx = 0;
|
||||
mix_len = tick_length_samples + volume_ramp_length << 1;
|
||||
while( mix_idx < mix_len ) {
|
||||
mixing_buffer[ mix_idx ] = 0;
|
||||
mix_idx += 1;
|
||||
}
|
||||
for( channel_idx = 0; channel_idx < channels.length; channel_idx++ ) {
|
||||
mix_len = tick_length_samples + volume_ramp_length;
|
||||
channels[ channel_idx ].resample( mixing_buffer, 0, mix_len, resampling_quality );
|
||||
}
|
||||
volume_ramp();
|
||||
}
|
||||
|
||||
private boolean next_tick() {
|
||||
int channel_idx;
|
||||
boolean song_end;
|
||||
for( channel_idx = 0; channel_idx < channels.length; channel_idx++ ) {
|
||||
channels[ channel_idx ].update_sample_idx( tick_length_samples );
|
||||
}
|
||||
tick_counter -= 1;
|
||||
if( tick_counter <= 0 ) {
|
||||
tick_counter = ticks_per_row;
|
||||
song_end = next_row();
|
||||
} else {
|
||||
for( channel_idx = 0; channel_idx < channels.length; channel_idx++ ) {
|
||||
channels[ channel_idx ].tick();
|
||||
}
|
||||
song_end = false;
|
||||
}
|
||||
return song_end;
|
||||
}
|
||||
|
||||
private boolean next_row() {
|
||||
int channel_idx, effect, effect_param;
|
||||
boolean song_end;
|
||||
Pattern pattern;
|
||||
song_end = false;
|
||||
if( next_sequence_index < 0 ) {
|
||||
/* Bad next sequence index.*/
|
||||
next_sequence_index = 0;
|
||||
next_row = 0;
|
||||
}
|
||||
if( next_sequence_index >= module.get_sequence_length() ) {
|
||||
/* End of sequence.*/
|
||||
song_end = true;
|
||||
next_sequence_index = module.restart_sequence_index;
|
||||
if( next_sequence_index < 0 ) {
|
||||
next_sequence_index = 0;
|
||||
}
|
||||
if( next_sequence_index >= module.get_sequence_length() ) {
|
||||
next_sequence_index = 0;
|
||||
}
|
||||
next_row = 0;
|
||||
}
|
||||
if( next_sequence_index < current_sequence_index ) {
|
||||
/* Jump to previous pattern. */
|
||||
song_end = true;
|
||||
}
|
||||
if( next_sequence_index == current_sequence_index ) {
|
||||
if( next_row <= current_row ) {
|
||||
if( pattern_loop_count < 0 ) {
|
||||
/* Jump to previous row in the same pattern, but not a pattern loop. */
|
||||
song_end = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
current_sequence_index = next_sequence_index;
|
||||
pattern = module.get_pattern_from_sequence( current_sequence_index );
|
||||
if( next_row < 0 || next_row >= pattern.num_rows ) {
|
||||
/* Bad next row.*/
|
||||
next_row = 0;
|
||||
}
|
||||
current_row = next_row;
|
||||
next_row = current_row + 1;
|
||||
if( next_row >= pattern.num_rows ) {
|
||||
next_sequence_index = current_sequence_index + 1;
|
||||
next_row = 0;
|
||||
}
|
||||
for( channel_idx = 0; channel_idx < channels.length; channel_idx++ ) {
|
||||
pattern.get_note( note, current_row * channels.length + channel_idx );
|
||||
effect = note[ 3 ];
|
||||
effect_param = note[ 4 ];
|
||||
channels[ channel_idx ].row( note[ 0 ], note[ 1 ], note[ 2 ], effect, effect_param );
|
||||
switch( effect ) {
|
||||
case 0x0B:
|
||||
/* Pattern Jump.*/
|
||||
if( pattern_loop_count < 0 ) {
|
||||
next_sequence_index = effect_param;
|
||||
next_row = 0;
|
||||
}
|
||||
break;
|
||||
case 0x0D:
|
||||
/* Pattern Break.*/
|
||||
if( pattern_loop_count < 0 ) {
|
||||
next_sequence_index = current_sequence_index + 1;
|
||||
next_row = ( effect_param >> 4 ) * 10 + ( effect_param & 0x0F );
|
||||
}
|
||||
break;
|
||||
case 0x0E:
|
||||
/* Extended.*/
|
||||
switch( effect_param & 0xF0 ) {
|
||||
case 0x60:
|
||||
/* Pattern loop.*/
|
||||
if( ( effect_param & 0x0F ) == 0 ) {
|
||||
/* Set loop marker on this channel. */
|
||||
channels[ channel_idx ].pattern_loop_row = current_row;
|
||||
}
|
||||
if( channels[ channel_idx ].pattern_loop_row < current_row ) {
|
||||
/* Marker and parameter are valid. Begin looping. */
|
||||
if( pattern_loop_count < 0 ) {
|
||||
/* Not already looping, begin. */
|
||||
pattern_loop_count = effect_param & 0x0F;
|
||||
pattern_loop_channel = channel_idx;
|
||||
}
|
||||
if( pattern_loop_channel == channel_idx ) {
|
||||
/* Loop in progress on this channel. Next iteration. */
|
||||
if( pattern_loop_count == 0 ) {
|
||||
/* Loop finished. */
|
||||
/* Invalidate current marker. */
|
||||
channels[ channel_idx ].pattern_loop_row = current_row + 1;
|
||||
} else {
|
||||
/* Count must be higher than zero. */
|
||||
/* Loop and cancel any breaks on this row. */
|
||||
next_row = channels[ channel_idx ].pattern_loop_row;
|
||||
next_sequence_index = current_sequence_index;
|
||||
}
|
||||
pattern_loop_count -= 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xE0:
|
||||
/* Pattern delay.*/
|
||||
tick_counter += ticks_per_row * ( effect_param & 0x0F );
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x0F:
|
||||
/* Set Speed/Tempo.*/
|
||||
if( effect_param < 32 ) {
|
||||
set_speed( effect_param );
|
||||
tick_counter = ticks_per_row;
|
||||
} else {
|
||||
set_tempo( effect_param );
|
||||
}
|
||||
break;
|
||||
case 0x25:
|
||||
/* S3M Set Speed.*/
|
||||
set_speed( effect_param );
|
||||
tick_counter = ticks_per_row;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return song_end;
|
||||
}
|
||||
|
||||
private void set_global_volume( int volume ) {
|
||||
if( volume < 0 ) {
|
||||
volume = 0;
|
||||
}
|
||||
if( volume > 64 ) {
|
||||
volume = 64;
|
||||
}
|
||||
global_volume[ 0 ] = volume;
|
||||
}
|
||||
|
||||
private void set_speed( int speed ) {
|
||||
if( speed > 0 && speed < 256 ) {
|
||||
ticks_per_row = speed;
|
||||
}
|
||||
}
|
||||
|
||||
private void set_tempo( int bpm ) {
|
||||
if( bpm > 31 && bpm < 256 ) {
|
||||
tick_length_samples = ( sampling_rate * 5 ) / ( bpm * 2 );
|
||||
}
|
||||
}
|
||||
|
||||
private void volume_ramp() {
|
||||
int ramp_idx, next_idx, ramp_end;
|
||||
int volume_ramp_delta, volume, sample;
|
||||
sample = 0;
|
||||
volume_ramp_delta = FP_ONE / volume_ramp_length;
|
||||
volume = 0;
|
||||
ramp_idx = 0;
|
||||
next_idx = 2 * tick_length_samples;
|
||||
ramp_end = volume_ramp_length * 2 - 1;
|
||||
while( ramp_idx <= ramp_end ) {
|
||||
sample = volume_ramp_buffer[ ramp_idx ] * ( FP_ONE - volume ) >> FP_SHIFT;
|
||||
mixing_buffer[ ramp_idx ] = sample + ( mixing_buffer[ ramp_idx ] * volume >> FP_SHIFT );
|
||||
volume_ramp_buffer[ ramp_idx ] = mixing_buffer[ next_idx + ramp_idx ];
|
||||
sample = volume_ramp_buffer[ ramp_idx + 1 ] * ( FP_ONE - volume ) >> FP_SHIFT;
|
||||
mixing_buffer[ ramp_idx + 1 ] = sample + ( mixing_buffer[ ramp_idx + 1 ] * volume >> FP_SHIFT );
|
||||
volume_ramp_buffer[ ramp_idx + 1 ] = mixing_buffer[ next_idx + ramp_idx + 1 ];
|
||||
volume += volume_ramp_delta;
|
||||
ramp_idx += 2;
|
||||
}
|
||||
}
|
||||
|
||||
private void clear_vol_ramp_buffer() {
|
||||
int ramp_idx, ramp_end;
|
||||
ramp_idx = 0;
|
||||
ramp_end = volume_ramp_length * 2 - 1;
|
||||
while( ramp_idx <= ramp_end ) {
|
||||
volume_ramp_buffer[ ramp_idx ] = 0;
|
||||
ramp_idx += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
package ibxm;
|
||||
|
||||
public class IBXM {
|
||||
public static final String VERSION = "ibxm alpha 51 (c)2008 mumart@gmail.com";
|
||||
|
||||
public static final int FP_SHIFT = 15;
|
||||
public static final int FP_ONE = 1 << FP_SHIFT;
|
||||
public static final int FP_MASK = FP_ONE - 1;
|
||||
|
||||
private int sampling_rate, resampling_quality, volume_ramp_length;
|
||||
private int tick_length_samples, current_tick_samples;
|
||||
private int[] mixing_buffer, volume_ramp_buffer;
|
||||
|
||||
private Module module;
|
||||
private Channel[] channels;
|
||||
private int[] global_volume, note;
|
||||
private int current_sequence_index, next_sequence_index;
|
||||
private int current_row, next_row;
|
||||
private int tick_counter, ticks_per_row;
|
||||
private int pattern_loop_count, pattern_loop_channel;
|
||||
|
||||
public IBXM( int sample_rate ) {
|
||||
|
||||
/** MODIFIED 13 Oct 2009 by Paul Lamb **/
|
||||
// System.out.println( VERSION );
|
||||
/***************************************/
|
||||
|
||||
if( sample_rate < 8000 ) {
|
||||
sample_rate = 8000;
|
||||
}
|
||||
sampling_rate = sample_rate;
|
||||
volume_ramp_length = sampling_rate >> 10;
|
||||
volume_ramp_buffer = new int[ volume_ramp_length * 2 ];
|
||||
mixing_buffer = new int[ sampling_rate / 6 ];
|
||||
global_volume = new int[ 1 ];
|
||||
note = new int[ 5 ];
|
||||
set_module( new Module() );
|
||||
set_resampling_quality( 1 );
|
||||
}
|
||||
|
||||
public void set_module( Module m ) {
|
||||
int channel_idx;
|
||||
module = m;
|
||||
channels = new Channel[ module.get_num_channels() ];
|
||||
for( channel_idx = 0; channel_idx < channels.length; channel_idx++ ) {
|
||||
channels[ channel_idx ] = new Channel( module, sampling_rate, global_volume );
|
||||
}
|
||||
set_sequence_index( 0, 0 );
|
||||
}
|
||||
|
||||
public void set_resampling_quality( int quality ) {
|
||||
resampling_quality = quality;
|
||||
}
|
||||
|
||||
public int calculate_song_duration() {
|
||||
int song_duration;
|
||||
set_sequence_index( 0, 0 );
|
||||
next_tick();
|
||||
song_duration = tick_length_samples;
|
||||
while( !next_tick() ) {
|
||||
song_duration += tick_length_samples;
|
||||
}
|
||||
set_sequence_index( 0, 0 );
|
||||
return song_duration;
|
||||
}
|
||||
|
||||
public void set_sequence_index( int sequence_index, int row ) {
|
||||
int channel_idx;
|
||||
global_volume[ 0 ] = 64;
|
||||
for( channel_idx = 0; channel_idx < channels.length; channel_idx++ ) {
|
||||
channels[ channel_idx ].reset();
|
||||
channels[ channel_idx ].set_panning( module.get_initial_panning( channel_idx ) );
|
||||
}
|
||||
set_global_volume( module.global_volume );
|
||||
set_speed( 6 );
|
||||
set_speed( module.default_speed );
|
||||
set_tempo( 125 );
|
||||
set_tempo( module.default_tempo );
|
||||
pattern_loop_count = -1;
|
||||
next_sequence_index = sequence_index;
|
||||
next_row = row;
|
||||
tick_counter = 0;
|
||||
current_tick_samples = tick_length_samples;
|
||||
clear_vol_ramp_buffer();
|
||||
}
|
||||
|
||||
public void seek( int sample_position ) {
|
||||
int idx;
|
||||
set_sequence_index( 0, 0 );
|
||||
next_tick();
|
||||
while( sample_position > tick_length_samples ) {
|
||||
sample_position -= tick_length_samples;
|
||||
next_tick();
|
||||
}
|
||||
mix_tick();
|
||||
current_tick_samples = sample_position;
|
||||
}
|
||||
|
||||
public void get_audio( byte[] output_buffer, int frames ) {
|
||||
int output_idx, mix_idx, mix_end, count, amplitude;
|
||||
output_idx = 0;
|
||||
while( frames > 0 ) {
|
||||
count = tick_length_samples - current_tick_samples;
|
||||
if( count > frames ) {
|
||||
count = frames;
|
||||
}
|
||||
mix_idx = current_tick_samples << 1;
|
||||
mix_end = mix_idx + ( count << 1 ) - 1;
|
||||
while( mix_idx <= mix_end ) {
|
||||
amplitude = mixing_buffer[ mix_idx ];
|
||||
if( amplitude > 32767 ) {
|
||||
amplitude = 32767;
|
||||
}
|
||||
if( amplitude < -32768 ) {
|
||||
amplitude = -32768;
|
||||
}
|
||||
output_buffer[ output_idx ] = ( byte ) ( amplitude >> 8 );
|
||||
output_buffer[ output_idx + 1 ] = ( byte ) ( amplitude & 0xFF );
|
||||
output_idx += 2;
|
||||
mix_idx += 1;
|
||||
}
|
||||
current_tick_samples = mix_idx >> 1;
|
||||
frames -= count;
|
||||
if( frames > 0 ) {
|
||||
next_tick();
|
||||
mix_tick();
|
||||
current_tick_samples = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void mix_tick() {
|
||||
int channel_idx, mix_idx, mix_len;
|
||||
mix_idx = 0;
|
||||
mix_len = tick_length_samples + volume_ramp_length << 1;
|
||||
while( mix_idx < mix_len ) {
|
||||
mixing_buffer[ mix_idx ] = 0;
|
||||
mix_idx += 1;
|
||||
}
|
||||
for( channel_idx = 0; channel_idx < channels.length; channel_idx++ ) {
|
||||
mix_len = tick_length_samples + volume_ramp_length;
|
||||
channels[ channel_idx ].resample( mixing_buffer, 0, mix_len, resampling_quality );
|
||||
}
|
||||
volume_ramp();
|
||||
}
|
||||
|
||||
private boolean next_tick() {
|
||||
int channel_idx;
|
||||
boolean song_end;
|
||||
for( channel_idx = 0; channel_idx < channels.length; channel_idx++ ) {
|
||||
channels[ channel_idx ].update_sample_idx( tick_length_samples );
|
||||
}
|
||||
tick_counter -= 1;
|
||||
if( tick_counter <= 0 ) {
|
||||
tick_counter = ticks_per_row;
|
||||
song_end = next_row();
|
||||
} else {
|
||||
for( channel_idx = 0; channel_idx < channels.length; channel_idx++ ) {
|
||||
channels[ channel_idx ].tick();
|
||||
}
|
||||
song_end = false;
|
||||
}
|
||||
return song_end;
|
||||
}
|
||||
|
||||
private boolean next_row() {
|
||||
int channel_idx, effect, effect_param;
|
||||
boolean song_end;
|
||||
Pattern pattern;
|
||||
song_end = false;
|
||||
if( next_sequence_index < 0 ) {
|
||||
/* Bad next sequence index.*/
|
||||
next_sequence_index = 0;
|
||||
next_row = 0;
|
||||
}
|
||||
if( next_sequence_index >= module.get_sequence_length() ) {
|
||||
/* End of sequence.*/
|
||||
song_end = true;
|
||||
next_sequence_index = module.restart_sequence_index;
|
||||
if( next_sequence_index < 0 ) {
|
||||
next_sequence_index = 0;
|
||||
}
|
||||
if( next_sequence_index >= module.get_sequence_length() ) {
|
||||
next_sequence_index = 0;
|
||||
}
|
||||
next_row = 0;
|
||||
}
|
||||
if( next_sequence_index < current_sequence_index ) {
|
||||
/* Jump to previous pattern. */
|
||||
song_end = true;
|
||||
}
|
||||
if( next_sequence_index == current_sequence_index ) {
|
||||
if( next_row <= current_row ) {
|
||||
if( pattern_loop_count < 0 ) {
|
||||
/* Jump to previous row in the same pattern, but not a pattern loop. */
|
||||
song_end = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
current_sequence_index = next_sequence_index;
|
||||
pattern = module.get_pattern_from_sequence( current_sequence_index );
|
||||
if( next_row < 0 || next_row >= pattern.num_rows ) {
|
||||
/* Bad next row.*/
|
||||
next_row = 0;
|
||||
}
|
||||
current_row = next_row;
|
||||
next_row = current_row + 1;
|
||||
if( next_row >= pattern.num_rows ) {
|
||||
next_sequence_index = current_sequence_index + 1;
|
||||
next_row = 0;
|
||||
}
|
||||
for( channel_idx = 0; channel_idx < channels.length; channel_idx++ ) {
|
||||
pattern.get_note( note, current_row * channels.length + channel_idx );
|
||||
effect = note[ 3 ];
|
||||
effect_param = note[ 4 ];
|
||||
channels[ channel_idx ].row( note[ 0 ], note[ 1 ], note[ 2 ], effect, effect_param );
|
||||
switch( effect ) {
|
||||
case 0x0B:
|
||||
/* Pattern Jump.*/
|
||||
if( pattern_loop_count < 0 ) {
|
||||
next_sequence_index = effect_param;
|
||||
next_row = 0;
|
||||
}
|
||||
break;
|
||||
case 0x0D:
|
||||
/* Pattern Break.*/
|
||||
if( pattern_loop_count < 0 ) {
|
||||
next_sequence_index = current_sequence_index + 1;
|
||||
next_row = ( effect_param >> 4 ) * 10 + ( effect_param & 0x0F );
|
||||
}
|
||||
break;
|
||||
case 0x0E:
|
||||
/* Extended.*/
|
||||
switch( effect_param & 0xF0 ) {
|
||||
case 0x60:
|
||||
/* Pattern loop.*/
|
||||
if( ( effect_param & 0x0F ) == 0 ) {
|
||||
/* Set loop marker on this channel. */
|
||||
channels[ channel_idx ].pattern_loop_row = current_row;
|
||||
}
|
||||
if( channels[ channel_idx ].pattern_loop_row < current_row ) {
|
||||
/* Marker and parameter are valid. Begin looping. */
|
||||
if( pattern_loop_count < 0 ) {
|
||||
/* Not already looping, begin. */
|
||||
pattern_loop_count = effect_param & 0x0F;
|
||||
pattern_loop_channel = channel_idx;
|
||||
}
|
||||
if( pattern_loop_channel == channel_idx ) {
|
||||
/* Loop in progress on this channel. Next iteration. */
|
||||
if( pattern_loop_count == 0 ) {
|
||||
/* Loop finished. */
|
||||
/* Invalidate current marker. */
|
||||
channels[ channel_idx ].pattern_loop_row = current_row + 1;
|
||||
} else {
|
||||
/* Count must be higher than zero. */
|
||||
/* Loop and cancel any breaks on this row. */
|
||||
next_row = channels[ channel_idx ].pattern_loop_row;
|
||||
next_sequence_index = current_sequence_index;
|
||||
}
|
||||
pattern_loop_count -= 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xE0:
|
||||
/* Pattern delay.*/
|
||||
tick_counter += ticks_per_row * ( effect_param & 0x0F );
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x0F:
|
||||
/* Set Speed/Tempo.*/
|
||||
if( effect_param < 32 ) {
|
||||
set_speed( effect_param );
|
||||
tick_counter = ticks_per_row;
|
||||
} else {
|
||||
set_tempo( effect_param );
|
||||
}
|
||||
break;
|
||||
case 0x25:
|
||||
/* S3M Set Speed.*/
|
||||
set_speed( effect_param );
|
||||
tick_counter = ticks_per_row;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return song_end;
|
||||
}
|
||||
|
||||
private void set_global_volume( int volume ) {
|
||||
if( volume < 0 ) {
|
||||
volume = 0;
|
||||
}
|
||||
if( volume > 64 ) {
|
||||
volume = 64;
|
||||
}
|
||||
global_volume[ 0 ] = volume;
|
||||
}
|
||||
|
||||
private void set_speed( int speed ) {
|
||||
if( speed > 0 && speed < 256 ) {
|
||||
ticks_per_row = speed;
|
||||
}
|
||||
}
|
||||
|
||||
private void set_tempo( int bpm ) {
|
||||
if( bpm > 31 && bpm < 256 ) {
|
||||
tick_length_samples = ( sampling_rate * 5 ) / ( bpm * 2 );
|
||||
}
|
||||
}
|
||||
|
||||
private void volume_ramp() {
|
||||
int ramp_idx, next_idx, ramp_end;
|
||||
int volume_ramp_delta, volume, sample;
|
||||
sample = 0;
|
||||
volume_ramp_delta = FP_ONE / volume_ramp_length;
|
||||
volume = 0;
|
||||
ramp_idx = 0;
|
||||
next_idx = 2 * tick_length_samples;
|
||||
ramp_end = volume_ramp_length * 2 - 1;
|
||||
while( ramp_idx <= ramp_end ) {
|
||||
sample = volume_ramp_buffer[ ramp_idx ] * ( FP_ONE - volume ) >> FP_SHIFT;
|
||||
mixing_buffer[ ramp_idx ] = sample + ( mixing_buffer[ ramp_idx ] * volume >> FP_SHIFT );
|
||||
volume_ramp_buffer[ ramp_idx ] = mixing_buffer[ next_idx + ramp_idx ];
|
||||
sample = volume_ramp_buffer[ ramp_idx + 1 ] * ( FP_ONE - volume ) >> FP_SHIFT;
|
||||
mixing_buffer[ ramp_idx + 1 ] = sample + ( mixing_buffer[ ramp_idx + 1 ] * volume >> FP_SHIFT );
|
||||
volume_ramp_buffer[ ramp_idx + 1 ] = mixing_buffer[ next_idx + ramp_idx + 1 ];
|
||||
volume += volume_ramp_delta;
|
||||
ramp_idx += 2;
|
||||
}
|
||||
}
|
||||
|
||||
private void clear_vol_ramp_buffer() {
|
||||
int ramp_idx, ramp_end;
|
||||
ramp_idx = 0;
|
||||
ramp_end = volume_ramp_length * 2 - 1;
|
||||
while( ramp_idx <= ramp_end ) {
|
||||
volume_ramp_buffer[ ramp_idx ] = 0;
|
||||
ramp_idx += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,90 +1,90 @@
|
|||
|
||||
package ibxm;
|
||||
|
||||
public class Instrument {
|
||||
public String name;
|
||||
public int vibrato_type, vibrato_sweep;
|
||||
public int vibrato_depth, vibrato_rate;
|
||||
public boolean volume_envelope_active, panning_envelope_active;
|
||||
public int volume_fade_out;
|
||||
|
||||
private Envelope volume_envelope, panning_envelope;
|
||||
private int[] key_to_sample;
|
||||
private Sample[] samples;
|
||||
|
||||
public Instrument() {
|
||||
name = "";
|
||||
set_volume_envelope( new Envelope() );
|
||||
set_panning_envelope( new Envelope() );
|
||||
key_to_sample = new int[ 96 ];
|
||||
set_num_samples( 1 );
|
||||
}
|
||||
|
||||
public Envelope get_volume_envelope() {
|
||||
return volume_envelope;
|
||||
}
|
||||
|
||||
public void set_volume_envelope( Envelope envelope ) {
|
||||
if( envelope != null ) {
|
||||
volume_envelope = envelope;
|
||||
}
|
||||
}
|
||||
|
||||
public Envelope get_panning_envelope() {
|
||||
return panning_envelope;
|
||||
}
|
||||
|
||||
public void set_panning_envelope( Envelope envelope ) {
|
||||
if( envelope != null ) {
|
||||
panning_envelope = envelope;
|
||||
}
|
||||
}
|
||||
|
||||
public Sample get_sample_from_key( int key ) {
|
||||
int sample_idx;
|
||||
sample_idx = 0;
|
||||
if( key > 0 && key <= key_to_sample.length ) {
|
||||
sample_idx = key_to_sample[ key - 1 ];
|
||||
}
|
||||
return get_sample( sample_idx );
|
||||
}
|
||||
|
||||
public void set_key_to_sample( int key, int sample ) {
|
||||
if( key > 0 && key <= key_to_sample.length ) {
|
||||
key_to_sample[ key - 1 ] = sample;
|
||||
}
|
||||
}
|
||||
|
||||
public int get_num_samples() {
|
||||
return samples.length;
|
||||
}
|
||||
|
||||
public void set_num_samples( int num_samples ) {
|
||||
if( num_samples < 1 ) {
|
||||
num_samples = 1;
|
||||
}
|
||||
samples = new Sample[ num_samples ];
|
||||
set_sample( 0, null );
|
||||
}
|
||||
|
||||
public Sample get_sample( int sample_index ) {
|
||||
Sample sample;
|
||||
sample = null;
|
||||
if( sample_index >= 0 && sample_index < samples.length ) {
|
||||
sample = samples[ sample_index ];
|
||||
}
|
||||
if( sample == null ) {
|
||||
sample = samples[ 0 ];
|
||||
}
|
||||
return sample;
|
||||
}
|
||||
|
||||
public void set_sample( int sample_index, Sample sample ) {
|
||||
if( sample_index >= 0 && sample_index < samples.length ) {
|
||||
samples[ sample_index ] = sample;
|
||||
}
|
||||
if( samples[ 0 ] == null ) {
|
||||
samples[ 0 ] = new Sample();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
package ibxm;
|
||||
|
||||
public class Instrument {
|
||||
public String name;
|
||||
public int vibrato_type, vibrato_sweep;
|
||||
public int vibrato_depth, vibrato_rate;
|
||||
public boolean volume_envelope_active, panning_envelope_active;
|
||||
public int volume_fade_out;
|
||||
|
||||
private Envelope volume_envelope, panning_envelope;
|
||||
private int[] key_to_sample;
|
||||
private Sample[] samples;
|
||||
|
||||
public Instrument() {
|
||||
name = "";
|
||||
set_volume_envelope( new Envelope() );
|
||||
set_panning_envelope( new Envelope() );
|
||||
key_to_sample = new int[ 96 ];
|
||||
set_num_samples( 1 );
|
||||
}
|
||||
|
||||
public Envelope get_volume_envelope() {
|
||||
return volume_envelope;
|
||||
}
|
||||
|
||||
public void set_volume_envelope( Envelope envelope ) {
|
||||
if( envelope != null ) {
|
||||
volume_envelope = envelope;
|
||||
}
|
||||
}
|
||||
|
||||
public Envelope get_panning_envelope() {
|
||||
return panning_envelope;
|
||||
}
|
||||
|
||||
public void set_panning_envelope( Envelope envelope ) {
|
||||
if( envelope != null ) {
|
||||
panning_envelope = envelope;
|
||||
}
|
||||
}
|
||||
|
||||
public Sample get_sample_from_key( int key ) {
|
||||
int sample_idx;
|
||||
sample_idx = 0;
|
||||
if( key > 0 && key <= key_to_sample.length ) {
|
||||
sample_idx = key_to_sample[ key - 1 ];
|
||||
}
|
||||
return get_sample( sample_idx );
|
||||
}
|
||||
|
||||
public void set_key_to_sample( int key, int sample ) {
|
||||
if( key > 0 && key <= key_to_sample.length ) {
|
||||
key_to_sample[ key - 1 ] = sample;
|
||||
}
|
||||
}
|
||||
|
||||
public int get_num_samples() {
|
||||
return samples.length;
|
||||
}
|
||||
|
||||
public void set_num_samples( int num_samples ) {
|
||||
if( num_samples < 1 ) {
|
||||
num_samples = 1;
|
||||
}
|
||||
samples = new Sample[ num_samples ];
|
||||
set_sample( 0, null );
|
||||
}
|
||||
|
||||
public Sample get_sample( int sample_index ) {
|
||||
Sample sample;
|
||||
sample = null;
|
||||
if( sample_index >= 0 && sample_index < samples.length ) {
|
||||
sample = samples[ sample_index ];
|
||||
}
|
||||
if( sample == null ) {
|
||||
sample = samples[ 0 ];
|
||||
}
|
||||
return sample;
|
||||
}
|
||||
|
||||
public void set_sample( int sample_index, Sample sample ) {
|
||||
if( sample_index >= 0 && sample_index < samples.length ) {
|
||||
samples[ sample_index ] = sample;
|
||||
}
|
||||
if( samples[ 0 ] == null ) {
|
||||
samples[ 0 ] = new Sample();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,91 +1,91 @@
|
|||
|
||||
package ibxm;
|
||||
|
||||
/*
|
||||
Base-2 Log and Exp functions, using linear-interpolated tables.
|
||||
*/
|
||||
public class LogTable {
|
||||
private static final int TABLE_SHIFT = 7; // 128 points (+1 for interp)
|
||||
private static final int INTERP_SHIFT = IBXM.FP_SHIFT - TABLE_SHIFT;
|
||||
private static final int INTERP_MASK = ( 1 << INTERP_SHIFT ) - 1;
|
||||
|
||||
private static final int[] exp_2_table = {
|
||||
32768, 32945, 33124, 33304, 33485, 33667, 33850, 34033,
|
||||
34218, 34404, 34591, 34779, 34968, 35157, 35348, 35540,
|
||||
35733, 35927, 36122, 36319, 36516, 36714, 36913, 37114,
|
||||
37315, 37518, 37722, 37926, 38132, 38339, 38548, 38757,
|
||||
38967, 39179, 39392, 39606, 39821, 40037, 40254, 40473,
|
||||
40693, 40914, 41136, 41359, 41584, 41810, 42037, 42265,
|
||||
42494, 42725, 42957, 43190, 43425, 43661, 43898, 44136,
|
||||
44376, 44617, 44859, 45103, 45347, 45594, 45841, 46090,
|
||||
46340, 46592, 46845, 47099, 47355, 47612, 47871, 48131,
|
||||
48392, 48655, 48919, 49185, 49452, 49720, 49990, 50262,
|
||||
50535, 50809, 51085, 51362, 51641, 51922, 52204, 52487,
|
||||
52772, 53059, 53347, 53636, 53928, 54220, 54515, 54811,
|
||||
55108, 55408, 55709, 56011, 56315, 56621, 56928, 57238,
|
||||
57548, 57861, 58175, 58491, 58809, 59128, 59449, 59772,
|
||||
60096, 60423, 60751, 61081, 61412, 61746, 62081, 62418,
|
||||
62757, 63098, 63440, 63785, 64131, 64479, 64830, 65182,
|
||||
65536
|
||||
};
|
||||
|
||||
private static final int[] log_2_table = {
|
||||
0, 367, 732, 1095, 1454, 1811, 2165, 2517,
|
||||
2865, 3212, 3556, 3897, 4236, 4572, 4906, 5238,
|
||||
5568, 5895, 6220, 6542, 6863, 7181, 7497, 7812,
|
||||
8124, 8434, 8742, 9048, 9352, 9654, 9954, 10252,
|
||||
10548, 10843, 11136, 11427, 11716, 12003, 12289, 12573,
|
||||
12855, 13136, 13414, 13692, 13967, 14241, 14514, 14785,
|
||||
15054, 15322, 15588, 15853, 16117, 16378, 16639, 16898,
|
||||
17156, 17412, 17667, 17920, 18172, 18423, 18673, 18921,
|
||||
19168, 19413, 19657, 19900, 20142, 20383, 20622, 20860,
|
||||
21097, 21333, 21568, 21801, 22034, 22265, 22495, 22724,
|
||||
22952, 23178, 23404, 23628, 23852, 24074, 24296, 24516,
|
||||
24736, 24954, 25171, 25388, 25603, 25817, 26031, 26243,
|
||||
26455, 26665, 26875, 27084, 27292, 27499, 27705, 27910,
|
||||
28114, 28317, 28520, 28721, 28922, 29122, 29321, 29519,
|
||||
29716, 29913, 30109, 30304, 30498, 30691, 30884, 31076,
|
||||
31267, 31457, 31646, 31835, 32023, 32210, 32397, 32582,
|
||||
32768
|
||||
};
|
||||
|
||||
/*
|
||||
Calculate log-base-2 of x (non-fixed-point).
|
||||
A fixed point value is returned.
|
||||
*/
|
||||
public static int log_2( int x ) {
|
||||
int shift;
|
||||
/* Scale x to range 1.0 <= x < 2.0 */
|
||||
shift = IBXM.FP_SHIFT;
|
||||
while( x < IBXM.FP_ONE ) {
|
||||
x <<= 1;
|
||||
shift--;
|
||||
}
|
||||
while( x >= ( IBXM.FP_ONE << 1 ) ) {
|
||||
x >>= 1;
|
||||
shift++;
|
||||
}
|
||||
return ( IBXM.FP_ONE * shift ) + eval_table( log_2_table, x - IBXM.FP_ONE );
|
||||
}
|
||||
|
||||
/*
|
||||
Raise 2 to the power x (fixed point).
|
||||
A fixed point value is returned.
|
||||
*/
|
||||
public static int raise_2( int x ) {
|
||||
int y;
|
||||
y = eval_table( exp_2_table, x & IBXM.FP_MASK ) << IBXM.FP_SHIFT;
|
||||
return y >> IBXM.FP_SHIFT - ( x >> IBXM.FP_SHIFT );
|
||||
}
|
||||
|
||||
private static int eval_table( int[] table, int x ) {
|
||||
int table_idx, table_frac, c, m, y;
|
||||
table_idx = x >> INTERP_SHIFT;
|
||||
table_frac = x & INTERP_MASK;
|
||||
c = table[ table_idx ];
|
||||
m = table[ table_idx + 1 ] - c;
|
||||
y = ( m * table_frac >> INTERP_SHIFT ) + c;
|
||||
return y >> 15 - IBXM.FP_SHIFT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
package ibxm;
|
||||
|
||||
/*
|
||||
Base-2 Log and Exp functions, using linear-interpolated tables.
|
||||
*/
|
||||
public class LogTable {
|
||||
private static final int TABLE_SHIFT = 7; // 128 points (+1 for interp)
|
||||
private static final int INTERP_SHIFT = IBXM.FP_SHIFT - TABLE_SHIFT;
|
||||
private static final int INTERP_MASK = ( 1 << INTERP_SHIFT ) - 1;
|
||||
|
||||
private static final int[] exp_2_table = {
|
||||
32768, 32945, 33124, 33304, 33485, 33667, 33850, 34033,
|
||||
34218, 34404, 34591, 34779, 34968, 35157, 35348, 35540,
|
||||
35733, 35927, 36122, 36319, 36516, 36714, 36913, 37114,
|
||||
37315, 37518, 37722, 37926, 38132, 38339, 38548, 38757,
|
||||
38967, 39179, 39392, 39606, 39821, 40037, 40254, 40473,
|
||||
40693, 40914, 41136, 41359, 41584, 41810, 42037, 42265,
|
||||
42494, 42725, 42957, 43190, 43425, 43661, 43898, 44136,
|
||||
44376, 44617, 44859, 45103, 45347, 45594, 45841, 46090,
|
||||
46340, 46592, 46845, 47099, 47355, 47612, 47871, 48131,
|
||||
48392, 48655, 48919, 49185, 49452, 49720, 49990, 50262,
|
||||
50535, 50809, 51085, 51362, 51641, 51922, 52204, 52487,
|
||||
52772, 53059, 53347, 53636, 53928, 54220, 54515, 54811,
|
||||
55108, 55408, 55709, 56011, 56315, 56621, 56928, 57238,
|
||||
57548, 57861, 58175, 58491, 58809, 59128, 59449, 59772,
|
||||
60096, 60423, 60751, 61081, 61412, 61746, 62081, 62418,
|
||||
62757, 63098, 63440, 63785, 64131, 64479, 64830, 65182,
|
||||
65536
|
||||
};
|
||||
|
||||
private static final int[] log_2_table = {
|
||||
0, 367, 732, 1095, 1454, 1811, 2165, 2517,
|
||||
2865, 3212, 3556, 3897, 4236, 4572, 4906, 5238,
|
||||
5568, 5895, 6220, 6542, 6863, 7181, 7497, 7812,
|
||||
8124, 8434, 8742, 9048, 9352, 9654, 9954, 10252,
|
||||
10548, 10843, 11136, 11427, 11716, 12003, 12289, 12573,
|
||||
12855, 13136, 13414, 13692, 13967, 14241, 14514, 14785,
|
||||
15054, 15322, 15588, 15853, 16117, 16378, 16639, 16898,
|
||||
17156, 17412, 17667, 17920, 18172, 18423, 18673, 18921,
|
||||
19168, 19413, 19657, 19900, 20142, 20383, 20622, 20860,
|
||||
21097, 21333, 21568, 21801, 22034, 22265, 22495, 22724,
|
||||
22952, 23178, 23404, 23628, 23852, 24074, 24296, 24516,
|
||||
24736, 24954, 25171, 25388, 25603, 25817, 26031, 26243,
|
||||
26455, 26665, 26875, 27084, 27292, 27499, 27705, 27910,
|
||||
28114, 28317, 28520, 28721, 28922, 29122, 29321, 29519,
|
||||
29716, 29913, 30109, 30304, 30498, 30691, 30884, 31076,
|
||||
31267, 31457, 31646, 31835, 32023, 32210, 32397, 32582,
|
||||
32768
|
||||
};
|
||||
|
||||
/*
|
||||
Calculate log-base-2 of x (non-fixed-point).
|
||||
A fixed point value is returned.
|
||||
*/
|
||||
public static int log_2( int x ) {
|
||||
int shift;
|
||||
/* Scale x to range 1.0 <= x < 2.0 */
|
||||
shift = IBXM.FP_SHIFT;
|
||||
while( x < IBXM.FP_ONE ) {
|
||||
x <<= 1;
|
||||
shift--;
|
||||
}
|
||||
while( x >= ( IBXM.FP_ONE << 1 ) ) {
|
||||
x >>= 1;
|
||||
shift++;
|
||||
}
|
||||
return ( IBXM.FP_ONE * shift ) + eval_table( log_2_table, x - IBXM.FP_ONE );
|
||||
}
|
||||
|
||||
/*
|
||||
Raise 2 to the power x (fixed point).
|
||||
A fixed point value is returned.
|
||||
*/
|
||||
public static int raise_2( int x ) {
|
||||
int y;
|
||||
y = eval_table( exp_2_table, x & IBXM.FP_MASK ) << IBXM.FP_SHIFT;
|
||||
return y >> IBXM.FP_SHIFT - ( x >> IBXM.FP_SHIFT );
|
||||
}
|
||||
|
||||
private static int eval_table( int[] table, int x ) {
|
||||
int table_idx, table_frac, c, m, y;
|
||||
table_idx = x >> INTERP_SHIFT;
|
||||
table_frac = x & INTERP_MASK;
|
||||
c = table[ table_idx ];
|
||||
m = table[ table_idx + 1 ] - c;
|
||||
y = ( m * table_frac >> INTERP_SHIFT ) + c;
|
||||
return y >> 15 - IBXM.FP_SHIFT;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,138 +1,138 @@
|
|||
|
||||
package ibxm;
|
||||
|
||||
public class Module {
|
||||
public String song_title;
|
||||
public boolean linear_periods, fast_volume_slides, pal;
|
||||
public int global_volume, channel_gain;
|
||||
public int default_speed, default_tempo;
|
||||
public int restart_sequence_index;
|
||||
|
||||
private int[] initial_panning, sequence;
|
||||
private Pattern[] patterns;
|
||||
private Instrument[] instruments;
|
||||
|
||||
private Pattern default_pattern;
|
||||
private Instrument default_instrument;
|
||||
|
||||
public Module() {
|
||||
song_title = IBXM.VERSION;
|
||||
set_num_channels( 1 );
|
||||
set_sequence_length( 1 );
|
||||
set_num_patterns( 0 );
|
||||
set_num_instruments( 0 );
|
||||
default_pattern = new Pattern();
|
||||
default_instrument = new Instrument();
|
||||
}
|
||||
|
||||
public int get_num_channels() {
|
||||
return initial_panning.length;
|
||||
}
|
||||
|
||||
public void set_num_channels( int num_channels ) {
|
||||
if( num_channels < 1 ) {
|
||||
num_channels = 1;
|
||||
}
|
||||
initial_panning = new int[ num_channels ];
|
||||
}
|
||||
|
||||
public int get_initial_panning( int channel ) {
|
||||
int panning;
|
||||
panning = 128;
|
||||
if( channel >= 0 && channel < initial_panning.length ) {
|
||||
panning = initial_panning[ channel ];
|
||||
}
|
||||
return panning;
|
||||
}
|
||||
|
||||
public void set_initial_panning( int channel, int panning ) {
|
||||
if( channel >= 0 && channel < initial_panning.length ) {
|
||||
initial_panning[ channel ] = panning;
|
||||
}
|
||||
}
|
||||
|
||||
public int get_sequence_length() {
|
||||
return sequence.length;
|
||||
}
|
||||
|
||||
public void set_sequence_length( int sequence_length ) {
|
||||
if( sequence_length < 0 ) {
|
||||
sequence_length = 0;
|
||||
}
|
||||
sequence = new int[ sequence_length ];
|
||||
}
|
||||
|
||||
public void set_sequence( int sequence_index, int pattern_index ) {
|
||||
if( sequence_index >= 0 && sequence_index < sequence.length ) {
|
||||
sequence[ sequence_index ] = pattern_index;
|
||||
}
|
||||
}
|
||||
|
||||
public int get_num_patterns() {
|
||||
return patterns.length;
|
||||
}
|
||||
|
||||
public void set_num_patterns( int num_patterns ) {
|
||||
if( num_patterns < 0 ) {
|
||||
num_patterns = 0;
|
||||
}
|
||||
patterns = new Pattern[ num_patterns ];
|
||||
}
|
||||
|
||||
public Pattern get_pattern_from_sequence( int sequence_index ) {
|
||||
Pattern pattern;
|
||||
pattern = default_pattern;
|
||||
if( sequence_index >= 0 && sequence_index < sequence.length ) {
|
||||
pattern = get_pattern( sequence[ sequence_index ] );
|
||||
}
|
||||
return pattern;
|
||||
}
|
||||
|
||||
public Pattern get_pattern( int pattern_index ) {
|
||||
Pattern pattern;
|
||||
pattern = null;
|
||||
if( pattern_index >= 0 && pattern_index < patterns.length ) {
|
||||
pattern = patterns[ pattern_index ];
|
||||
}
|
||||
if( pattern == null ) {
|
||||
pattern = default_pattern;
|
||||
}
|
||||
return pattern;
|
||||
}
|
||||
|
||||
public void set_pattern( int pattern_index, Pattern pattern ) {
|
||||
if( pattern_index >= 0 && pattern_index < patterns.length ) {
|
||||
patterns[ pattern_index ] = pattern;
|
||||
}
|
||||
}
|
||||
|
||||
public int get_num_instruments() {
|
||||
return instruments.length;
|
||||
}
|
||||
|
||||
public void set_num_instruments( int num_instruments ) {
|
||||
if( num_instruments < 0 ) {
|
||||
num_instruments = 0;
|
||||
}
|
||||
instruments = new Instrument[ num_instruments ];
|
||||
}
|
||||
|
||||
public Instrument get_instrument( int instrument_index ) {
|
||||
Instrument instrument;
|
||||
instrument = null;
|
||||
if( instrument_index > 0 && instrument_index <= instruments.length ) {
|
||||
instrument = instruments[ instrument_index - 1 ];
|
||||
}
|
||||
if( instrument == null ) {
|
||||
instrument = default_instrument;
|
||||
}
|
||||
return instrument;
|
||||
}
|
||||
|
||||
public void set_instrument( int instrument_index, Instrument instrument ) {
|
||||
if( instrument_index > 0 && instrument_index <= instruments.length ) {
|
||||
instruments[ instrument_index - 1 ] = instrument;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
package ibxm;
|
||||
|
||||
public class Module {
|
||||
public String song_title;
|
||||
public boolean linear_periods, fast_volume_slides, pal;
|
||||
public int global_volume, channel_gain;
|
||||
public int default_speed, default_tempo;
|
||||
public int restart_sequence_index;
|
||||
|
||||
private int[] initial_panning, sequence;
|
||||
private Pattern[] patterns;
|
||||
private Instrument[] instruments;
|
||||
|
||||
private Pattern default_pattern;
|
||||
private Instrument default_instrument;
|
||||
|
||||
public Module() {
|
||||
song_title = IBXM.VERSION;
|
||||
set_num_channels( 1 );
|
||||
set_sequence_length( 1 );
|
||||
set_num_patterns( 0 );
|
||||
set_num_instruments( 0 );
|
||||
default_pattern = new Pattern();
|
||||
default_instrument = new Instrument();
|
||||
}
|
||||
|
||||
public int get_num_channels() {
|
||||
return initial_panning.length;
|
||||
}
|
||||
|
||||
public void set_num_channels( int num_channels ) {
|
||||
if( num_channels < 1 ) {
|
||||
num_channels = 1;
|
||||
}
|
||||
initial_panning = new int[ num_channels ];
|
||||
}
|
||||
|
||||
public int get_initial_panning( int channel ) {
|
||||
int panning;
|
||||
panning = 128;
|
||||
if( channel >= 0 && channel < initial_panning.length ) {
|
||||
panning = initial_panning[ channel ];
|
||||
}
|
||||
return panning;
|
||||
}
|
||||
|
||||
public void set_initial_panning( int channel, int panning ) {
|
||||
if( channel >= 0 && channel < initial_panning.length ) {
|
||||
initial_panning[ channel ] = panning;
|
||||
}
|
||||
}
|
||||
|
||||
public int get_sequence_length() {
|
||||
return sequence.length;
|
||||
}
|
||||
|
||||
public void set_sequence_length( int sequence_length ) {
|
||||
if( sequence_length < 0 ) {
|
||||
sequence_length = 0;
|
||||
}
|
||||
sequence = new int[ sequence_length ];
|
||||
}
|
||||
|
||||
public void set_sequence( int sequence_index, int pattern_index ) {
|
||||
if( sequence_index >= 0 && sequence_index < sequence.length ) {
|
||||
sequence[ sequence_index ] = pattern_index;
|
||||
}
|
||||
}
|
||||
|
||||
public int get_num_patterns() {
|
||||
return patterns.length;
|
||||
}
|
||||
|
||||
public void set_num_patterns( int num_patterns ) {
|
||||
if( num_patterns < 0 ) {
|
||||
num_patterns = 0;
|
||||
}
|
||||
patterns = new Pattern[ num_patterns ];
|
||||
}
|
||||
|
||||
public Pattern get_pattern_from_sequence( int sequence_index ) {
|
||||
Pattern pattern;
|
||||
pattern = default_pattern;
|
||||
if( sequence_index >= 0 && sequence_index < sequence.length ) {
|
||||
pattern = get_pattern( sequence[ sequence_index ] );
|
||||
}
|
||||
return pattern;
|
||||
}
|
||||
|
||||
public Pattern get_pattern( int pattern_index ) {
|
||||
Pattern pattern;
|
||||
pattern = null;
|
||||
if( pattern_index >= 0 && pattern_index < patterns.length ) {
|
||||
pattern = patterns[ pattern_index ];
|
||||
}
|
||||
if( pattern == null ) {
|
||||
pattern = default_pattern;
|
||||
}
|
||||
return pattern;
|
||||
}
|
||||
|
||||
public void set_pattern( int pattern_index, Pattern pattern ) {
|
||||
if( pattern_index >= 0 && pattern_index < patterns.length ) {
|
||||
patterns[ pattern_index ] = pattern;
|
||||
}
|
||||
}
|
||||
|
||||
public int get_num_instruments() {
|
||||
return instruments.length;
|
||||
}
|
||||
|
||||
public void set_num_instruments( int num_instruments ) {
|
||||
if( num_instruments < 0 ) {
|
||||
num_instruments = 0;
|
||||
}
|
||||
instruments = new Instrument[ num_instruments ];
|
||||
}
|
||||
|
||||
public Instrument get_instrument( int instrument_index ) {
|
||||
Instrument instrument;
|
||||
instrument = null;
|
||||
if( instrument_index > 0 && instrument_index <= instruments.length ) {
|
||||
instrument = instruments[ instrument_index - 1 ];
|
||||
}
|
||||
if( instrument == null ) {
|
||||
instrument = default_instrument;
|
||||
}
|
||||
return instrument;
|
||||
}
|
||||
|
||||
public void set_instrument( int instrument_index, Instrument instrument ) {
|
||||
if( instrument_index > 0 && instrument_index <= instruments.length ) {
|
||||
instruments[ instrument_index - 1 ] = instrument;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,61 +1,61 @@
|
|||
|
||||
package ibxm;
|
||||
|
||||
public class Pattern {
|
||||
public int num_rows;
|
||||
|
||||
private int data_offset, note_index;
|
||||
private byte[] pattern_data;
|
||||
|
||||
public Pattern() {
|
||||
num_rows = 1;
|
||||
set_pattern_data( new byte[ 0 ] );
|
||||
}
|
||||
|
||||
public void set_pattern_data( byte[] data ) {
|
||||
if( data != null ) {
|
||||
pattern_data = data;
|
||||
}
|
||||
data_offset = 0;
|
||||
note_index = 0;
|
||||
}
|
||||
|
||||
public void get_note( int[] note, int index ) {
|
||||
if( index < note_index ) {
|
||||
note_index = 0;
|
||||
data_offset = 0;
|
||||
}
|
||||
while( note_index <= index ) {
|
||||
data_offset = next_note( data_offset, note );
|
||||
note_index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
public int next_note( int data_offset, int[] note ) {
|
||||
int bitmask, field;
|
||||
if( data_offset < 0 ) {
|
||||
data_offset = pattern_data.length;
|
||||
}
|
||||
bitmask = 0x80;
|
||||
if( data_offset < pattern_data.length ) {
|
||||
bitmask = pattern_data[ data_offset ] & 0xFF;
|
||||
}
|
||||
if( ( bitmask & 0x80 ) == 0x80 ) {
|
||||
data_offset += 1;
|
||||
} else {
|
||||
bitmask = 0x1F;
|
||||
}
|
||||
for( field = 0; field < 5; field++ ) {
|
||||
note[ field ] = 0;
|
||||
if( ( bitmask & 0x01 ) == 0x01 ) {
|
||||
if( data_offset < pattern_data.length ) {
|
||||
note[ field ] = pattern_data[ data_offset ] & 0xFF;
|
||||
data_offset += 1;
|
||||
}
|
||||
}
|
||||
bitmask = bitmask >> 1;
|
||||
}
|
||||
return data_offset;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
package ibxm;
|
||||
|
||||
public class Pattern {
|
||||
public int num_rows;
|
||||
|
||||
private int data_offset, note_index;
|
||||
private byte[] pattern_data;
|
||||
|
||||
public Pattern() {
|
||||
num_rows = 1;
|
||||
set_pattern_data( new byte[ 0 ] );
|
||||
}
|
||||
|
||||
public void set_pattern_data( byte[] data ) {
|
||||
if( data != null ) {
|
||||
pattern_data = data;
|
||||
}
|
||||
data_offset = 0;
|
||||
note_index = 0;
|
||||
}
|
||||
|
||||
public void get_note( int[] note, int index ) {
|
||||
if( index < note_index ) {
|
||||
note_index = 0;
|
||||
data_offset = 0;
|
||||
}
|
||||
while( note_index <= index ) {
|
||||
data_offset = next_note( data_offset, note );
|
||||
note_index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
public int next_note( int data_offset, int[] note ) {
|
||||
int bitmask, field;
|
||||
if( data_offset < 0 ) {
|
||||
data_offset = pattern_data.length;
|
||||
}
|
||||
bitmask = 0x80;
|
||||
if( data_offset < pattern_data.length ) {
|
||||
bitmask = pattern_data[ data_offset ] & 0xFF;
|
||||
}
|
||||
if( ( bitmask & 0x80 ) == 0x80 ) {
|
||||
data_offset += 1;
|
||||
} else {
|
||||
bitmask = 0x1F;
|
||||
}
|
||||
for( field = 0; field < 5; field++ ) {
|
||||
note[ field ] = 0;
|
||||
if( ( bitmask & 0x01 ) == 0x01 ) {
|
||||
if( data_offset < pattern_data.length ) {
|
||||
note[ field ] = pattern_data[ data_offset ] & 0xFF;
|
||||
data_offset += 1;
|
||||
}
|
||||
}
|
||||
bitmask = bitmask >> 1;
|
||||
}
|
||||
return data_offset;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,132 +1,132 @@
|
|||
|
||||
package ibxm;
|
||||
|
||||
import java.io.*;
|
||||
import javax.sound.sampled.*;
|
||||
|
||||
public class Player {
|
||||
private Thread play_thread;
|
||||
private IBXM ibxm;
|
||||
private Module module;
|
||||
private int song_duration, play_position;
|
||||
private boolean running, loop;
|
||||
private byte[] output_buffer;
|
||||
private SourceDataLine output_line;
|
||||
|
||||
/**
|
||||
Simple command-line test player.
|
||||
*/
|
||||
public static void main( String[] args ) throws Exception {
|
||||
if( args.length < 1 ) {
|
||||
System.err.println( "Usage: java ibxm.Player <module file>" );
|
||||
System.exit( 0 );
|
||||
}
|
||||
FileInputStream file_input_stream = new FileInputStream( args[ 0 ] );
|
||||
Player player = new Player();
|
||||
player.set_module( Player.load_module( file_input_stream ) );
|
||||
file_input_stream.close();
|
||||
player.play();
|
||||
}
|
||||
|
||||
/**
|
||||
Decode the data in the specified InputStream into a Module instance.
|
||||
@param input an InputStream containing the module file to be decoded.
|
||||
@throws IllegalArgumentException if the data is not recognised as a module file.
|
||||
*/
|
||||
public static Module load_module( InputStream input ) throws IllegalArgumentException, IOException {
|
||||
DataInputStream data_input_stream = new DataInputStream( input );
|
||||
/* Check if data is in XM format.*/
|
||||
byte[] xm_header = new byte[ 60 ];
|
||||
data_input_stream.readFully( xm_header );
|
||||
if( FastTracker2.is_xm( xm_header ) )
|
||||
return FastTracker2.load_xm( xm_header, data_input_stream );
|
||||
/* Check if data is in ScreamTracker 3 format.*/
|
||||
byte[] s3m_header = new byte[ 96 ];
|
||||
System.arraycopy( xm_header, 0, s3m_header, 0, 60 );
|
||||
data_input_stream.readFully( s3m_header, 60, 36 );
|
||||
if( ScreamTracker3.is_s3m( s3m_header ) )
|
||||
return ScreamTracker3.load_s3m( s3m_header, data_input_stream );
|
||||
/* Check if data is in ProTracker format.*/
|
||||
byte[] mod_header = new byte[ 1084 ];
|
||||
System.arraycopy( s3m_header, 0, mod_header, 0, 96 );
|
||||
data_input_stream.readFully( mod_header, 96, 988 );
|
||||
return ProTracker.load_mod( mod_header, data_input_stream );
|
||||
}
|
||||
|
||||
/**
|
||||
Instantiate a new Player.
|
||||
*/
|
||||
public Player() throws LineUnavailableException {
|
||||
ibxm = new IBXM( 48000 );
|
||||
set_loop( true );
|
||||
output_line = AudioSystem.getSourceDataLine( new AudioFormat( 48000, 16, 2, true, true ) );
|
||||
output_buffer = new byte[ 1024 * 4 ];
|
||||
}
|
||||
|
||||
/**
|
||||
Set the Module instance to be played.
|
||||
*/
|
||||
public void set_module( Module m ) {
|
||||
if( m != null ) module = m;
|
||||
stop();
|
||||
ibxm.set_module( module );
|
||||
song_duration = ibxm.calculate_song_duration();
|
||||
}
|
||||
|
||||
/**
|
||||
If loop is true, playback will continue indefinitely,
|
||||
otherwise the module will play through once and stop.
|
||||
*/
|
||||
public void set_loop( boolean loop ) {
|
||||
this.loop = loop;
|
||||
}
|
||||
|
||||
/**
|
||||
Open the audio device and begin playback.
|
||||
If a module is already playing it will be restarted.
|
||||
*/
|
||||
public void play() {
|
||||
stop();
|
||||
play_thread = new Thread( new Driver() );
|
||||
play_thread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
Stop playback and close the audio device.
|
||||
*/
|
||||
public void stop() {
|
||||
running = false;
|
||||
if( play_thread != null ) {
|
||||
try {
|
||||
play_thread.join();
|
||||
} catch( InterruptedException ie ) {}
|
||||
}
|
||||
}
|
||||
|
||||
private class Driver implements Runnable {
|
||||
public void run() {
|
||||
if( running ) return;
|
||||
try {
|
||||
output_line.open();
|
||||
output_line.start();
|
||||
play_position = 0;
|
||||
running = true;
|
||||
while( running ) {
|
||||
int frames = song_duration - play_position;
|
||||
if( frames > 1024 ) frames = 1024;
|
||||
ibxm.get_audio( output_buffer, frames );
|
||||
output_line.write( output_buffer, 0, frames * 4 );
|
||||
play_position += frames;
|
||||
if( play_position >= song_duration ) {
|
||||
play_position = 0;
|
||||
if( !loop ) running = false;
|
||||
}
|
||||
}
|
||||
output_line.drain();
|
||||
output_line.close();
|
||||
} catch( LineUnavailableException lue ) {
|
||||
lue.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
package ibxm;
|
||||
|
||||
import java.io.*;
|
||||
import javax.sound.sampled.*;
|
||||
|
||||
public class Player {
|
||||
private Thread play_thread;
|
||||
private IBXM ibxm;
|
||||
private Module module;
|
||||
private int song_duration, play_position;
|
||||
private boolean running, loop;
|
||||
private byte[] output_buffer;
|
||||
private SourceDataLine output_line;
|
||||
|
||||
/**
|
||||
Simple command-line test player.
|
||||
*/
|
||||
public static void main( String[] args ) throws Exception {
|
||||
if( args.length < 1 ) {
|
||||
System.err.println( "Usage: java ibxm.Player <module file>" );
|
||||
System.exit( 0 );
|
||||
}
|
||||
FileInputStream file_input_stream = new FileInputStream( args[ 0 ] );
|
||||
Player player = new Player();
|
||||
player.set_module( Player.load_module( file_input_stream ) );
|
||||
file_input_stream.close();
|
||||
player.play();
|
||||
}
|
||||
|
||||
/**
|
||||
Decode the data in the specified InputStream into a Module instance.
|
||||
@param input an InputStream containing the module file to be decoded.
|
||||
@throws IllegalArgumentException if the data is not recognised as a module file.
|
||||
*/
|
||||
public static Module load_module( InputStream input ) throws IllegalArgumentException, IOException {
|
||||
DataInputStream data_input_stream = new DataInputStream( input );
|
||||
/* Check if data is in XM format.*/
|
||||
byte[] xm_header = new byte[ 60 ];
|
||||
data_input_stream.readFully( xm_header );
|
||||
if( FastTracker2.is_xm( xm_header ) )
|
||||
return FastTracker2.load_xm( xm_header, data_input_stream );
|
||||
/* Check if data is in ScreamTracker 3 format.*/
|
||||
byte[] s3m_header = new byte[ 96 ];
|
||||
System.arraycopy( xm_header, 0, s3m_header, 0, 60 );
|
||||
data_input_stream.readFully( s3m_header, 60, 36 );
|
||||
if( ScreamTracker3.is_s3m( s3m_header ) )
|
||||
return ScreamTracker3.load_s3m( s3m_header, data_input_stream );
|
||||
/* Check if data is in ProTracker format.*/
|
||||
byte[] mod_header = new byte[ 1084 ];
|
||||
System.arraycopy( s3m_header, 0, mod_header, 0, 96 );
|
||||
data_input_stream.readFully( mod_header, 96, 988 );
|
||||
return ProTracker.load_mod( mod_header, data_input_stream );
|
||||
}
|
||||
|
||||
/**
|
||||
Instantiate a new Player.
|
||||
*/
|
||||
public Player() throws LineUnavailableException {
|
||||
ibxm = new IBXM( 48000 );
|
||||
set_loop( true );
|
||||
output_line = AudioSystem.getSourceDataLine( new AudioFormat( 48000, 16, 2, true, true ) );
|
||||
output_buffer = new byte[ 1024 * 4 ];
|
||||
}
|
||||
|
||||
/**
|
||||
Set the Module instance to be played.
|
||||
*/
|
||||
public void set_module( Module m ) {
|
||||
if( m != null ) module = m;
|
||||
stop();
|
||||
ibxm.set_module( module );
|
||||
song_duration = ibxm.calculate_song_duration();
|
||||
}
|
||||
|
||||
/**
|
||||
If loop is true, playback will continue indefinitely,
|
||||
otherwise the module will play through once and stop.
|
||||
*/
|
||||
public void set_loop( boolean loop ) {
|
||||
this.loop = loop;
|
||||
}
|
||||
|
||||
/**
|
||||
Open the audio device and begin playback.
|
||||
If a module is already playing it will be restarted.
|
||||
*/
|
||||
public void play() {
|
||||
stop();
|
||||
play_thread = new Thread( new Driver() );
|
||||
play_thread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
Stop playback and close the audio device.
|
||||
*/
|
||||
public void stop() {
|
||||
running = false;
|
||||
if( play_thread != null ) {
|
||||
try {
|
||||
play_thread.join();
|
||||
} catch( InterruptedException ie ) {}
|
||||
}
|
||||
}
|
||||
|
||||
private class Driver implements Runnable {
|
||||
public void run() {
|
||||
if( running ) return;
|
||||
try {
|
||||
output_line.open();
|
||||
output_line.start();
|
||||
play_position = 0;
|
||||
running = true;
|
||||
while( running ) {
|
||||
int frames = song_duration - play_position;
|
||||
if( frames > 1024 ) frames = 1024;
|
||||
ibxm.get_audio( output_buffer, frames );
|
||||
output_line.write( output_buffer, 0, frames * 4 );
|
||||
play_position += frames;
|
||||
if( play_position >= song_duration ) {
|
||||
play_position = 0;
|
||||
if( !loop ) running = false;
|
||||
}
|
||||
}
|
||||
output_line.drain();
|
||||
output_line.close();
|
||||
} catch( LineUnavailableException lue ) {
|
||||
lue.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,234 +1,234 @@
|
|||
package ibxm;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public class ProTracker {
|
||||
public static boolean is_mod( byte[] header_1084_bytes ) {
|
||||
boolean is_mod;
|
||||
is_mod = false;
|
||||
if( calculate_num_channels( header_1084_bytes ) > 0 ) {
|
||||
is_mod = true;
|
||||
}
|
||||
return is_mod;
|
||||
}
|
||||
|
||||
public static Module load_mod( byte[] header_1084_bytes, DataInput data_input ) throws IOException {
|
||||
int num_channels, channel_idx, panning;
|
||||
int sequence_length, restart_idx, sequence_idx;
|
||||
int num_patterns, pattern_idx, instrument_idx;
|
||||
Module module;
|
||||
num_channels = calculate_num_channels( header_1084_bytes );
|
||||
if( num_channels < 1 ) {
|
||||
throw new IllegalArgumentException( "ProTracker: Unrecognised module format!" );
|
||||
}
|
||||
module = new Module();
|
||||
module.song_title = ascii_text( header_1084_bytes, 0, 20 );
|
||||
module.pal = ( num_channels == 4 );
|
||||
module.global_volume = 64;
|
||||
module.channel_gain = IBXM.FP_ONE * 3 / 8;
|
||||
module.default_speed = 6;
|
||||
module.default_tempo = 125;
|
||||
module.set_num_channels( num_channels );
|
||||
for( channel_idx = 0; channel_idx < num_channels; channel_idx++ ) {
|
||||
panning = 64;
|
||||
if( ( channel_idx & 0x03 ) == 0x01 || ( channel_idx & 0x03 ) == 0x02 ) {
|
||||
panning = 192;
|
||||
}
|
||||
module.set_initial_panning( channel_idx, panning );
|
||||
}
|
||||
sequence_length = header_1084_bytes[ 950 ] & 0x7F;
|
||||
restart_idx = header_1084_bytes[ 951 ] & 0x7F;
|
||||
if( restart_idx >= sequence_length ) {
|
||||
restart_idx = 0;
|
||||
}
|
||||
module.restart_sequence_index = restart_idx;
|
||||
module.set_sequence_length( sequence_length );
|
||||
for( sequence_idx = 0; sequence_idx < sequence_length; sequence_idx++ ) {
|
||||
module.set_sequence( sequence_idx, header_1084_bytes[ 952 + sequence_idx ] & 0x7F );
|
||||
}
|
||||
num_patterns = calculate_num_patterns( header_1084_bytes );
|
||||
module.set_num_patterns( num_patterns );
|
||||
for( pattern_idx = 0; pattern_idx < num_patterns; pattern_idx++ ) {
|
||||
module.set_pattern( pattern_idx, read_mod_pattern( data_input, num_channels ) );
|
||||
}
|
||||
module.set_num_instruments( 31 );
|
||||
for( instrument_idx = 1; instrument_idx <= 31; instrument_idx++ ) {
|
||||
module.set_instrument( instrument_idx, read_mod_instrument( header_1084_bytes, instrument_idx, data_input ) );
|
||||
}
|
||||
return module;
|
||||
}
|
||||
|
||||
private static int calculate_num_patterns( byte[] module_header ) {
|
||||
int num_patterns, order_entry, pattern_idx;
|
||||
num_patterns = 0;
|
||||
for( pattern_idx = 0; pattern_idx < 128; pattern_idx++ ) {
|
||||
order_entry = module_header[ 952 + pattern_idx ] & 0x7F;
|
||||
if( order_entry >= num_patterns ) {
|
||||
num_patterns = order_entry + 1;
|
||||
}
|
||||
}
|
||||
return num_patterns;
|
||||
}
|
||||
|
||||
private static int calculate_num_channels( byte[] module_header ) {
|
||||
int num_channels;
|
||||
switch( ( module_header[ 1082 ] << 8 ) | module_header[ 1083 ] ) {
|
||||
case 0x4b2e: /* M.K. */
|
||||
case 0x4b21: /* M!K! */
|
||||
case 0x542e: /* N.T. */
|
||||
case 0x5434: /* FLT4 */
|
||||
num_channels = 4;
|
||||
break;
|
||||
case 0x484e: /* xCHN */
|
||||
num_channels = module_header[ 1080 ] - 48;
|
||||
break;
|
||||
case 0x4348: /* xxCH */
|
||||
num_channels = ( ( module_header[ 1080 ] - 48 ) * 10 ) + ( module_header[ 1081 ] - 48 );
|
||||
break;
|
||||
default:
|
||||
/* Not recognised. */
|
||||
num_channels = 0;
|
||||
break;
|
||||
}
|
||||
return num_channels;
|
||||
}
|
||||
|
||||
private static Pattern read_mod_pattern( DataInput data_input, int num_channels ) throws IOException {
|
||||
int input_idx, output_idx;
|
||||
int period, instrument, effect, effect_param;
|
||||
Pattern pattern;
|
||||
byte[] input_pattern_data, output_pattern_data;
|
||||
pattern = new Pattern();
|
||||
pattern.num_rows = 64;
|
||||
input_pattern_data = new byte[ 64 * num_channels * 4 ];
|
||||
output_pattern_data = new byte[ 64 * num_channels * 5 ];
|
||||
data_input.readFully( input_pattern_data );
|
||||
input_idx = 0;
|
||||
output_idx = 0;
|
||||
while( input_idx < input_pattern_data.length ) {
|
||||
period = ( input_pattern_data[ input_idx ] & 0x0F ) << 8;
|
||||
period = period | ( input_pattern_data[ input_idx + 1 ] & 0xFF );
|
||||
output_pattern_data[ output_idx ] = to_key( period );
|
||||
instrument = input_pattern_data[ input_idx ] & 0x10;
|
||||
instrument = instrument | ( ( input_pattern_data[ input_idx + 2 ] & 0xF0 ) >> 4 );
|
||||
output_pattern_data[ output_idx + 1 ] = ( byte ) instrument;
|
||||
effect = input_pattern_data[ input_idx + 2 ] & 0x0F;
|
||||
effect_param = input_pattern_data[ input_idx + 3 ] & 0xFF;
|
||||
if( effect == 0x01 && effect_param == 0 ) {
|
||||
/* Portamento up of zero has no effect. */
|
||||
effect = 0;
|
||||
}
|
||||
if( effect == 0x02 && effect_param == 0 ) {
|
||||
/* Portamento down of zero has no effect. */
|
||||
effect = 0;
|
||||
}
|
||||
if( effect == 0x08 && num_channels == 4 ) {
|
||||
/* Some Amiga mods use effect 0x08 for reasons other than panning.*/
|
||||
effect = 0;
|
||||
effect_param = 0;
|
||||
}
|
||||
if( effect == 0x0A && effect_param == 0 ) {
|
||||
/* Volume slide of zero has no effect.*/
|
||||
effect = 0;
|
||||
}
|
||||
if( effect == 0x05 && effect_param == 0 ) {
|
||||
/* Porta + Volume slide of zero has no effect.*/
|
||||
effect = 0x03;
|
||||
}
|
||||
if( effect == 0x06 && effect_param == 0 ) {
|
||||
/* Vibrato + Volume slide of zero has no effect.*/
|
||||
effect = 0x04;
|
||||
}
|
||||
output_pattern_data[ output_idx + 3 ] = ( byte ) effect;
|
||||
output_pattern_data[ output_idx + 4 ] = ( byte ) effect_param;
|
||||
input_idx += 4;
|
||||
output_idx += 5;
|
||||
}
|
||||
pattern.set_pattern_data( output_pattern_data );
|
||||
return pattern;
|
||||
}
|
||||
|
||||
private static Instrument read_mod_instrument( byte[] mod_header, int idx, DataInput data_input ) throws IOException {
|
||||
int header_offset, sample_data_length;
|
||||
int loop_start, loop_length, sample_idx, fine_tune;
|
||||
Instrument instrument;
|
||||
Sample sample;
|
||||
byte[] raw_sample_data;
|
||||
short[] sample_data;
|
||||
header_offset = ( idx - 1 ) * 30 + 20;
|
||||
instrument = new Instrument();
|
||||
instrument.name = ascii_text( mod_header, header_offset, 22 );
|
||||
sample = new Sample();
|
||||
sample_data_length = unsigned_short_be( mod_header, header_offset + 22 ) << 1;
|
||||
fine_tune = mod_header[ header_offset + 24 ] & 0x0F;
|
||||
if( fine_tune > 7 ) {
|
||||
fine_tune -= 16;
|
||||
}
|
||||
sample.transpose = ( fine_tune << IBXM.FP_SHIFT ) / 96;
|
||||
sample.volume = mod_header[ header_offset + 25 ] & 0x7F;
|
||||
loop_start = unsigned_short_be( mod_header, header_offset + 26 ) << 1;
|
||||
loop_length = unsigned_short_be( mod_header, header_offset + 28 ) << 1;
|
||||
if( loop_length < 4 ) {
|
||||
loop_length = 0;
|
||||
}
|
||||
raw_sample_data = new byte[ sample_data_length ];
|
||||
sample_data = new short[ sample_data_length ];
|
||||
try {
|
||||
data_input.readFully( raw_sample_data );
|
||||
} catch( EOFException e ) {
|
||||
System.out.println( "ProTracker: Instrument " + idx + " has samples missing." );
|
||||
}
|
||||
for( sample_idx = 0; sample_idx < raw_sample_data.length; sample_idx++ ) {
|
||||
sample_data[ sample_idx ] = ( short ) ( raw_sample_data[ sample_idx ] << 8 );
|
||||
}
|
||||
sample.set_sample_data( sample_data, loop_start, loop_length, false );
|
||||
instrument.set_num_samples( 1 );
|
||||
instrument.set_sample( 0, sample );
|
||||
return instrument;
|
||||
}
|
||||
|
||||
private static byte to_key( int period ) {
|
||||
int oct, key;
|
||||
if( period < 32 ) {
|
||||
key = 0;
|
||||
} else {
|
||||
oct = LogTable.log_2( 7256 ) - LogTable.log_2( period );
|
||||
if( oct < 0 ) {
|
||||
key = 0;
|
||||
} else {
|
||||
key = oct * 12;
|
||||
key = key >> ( IBXM.FP_SHIFT - 1 );
|
||||
key = ( key >> 1 ) + ( key & 1 );
|
||||
}
|
||||
}
|
||||
return ( byte ) key;
|
||||
}
|
||||
|
||||
private static int unsigned_short_be( byte[] buf, int offset ) {
|
||||
int value;
|
||||
value = ( buf[ offset ] & 0xFF ) << 8;
|
||||
value = value | ( buf[ offset + 1 ] & 0xFF );
|
||||
return value;
|
||||
}
|
||||
|
||||
private static String ascii_text( byte[] buffer, int offset, int length ) {
|
||||
int idx, chr;
|
||||
byte[] string_buffer;
|
||||
String string;
|
||||
string_buffer = new byte[ length ];
|
||||
for( idx = 0; idx < length; idx++ ) {
|
||||
chr = buffer[ offset + idx ];
|
||||
if( chr < 32 ) {
|
||||
chr = 32;
|
||||
}
|
||||
string_buffer[ idx ] = ( byte ) chr;
|
||||
}
|
||||
try {
|
||||
string = new String( string_buffer, 0, length, "ISO-8859-1" );
|
||||
} catch( UnsupportedEncodingException e ) {
|
||||
string = "";
|
||||
}
|
||||
return string;
|
||||
}
|
||||
}
|
||||
|
||||
package ibxm;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public class ProTracker {
|
||||
public static boolean is_mod( byte[] header_1084_bytes ) {
|
||||
boolean is_mod;
|
||||
is_mod = false;
|
||||
if( calculate_num_channels( header_1084_bytes ) > 0 ) {
|
||||
is_mod = true;
|
||||
}
|
||||
return is_mod;
|
||||
}
|
||||
|
||||
public static Module load_mod( byte[] header_1084_bytes, DataInput data_input ) throws IOException {
|
||||
int num_channels, channel_idx, panning;
|
||||
int sequence_length, restart_idx, sequence_idx;
|
||||
int num_patterns, pattern_idx, instrument_idx;
|
||||
Module module;
|
||||
num_channels = calculate_num_channels( header_1084_bytes );
|
||||
if( num_channels < 1 ) {
|
||||
throw new IllegalArgumentException( "ProTracker: Unrecognised module format!" );
|
||||
}
|
||||
module = new Module();
|
||||
module.song_title = ascii_text( header_1084_bytes, 0, 20 );
|
||||
module.pal = ( num_channels == 4 );
|
||||
module.global_volume = 64;
|
||||
module.channel_gain = IBXM.FP_ONE * 3 / 8;
|
||||
module.default_speed = 6;
|
||||
module.default_tempo = 125;
|
||||
module.set_num_channels( num_channels );
|
||||
for( channel_idx = 0; channel_idx < num_channels; channel_idx++ ) {
|
||||
panning = 64;
|
||||
if( ( channel_idx & 0x03 ) == 0x01 || ( channel_idx & 0x03 ) == 0x02 ) {
|
||||
panning = 192;
|
||||
}
|
||||
module.set_initial_panning( channel_idx, panning );
|
||||
}
|
||||
sequence_length = header_1084_bytes[ 950 ] & 0x7F;
|
||||
restart_idx = header_1084_bytes[ 951 ] & 0x7F;
|
||||
if( restart_idx >= sequence_length ) {
|
||||
restart_idx = 0;
|
||||
}
|
||||
module.restart_sequence_index = restart_idx;
|
||||
module.set_sequence_length( sequence_length );
|
||||
for( sequence_idx = 0; sequence_idx < sequence_length; sequence_idx++ ) {
|
||||
module.set_sequence( sequence_idx, header_1084_bytes[ 952 + sequence_idx ] & 0x7F );
|
||||
}
|
||||
num_patterns = calculate_num_patterns( header_1084_bytes );
|
||||
module.set_num_patterns( num_patterns );
|
||||
for( pattern_idx = 0; pattern_idx < num_patterns; pattern_idx++ ) {
|
||||
module.set_pattern( pattern_idx, read_mod_pattern( data_input, num_channels ) );
|
||||
}
|
||||
module.set_num_instruments( 31 );
|
||||
for( instrument_idx = 1; instrument_idx <= 31; instrument_idx++ ) {
|
||||
module.set_instrument( instrument_idx, read_mod_instrument( header_1084_bytes, instrument_idx, data_input ) );
|
||||
}
|
||||
return module;
|
||||
}
|
||||
|
||||
private static int calculate_num_patterns( byte[] module_header ) {
|
||||
int num_patterns, order_entry, pattern_idx;
|
||||
num_patterns = 0;
|
||||
for( pattern_idx = 0; pattern_idx < 128; pattern_idx++ ) {
|
||||
order_entry = module_header[ 952 + pattern_idx ] & 0x7F;
|
||||
if( order_entry >= num_patterns ) {
|
||||
num_patterns = order_entry + 1;
|
||||
}
|
||||
}
|
||||
return num_patterns;
|
||||
}
|
||||
|
||||
private static int calculate_num_channels( byte[] module_header ) {
|
||||
int num_channels;
|
||||
switch( ( module_header[ 1082 ] << 8 ) | module_header[ 1083 ] ) {
|
||||
case 0x4b2e: /* M.K. */
|
||||
case 0x4b21: /* M!K! */
|
||||
case 0x542e: /* N.T. */
|
||||
case 0x5434: /* FLT4 */
|
||||
num_channels = 4;
|
||||
break;
|
||||
case 0x484e: /* xCHN */
|
||||
num_channels = module_header[ 1080 ] - 48;
|
||||
break;
|
||||
case 0x4348: /* xxCH */
|
||||
num_channels = ( ( module_header[ 1080 ] - 48 ) * 10 ) + ( module_header[ 1081 ] - 48 );
|
||||
break;
|
||||
default:
|
||||
/* Not recognised. */
|
||||
num_channels = 0;
|
||||
break;
|
||||
}
|
||||
return num_channels;
|
||||
}
|
||||
|
||||
private static Pattern read_mod_pattern( DataInput data_input, int num_channels ) throws IOException {
|
||||
int input_idx, output_idx;
|
||||
int period, instrument, effect, effect_param;
|
||||
Pattern pattern;
|
||||
byte[] input_pattern_data, output_pattern_data;
|
||||
pattern = new Pattern();
|
||||
pattern.num_rows = 64;
|
||||
input_pattern_data = new byte[ 64 * num_channels * 4 ];
|
||||
output_pattern_data = new byte[ 64 * num_channels * 5 ];
|
||||
data_input.readFully( input_pattern_data );
|
||||
input_idx = 0;
|
||||
output_idx = 0;
|
||||
while( input_idx < input_pattern_data.length ) {
|
||||
period = ( input_pattern_data[ input_idx ] & 0x0F ) << 8;
|
||||
period = period | ( input_pattern_data[ input_idx + 1 ] & 0xFF );
|
||||
output_pattern_data[ output_idx ] = to_key( period );
|
||||
instrument = input_pattern_data[ input_idx ] & 0x10;
|
||||
instrument = instrument | ( ( input_pattern_data[ input_idx + 2 ] & 0xF0 ) >> 4 );
|
||||
output_pattern_data[ output_idx + 1 ] = ( byte ) instrument;
|
||||
effect = input_pattern_data[ input_idx + 2 ] & 0x0F;
|
||||
effect_param = input_pattern_data[ input_idx + 3 ] & 0xFF;
|
||||
if( effect == 0x01 && effect_param == 0 ) {
|
||||
/* Portamento up of zero has no effect. */
|
||||
effect = 0;
|
||||
}
|
||||
if( effect == 0x02 && effect_param == 0 ) {
|
||||
/* Portamento down of zero has no effect. */
|
||||
effect = 0;
|
||||
}
|
||||
if( effect == 0x08 && num_channels == 4 ) {
|
||||
/* Some Amiga mods use effect 0x08 for reasons other than panning.*/
|
||||
effect = 0;
|
||||
effect_param = 0;
|
||||
}
|
||||
if( effect == 0x0A && effect_param == 0 ) {
|
||||
/* Volume slide of zero has no effect.*/
|
||||
effect = 0;
|
||||
}
|
||||
if( effect == 0x05 && effect_param == 0 ) {
|
||||
/* Porta + Volume slide of zero has no effect.*/
|
||||
effect = 0x03;
|
||||
}
|
||||
if( effect == 0x06 && effect_param == 0 ) {
|
||||
/* Vibrato + Volume slide of zero has no effect.*/
|
||||
effect = 0x04;
|
||||
}
|
||||
output_pattern_data[ output_idx + 3 ] = ( byte ) effect;
|
||||
output_pattern_data[ output_idx + 4 ] = ( byte ) effect_param;
|
||||
input_idx += 4;
|
||||
output_idx += 5;
|
||||
}
|
||||
pattern.set_pattern_data( output_pattern_data );
|
||||
return pattern;
|
||||
}
|
||||
|
||||
private static Instrument read_mod_instrument( byte[] mod_header, int idx, DataInput data_input ) throws IOException {
|
||||
int header_offset, sample_data_length;
|
||||
int loop_start, loop_length, sample_idx, fine_tune;
|
||||
Instrument instrument;
|
||||
Sample sample;
|
||||
byte[] raw_sample_data;
|
||||
short[] sample_data;
|
||||
header_offset = ( idx - 1 ) * 30 + 20;
|
||||
instrument = new Instrument();
|
||||
instrument.name = ascii_text( mod_header, header_offset, 22 );
|
||||
sample = new Sample();
|
||||
sample_data_length = unsigned_short_be( mod_header, header_offset + 22 ) << 1;
|
||||
fine_tune = mod_header[ header_offset + 24 ] & 0x0F;
|
||||
if( fine_tune > 7 ) {
|
||||
fine_tune -= 16;
|
||||
}
|
||||
sample.transpose = ( fine_tune << IBXM.FP_SHIFT ) / 96;
|
||||
sample.volume = mod_header[ header_offset + 25 ] & 0x7F;
|
||||
loop_start = unsigned_short_be( mod_header, header_offset + 26 ) << 1;
|
||||
loop_length = unsigned_short_be( mod_header, header_offset + 28 ) << 1;
|
||||
if( loop_length < 4 ) {
|
||||
loop_length = 0;
|
||||
}
|
||||
raw_sample_data = new byte[ sample_data_length ];
|
||||
sample_data = new short[ sample_data_length ];
|
||||
try {
|
||||
data_input.readFully( raw_sample_data );
|
||||
} catch( EOFException e ) {
|
||||
System.out.println( "ProTracker: Instrument " + idx + " has samples missing." );
|
||||
}
|
||||
for( sample_idx = 0; sample_idx < raw_sample_data.length; sample_idx++ ) {
|
||||
sample_data[ sample_idx ] = ( short ) ( raw_sample_data[ sample_idx ] << 8 );
|
||||
}
|
||||
sample.set_sample_data( sample_data, loop_start, loop_length, false );
|
||||
instrument.set_num_samples( 1 );
|
||||
instrument.set_sample( 0, sample );
|
||||
return instrument;
|
||||
}
|
||||
|
||||
private static byte to_key( int period ) {
|
||||
int oct, key;
|
||||
if( period < 32 ) {
|
||||
key = 0;
|
||||
} else {
|
||||
oct = LogTable.log_2( 7256 ) - LogTable.log_2( period );
|
||||
if( oct < 0 ) {
|
||||
key = 0;
|
||||
} else {
|
||||
key = oct * 12;
|
||||
key = key >> ( IBXM.FP_SHIFT - 1 );
|
||||
key = ( key >> 1 ) + ( key & 1 );
|
||||
}
|
||||
}
|
||||
return ( byte ) key;
|
||||
}
|
||||
|
||||
private static int unsigned_short_be( byte[] buf, int offset ) {
|
||||
int value;
|
||||
value = ( buf[ offset ] & 0xFF ) << 8;
|
||||
value = value | ( buf[ offset + 1 ] & 0xFF );
|
||||
return value;
|
||||
}
|
||||
|
||||
private static String ascii_text( byte[] buffer, int offset, int length ) {
|
||||
int idx, chr;
|
||||
byte[] string_buffer;
|
||||
String string;
|
||||
string_buffer = new byte[ length ];
|
||||
for( idx = 0; idx < length; idx++ ) {
|
||||
chr = buffer[ offset + idx ];
|
||||
if( chr < 32 ) {
|
||||
chr = 32;
|
||||
}
|
||||
string_buffer[ idx ] = ( byte ) chr;
|
||||
}
|
||||
try {
|
||||
string = new String( string_buffer, 0, length, "ISO-8859-1" );
|
||||
} catch( UnsupportedEncodingException e ) {
|
||||
string = "";
|
||||
}
|
||||
return string;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,239 +1,239 @@
|
|||
|
||||
package ibxm;
|
||||
|
||||
public class Sample {
|
||||
public String name;
|
||||
public boolean set_panning;
|
||||
public int volume, panning;
|
||||
public int transpose;
|
||||
|
||||
private int loop_start, loop_length;
|
||||
private short[] sample_data;
|
||||
|
||||
/* For the sinc interpolator.*/
|
||||
private static final int POINT_SHIFT = 4;
|
||||
private static final int POINTS = 1 << POINT_SHIFT;
|
||||
private static final int OVERLAP = POINTS >> 1;
|
||||
private static final int INTERP_SHIFT = IBXM.FP_SHIFT - 4;
|
||||
private static final int INTERP_BITMASK = ( 1 << INTERP_SHIFT ) - 1;
|
||||
private static final short[] sinc_table = {
|
||||
0, -7, 27, -71, 142, -227, 299, 32439, 299, -227, 142, -71, 27, -7, 0, 0,
|
||||
0, 0, -5, 36, -142, 450, -1439, 32224, 2302, -974, 455, -190, 64, -15, 2, 0,
|
||||
0, 6, -33, 128, -391, 1042, -2894, 31584, 4540, -1765, 786, -318, 105, -25, 3, 0,
|
||||
0, 10, -55, 204, -597, 1533, -4056, 30535, 6977, -2573, 1121, -449, 148, -36, 5, 0,
|
||||
-1, 13, -71, 261, -757, 1916, -4922, 29105, 9568, -3366, 1448, -578, 191, -47, 7, 0,
|
||||
-1, 15, -81, 300, -870, 2185, -5498, 27328, 12263, -4109, 1749, -698, 232, -58, 9, 0,
|
||||
-1, 15, -86, 322, -936, 2343, -5800, 25249, 15006, -4765, 2011, -802, 269, -68, 10, 0,
|
||||
-1, 15, -87, 328, -957, 2394, -5849, 22920, 17738, -5298, 2215, -885, 299, -77, 12, 0,
|
||||
0, 14, -83, 319, -938, 2347, -5671, 20396, 20396, -5671, 2347, -938, 319, -83, 14, 0,
|
||||
0, 12, -77, 299, -885, 2215, -5298, 17738, 22920, -5849, 2394, -957, 328, -87, 15, -1,
|
||||
0, 10, -68, 269, -802, 2011, -4765, 15006, 25249, -5800, 2343, -936, 322, -86, 15, -1,
|
||||
0, 9, -58, 232, -698, 1749, -4109, 12263, 27328, -5498, 2185, -870, 300, -81, 15, -1,
|
||||
0, 7, -47, 191, -578, 1448, -3366, 9568, 29105, -4922, 1916, -757, 261, -71, 13, -1,
|
||||
0, 5, -36, 148, -449, 1121, -2573, 6977, 30535, -4056, 1533, -597, 204, -55, 10, 0,
|
||||
0, 3, -25, 105, -318, 786, -1765, 4540, 31584, -2894, 1042, -391, 128, -33, 6, 0,
|
||||
0, 2, -15, 64, -190, 455, -974, 2302, 32224, -1439, 450, -142, 36, -5, 0, 0,
|
||||
0, 0, -7, 27, -71, 142, -227, 299, 32439, 299, -227, 142, -71, 27, -7, 0
|
||||
};
|
||||
|
||||
public Sample() {
|
||||
name = "";
|
||||
set_sample_data( new short[ 0 ], 0, 0, false );
|
||||
}
|
||||
|
||||
public void set_sample_data( short[] data, int loop_start, int loop_length, boolean ping_pong ) {
|
||||
int offset;
|
||||
short sample;
|
||||
if( loop_start < 0 ) {
|
||||
loop_start = 0;
|
||||
}
|
||||
if( loop_start >= data.length ) {
|
||||
loop_start = data.length - 1;
|
||||
}
|
||||
if( loop_start + loop_length > data.length ) {
|
||||
loop_length = data.length - loop_start;
|
||||
}
|
||||
if( loop_length <= 1 ) {
|
||||
sample_data = new short[ OVERLAP + data.length + OVERLAP * 3 ];
|
||||
System.arraycopy( data, 0, sample_data, OVERLAP, data.length );
|
||||
offset = 0;
|
||||
while( offset < OVERLAP ) {
|
||||
sample = sample_data[ OVERLAP + data.length - 1 ];
|
||||
sample = ( short ) ( sample * ( OVERLAP - offset ) / OVERLAP );
|
||||
sample_data[ OVERLAP + data.length + offset ] = sample;
|
||||
offset += 1;
|
||||
}
|
||||
loop_start = OVERLAP + data.length + OVERLAP;
|
||||
loop_length = 1;
|
||||
} else {
|
||||
if( ping_pong ) {
|
||||
sample_data = new short[ OVERLAP + loop_start + loop_length * 2 + OVERLAP * 2 ];
|
||||
System.arraycopy( data, 0, sample_data, OVERLAP, loop_start + loop_length );
|
||||
offset = 0;
|
||||
while( offset < loop_length ) {
|
||||
sample = data[ loop_start + loop_length - offset - 1 ];
|
||||
sample_data[ OVERLAP + loop_start + loop_length + offset ] = sample;
|
||||
offset += 1;
|
||||
}
|
||||
loop_start = loop_start + OVERLAP;
|
||||
loop_length = loop_length * 2;
|
||||
} else {
|
||||
sample_data = new short[ OVERLAP + loop_start + loop_length + OVERLAP * 2 ];
|
||||
System.arraycopy( data, 0, sample_data, OVERLAP, loop_start + loop_length );
|
||||
loop_start = loop_start + OVERLAP;
|
||||
}
|
||||
offset = 0;
|
||||
while( offset < OVERLAP * 2 ) {
|
||||
sample = sample_data[ loop_start + offset ];
|
||||
sample_data[ loop_start + loop_length + offset ] = sample;
|
||||
offset += 1;
|
||||
}
|
||||
}
|
||||
this.loop_start = loop_start;
|
||||
this.loop_length = loop_length;
|
||||
}
|
||||
|
||||
public void resample_nearest(
|
||||
int sample_idx, int sample_frac, int step, int left_gain, int right_gain,
|
||||
int[] mix_buffer, int frame_offset, int frames ) {
|
||||
int loop_end, offset, end, max_sample_idx;
|
||||
sample_idx += OVERLAP;
|
||||
loop_end = loop_start + loop_length - 1;
|
||||
offset = frame_offset << 1;
|
||||
end = ( frame_offset + frames - 1 ) << 1;
|
||||
while( frames > 0 ) {
|
||||
if( sample_idx > loop_end ) {
|
||||
if( loop_length <= 1 ) {
|
||||
break;
|
||||
}
|
||||
sample_idx = loop_start + ( sample_idx - loop_start ) % loop_length;
|
||||
}
|
||||
max_sample_idx = sample_idx + ( ( sample_frac + ( frames - 1 ) * step ) >> IBXM.FP_SHIFT );
|
||||
if( max_sample_idx > loop_end ) {
|
||||
while( sample_idx <= loop_end ) {
|
||||
mix_buffer[ offset++ ] += sample_data[ sample_idx ] * left_gain >> IBXM.FP_SHIFT;
|
||||
mix_buffer[ offset++ ] += sample_data[ sample_idx ] * right_gain >> IBXM.FP_SHIFT;
|
||||
sample_frac += step;
|
||||
sample_idx += sample_frac >> IBXM.FP_SHIFT;
|
||||
sample_frac &= IBXM.FP_MASK;
|
||||
}
|
||||
} else {
|
||||
while( offset <= end ) {
|
||||
mix_buffer[ offset++ ] += sample_data[ sample_idx ] * left_gain >> IBXM.FP_SHIFT;
|
||||
mix_buffer[ offset++ ] += sample_data[ sample_idx ] * right_gain >> IBXM.FP_SHIFT;
|
||||
sample_frac += step;
|
||||
sample_idx += sample_frac >> IBXM.FP_SHIFT;
|
||||
sample_frac &= IBXM.FP_MASK;
|
||||
}
|
||||
}
|
||||
frames = ( end - offset + 2 ) >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
public void resample_linear(
|
||||
int sample_idx, int sample_frac, int step, int left_gain, int right_gain,
|
||||
int[] mix_buffer, int frame_offset, int frames ) {
|
||||
int loop_end, offset, end, max_sample_idx, amplitude;
|
||||
sample_idx += OVERLAP;
|
||||
loop_end = loop_start + loop_length - 1;
|
||||
offset = frame_offset << 1;
|
||||
end = ( frame_offset + frames - 1 ) << 1;
|
||||
while( frames > 0 ) {
|
||||
if( sample_idx > loop_end ) {
|
||||
if( loop_length <= 1 ) {
|
||||
break;
|
||||
}
|
||||
sample_idx = loop_start + ( sample_idx - loop_start ) % loop_length;
|
||||
}
|
||||
max_sample_idx = sample_idx + ( ( sample_frac + ( frames - 1 ) * step ) >> IBXM.FP_SHIFT );
|
||||
if( max_sample_idx > loop_end ) {
|
||||
while( sample_idx <= loop_end ) {
|
||||
amplitude = sample_data[ sample_idx ];
|
||||
amplitude += ( sample_data[ sample_idx + 1 ] - amplitude ) * sample_frac >> IBXM.FP_SHIFT;
|
||||
mix_buffer[ offset++ ] += amplitude * left_gain >> IBXM.FP_SHIFT;
|
||||
mix_buffer[ offset++ ] += amplitude * right_gain >> IBXM.FP_SHIFT;
|
||||
sample_frac += step;
|
||||
sample_idx += sample_frac >> IBXM.FP_SHIFT;
|
||||
sample_frac &= IBXM.FP_MASK;
|
||||
}
|
||||
} else {
|
||||
while( offset <= end ) {
|
||||
amplitude = sample_data[ sample_idx ];
|
||||
amplitude += ( sample_data[ sample_idx + 1 ] - amplitude ) * sample_frac >> IBXM.FP_SHIFT;
|
||||
mix_buffer[ offset++ ] += amplitude * left_gain >> IBXM.FP_SHIFT;
|
||||
mix_buffer[ offset++ ] += amplitude * right_gain >> IBXM.FP_SHIFT;
|
||||
sample_frac += step;
|
||||
sample_idx += sample_frac >> IBXM.FP_SHIFT;
|
||||
sample_frac &= IBXM.FP_MASK;
|
||||
}
|
||||
}
|
||||
frames = ( end - offset + 2 ) >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
public void resample_sinc(
|
||||
int sample_idx, int sample_frac, int step, int left_gain, int right_gain,
|
||||
int[] mix_buffer, int frame_offset, int frames ) {
|
||||
int offset, end, loop_end, table_idx, a1, a2, amplitude;
|
||||
loop_end = loop_start + loop_length - 1;
|
||||
offset = frame_offset << 1;
|
||||
end = ( frame_offset + frames - 1 ) << 1;
|
||||
while( offset <= end ) {
|
||||
if( sample_idx > loop_end ) {
|
||||
if( loop_length <= 1 ) {
|
||||
break;
|
||||
}
|
||||
sample_idx = loop_start + ( sample_idx - loop_start ) % loop_length;
|
||||
}
|
||||
table_idx = ( sample_frac >> INTERP_SHIFT ) << POINT_SHIFT;
|
||||
a1 = sinc_table[ table_idx + 0 ] * sample_data[ sample_idx + 0 ] >> 15;
|
||||
a1 += sinc_table[ table_idx + 1 ] * sample_data[ sample_idx + 1 ] >> 15;
|
||||
a1 += sinc_table[ table_idx + 2 ] * sample_data[ sample_idx + 2 ] >> 15;
|
||||
a1 += sinc_table[ table_idx + 3 ] * sample_data[ sample_idx + 3 ] >> 15;
|
||||
a1 += sinc_table[ table_idx + 4 ] * sample_data[ sample_idx + 4 ] >> 15;
|
||||
a1 += sinc_table[ table_idx + 5 ] * sample_data[ sample_idx + 5 ] >> 15;
|
||||
a1 += sinc_table[ table_idx + 6 ] * sample_data[ sample_idx + 6 ] >> 15;
|
||||
a1 += sinc_table[ table_idx + 7 ] * sample_data[ sample_idx + 7 ] >> 15;
|
||||
a1 += sinc_table[ table_idx + 8 ] * sample_data[ sample_idx + 8 ] >> 15;
|
||||
a1 += sinc_table[ table_idx + 9 ] * sample_data[ sample_idx + 9 ] >> 15;
|
||||
a1 += sinc_table[ table_idx + 10 ] * sample_data[ sample_idx + 10 ] >> 15;
|
||||
a1 += sinc_table[ table_idx + 11 ] * sample_data[ sample_idx + 11 ] >> 15;
|
||||
a1 += sinc_table[ table_idx + 12 ] * sample_data[ sample_idx + 12 ] >> 15;
|
||||
a1 += sinc_table[ table_idx + 13 ] * sample_data[ sample_idx + 13 ] >> 15;
|
||||
a1 += sinc_table[ table_idx + 14 ] * sample_data[ sample_idx + 14 ] >> 15;
|
||||
a1 += sinc_table[ table_idx + 15 ] * sample_data[ sample_idx + 15 ] >> 15;
|
||||
a2 = sinc_table[ table_idx + 16 ] * sample_data[ sample_idx + 0 ] >> 15;
|
||||
a2 += sinc_table[ table_idx + 17 ] * sample_data[ sample_idx + 1 ] >> 15;
|
||||
a2 += sinc_table[ table_idx + 18 ] * sample_data[ sample_idx + 2 ] >> 15;
|
||||
a2 += sinc_table[ table_idx + 19 ] * sample_data[ sample_idx + 3 ] >> 15;
|
||||
a2 += sinc_table[ table_idx + 20 ] * sample_data[ sample_idx + 4 ] >> 15;
|
||||
a2 += sinc_table[ table_idx + 21 ] * sample_data[ sample_idx + 5 ] >> 15;
|
||||
a2 += sinc_table[ table_idx + 22 ] * sample_data[ sample_idx + 6 ] >> 15;
|
||||
a2 += sinc_table[ table_idx + 23 ] * sample_data[ sample_idx + 7 ] >> 15;
|
||||
a2 += sinc_table[ table_idx + 24 ] * sample_data[ sample_idx + 8 ] >> 15;
|
||||
a2 += sinc_table[ table_idx + 25 ] * sample_data[ sample_idx + 9 ] >> 15;
|
||||
a2 += sinc_table[ table_idx + 26 ] * sample_data[ sample_idx + 10 ] >> 15;
|
||||
a2 += sinc_table[ table_idx + 27 ] * sample_data[ sample_idx + 11 ] >> 15;
|
||||
a2 += sinc_table[ table_idx + 28 ] * sample_data[ sample_idx + 12 ] >> 15;
|
||||
a2 += sinc_table[ table_idx + 29 ] * sample_data[ sample_idx + 13 ] >> 15;
|
||||
a2 += sinc_table[ table_idx + 30 ] * sample_data[ sample_idx + 14 ] >> 15;
|
||||
a2 += sinc_table[ table_idx + 31 ] * sample_data[ sample_idx + 15 ] >> 15;
|
||||
amplitude = a1 + ( ( a2 - a1 ) * ( sample_frac & INTERP_BITMASK ) >> INTERP_SHIFT );
|
||||
mix_buffer[ offset ] += amplitude * left_gain >> IBXM.FP_SHIFT;
|
||||
mix_buffer[ offset + 1 ] += amplitude * right_gain >> IBXM.FP_SHIFT;
|
||||
offset += 2;
|
||||
sample_frac += step;
|
||||
sample_idx += sample_frac >> IBXM.FP_SHIFT;
|
||||
sample_frac &= IBXM.FP_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean has_finished( int sample_idx ) {
|
||||
boolean finished;
|
||||
finished = false;
|
||||
if( loop_length <= 1 && sample_idx > loop_start ) {
|
||||
finished = true;
|
||||
}
|
||||
return finished;
|
||||
}
|
||||
}
|
||||
|
||||
package ibxm;
|
||||
|
||||
public class Sample {
|
||||
public String name;
|
||||
public boolean set_panning;
|
||||
public int volume, panning;
|
||||
public int transpose;
|
||||
|
||||
private int loop_start, loop_length;
|
||||
private short[] sample_data;
|
||||
|
||||
/* For the sinc interpolator.*/
|
||||
private static final int POINT_SHIFT = 4;
|
||||
private static final int POINTS = 1 << POINT_SHIFT;
|
||||
private static final int OVERLAP = POINTS >> 1;
|
||||
private static final int INTERP_SHIFT = IBXM.FP_SHIFT - 4;
|
||||
private static final int INTERP_BITMASK = ( 1 << INTERP_SHIFT ) - 1;
|
||||
private static final short[] sinc_table = {
|
||||
0, -7, 27, -71, 142, -227, 299, 32439, 299, -227, 142, -71, 27, -7, 0, 0,
|
||||
0, 0, -5, 36, -142, 450, -1439, 32224, 2302, -974, 455, -190, 64, -15, 2, 0,
|
||||
0, 6, -33, 128, -391, 1042, -2894, 31584, 4540, -1765, 786, -318, 105, -25, 3, 0,
|
||||
0, 10, -55, 204, -597, 1533, -4056, 30535, 6977, -2573, 1121, -449, 148, -36, 5, 0,
|
||||
-1, 13, -71, 261, -757, 1916, -4922, 29105, 9568, -3366, 1448, -578, 191, -47, 7, 0,
|
||||
-1, 15, -81, 300, -870, 2185, -5498, 27328, 12263, -4109, 1749, -698, 232, -58, 9, 0,
|
||||
-1, 15, -86, 322, -936, 2343, -5800, 25249, 15006, -4765, 2011, -802, 269, -68, 10, 0,
|
||||
-1, 15, -87, 328, -957, 2394, -5849, 22920, 17738, -5298, 2215, -885, 299, -77, 12, 0,
|
||||
0, 14, -83, 319, -938, 2347, -5671, 20396, 20396, -5671, 2347, -938, 319, -83, 14, 0,
|
||||
0, 12, -77, 299, -885, 2215, -5298, 17738, 22920, -5849, 2394, -957, 328, -87, 15, -1,
|
||||
0, 10, -68, 269, -802, 2011, -4765, 15006, 25249, -5800, 2343, -936, 322, -86, 15, -1,
|
||||
0, 9, -58, 232, -698, 1749, -4109, 12263, 27328, -5498, 2185, -870, 300, -81, 15, -1,
|
||||
0, 7, -47, 191, -578, 1448, -3366, 9568, 29105, -4922, 1916, -757, 261, -71, 13, -1,
|
||||
0, 5, -36, 148, -449, 1121, -2573, 6977, 30535, -4056, 1533, -597, 204, -55, 10, 0,
|
||||
0, 3, -25, 105, -318, 786, -1765, 4540, 31584, -2894, 1042, -391, 128, -33, 6, 0,
|
||||
0, 2, -15, 64, -190, 455, -974, 2302, 32224, -1439, 450, -142, 36, -5, 0, 0,
|
||||
0, 0, -7, 27, -71, 142, -227, 299, 32439, 299, -227, 142, -71, 27, -7, 0
|
||||
};
|
||||
|
||||
public Sample() {
|
||||
name = "";
|
||||
set_sample_data( new short[ 0 ], 0, 0, false );
|
||||
}
|
||||
|
||||
public void set_sample_data( short[] data, int loop_start, int loop_length, boolean ping_pong ) {
|
||||
int offset;
|
||||
short sample;
|
||||
if( loop_start < 0 ) {
|
||||
loop_start = 0;
|
||||
}
|
||||
if( loop_start >= data.length ) {
|
||||
loop_start = data.length - 1;
|
||||
}
|
||||
if( loop_start + loop_length > data.length ) {
|
||||
loop_length = data.length - loop_start;
|
||||
}
|
||||
if( loop_length <= 1 ) {
|
||||
sample_data = new short[ OVERLAP + data.length + OVERLAP * 3 ];
|
||||
System.arraycopy( data, 0, sample_data, OVERLAP, data.length );
|
||||
offset = 0;
|
||||
while( offset < OVERLAP ) {
|
||||
sample = sample_data[ OVERLAP + data.length - 1 ];
|
||||
sample = ( short ) ( sample * ( OVERLAP - offset ) / OVERLAP );
|
||||
sample_data[ OVERLAP + data.length + offset ] = sample;
|
||||
offset += 1;
|
||||
}
|
||||
loop_start = OVERLAP + data.length + OVERLAP;
|
||||
loop_length = 1;
|
||||
} else {
|
||||
if( ping_pong ) {
|
||||
sample_data = new short[ OVERLAP + loop_start + loop_length * 2 + OVERLAP * 2 ];
|
||||
System.arraycopy( data, 0, sample_data, OVERLAP, loop_start + loop_length );
|
||||
offset = 0;
|
||||
while( offset < loop_length ) {
|
||||
sample = data[ loop_start + loop_length - offset - 1 ];
|
||||
sample_data[ OVERLAP + loop_start + loop_length + offset ] = sample;
|
||||
offset += 1;
|
||||
}
|
||||
loop_start = loop_start + OVERLAP;
|
||||
loop_length = loop_length * 2;
|
||||
} else {
|
||||
sample_data = new short[ OVERLAP + loop_start + loop_length + OVERLAP * 2 ];
|
||||
System.arraycopy( data, 0, sample_data, OVERLAP, loop_start + loop_length );
|
||||
loop_start = loop_start + OVERLAP;
|
||||
}
|
||||
offset = 0;
|
||||
while( offset < OVERLAP * 2 ) {
|
||||
sample = sample_data[ loop_start + offset ];
|
||||
sample_data[ loop_start + loop_length + offset ] = sample;
|
||||
offset += 1;
|
||||
}
|
||||
}
|
||||
this.loop_start = loop_start;
|
||||
this.loop_length = loop_length;
|
||||
}
|
||||
|
||||
public void resample_nearest(
|
||||
int sample_idx, int sample_frac, int step, int left_gain, int right_gain,
|
||||
int[] mix_buffer, int frame_offset, int frames ) {
|
||||
int loop_end, offset, end, max_sample_idx;
|
||||
sample_idx += OVERLAP;
|
||||
loop_end = loop_start + loop_length - 1;
|
||||
offset = frame_offset << 1;
|
||||
end = ( frame_offset + frames - 1 ) << 1;
|
||||
while( frames > 0 ) {
|
||||
if( sample_idx > loop_end ) {
|
||||
if( loop_length <= 1 ) {
|
||||
break;
|
||||
}
|
||||
sample_idx = loop_start + ( sample_idx - loop_start ) % loop_length;
|
||||
}
|
||||
max_sample_idx = sample_idx + ( ( sample_frac + ( frames - 1 ) * step ) >> IBXM.FP_SHIFT );
|
||||
if( max_sample_idx > loop_end ) {
|
||||
while( sample_idx <= loop_end ) {
|
||||
mix_buffer[ offset++ ] += sample_data[ sample_idx ] * left_gain >> IBXM.FP_SHIFT;
|
||||
mix_buffer[ offset++ ] += sample_data[ sample_idx ] * right_gain >> IBXM.FP_SHIFT;
|
||||
sample_frac += step;
|
||||
sample_idx += sample_frac >> IBXM.FP_SHIFT;
|
||||
sample_frac &= IBXM.FP_MASK;
|
||||
}
|
||||
} else {
|
||||
while( offset <= end ) {
|
||||
mix_buffer[ offset++ ] += sample_data[ sample_idx ] * left_gain >> IBXM.FP_SHIFT;
|
||||
mix_buffer[ offset++ ] += sample_data[ sample_idx ] * right_gain >> IBXM.FP_SHIFT;
|
||||
sample_frac += step;
|
||||
sample_idx += sample_frac >> IBXM.FP_SHIFT;
|
||||
sample_frac &= IBXM.FP_MASK;
|
||||
}
|
||||
}
|
||||
frames = ( end - offset + 2 ) >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
public void resample_linear(
|
||||
int sample_idx, int sample_frac, int step, int left_gain, int right_gain,
|
||||
int[] mix_buffer, int frame_offset, int frames ) {
|
||||
int loop_end, offset, end, max_sample_idx, amplitude;
|
||||
sample_idx += OVERLAP;
|
||||
loop_end = loop_start + loop_length - 1;
|
||||
offset = frame_offset << 1;
|
||||
end = ( frame_offset + frames - 1 ) << 1;
|
||||
while( frames > 0 ) {
|
||||
if( sample_idx > loop_end ) {
|
||||
if( loop_length <= 1 ) {
|
||||
break;
|
||||
}
|
||||
sample_idx = loop_start + ( sample_idx - loop_start ) % loop_length;
|
||||
}
|
||||
max_sample_idx = sample_idx + ( ( sample_frac + ( frames - 1 ) * step ) >> IBXM.FP_SHIFT );
|
||||
if( max_sample_idx > loop_end ) {
|
||||
while( sample_idx <= loop_end ) {
|
||||
amplitude = sample_data[ sample_idx ];
|
||||
amplitude += ( sample_data[ sample_idx + 1 ] - amplitude ) * sample_frac >> IBXM.FP_SHIFT;
|
||||
mix_buffer[ offset++ ] += amplitude * left_gain >> IBXM.FP_SHIFT;
|
||||
mix_buffer[ offset++ ] += amplitude * right_gain >> IBXM.FP_SHIFT;
|
||||
sample_frac += step;
|
||||
sample_idx += sample_frac >> IBXM.FP_SHIFT;
|
||||
sample_frac &= IBXM.FP_MASK;
|
||||
}
|
||||
} else {
|
||||
while( offset <= end ) {
|
||||
amplitude = sample_data[ sample_idx ];
|
||||
amplitude += ( sample_data[ sample_idx + 1 ] - amplitude ) * sample_frac >> IBXM.FP_SHIFT;
|
||||
mix_buffer[ offset++ ] += amplitude * left_gain >> IBXM.FP_SHIFT;
|
||||
mix_buffer[ offset++ ] += amplitude * right_gain >> IBXM.FP_SHIFT;
|
||||
sample_frac += step;
|
||||
sample_idx += sample_frac >> IBXM.FP_SHIFT;
|
||||
sample_frac &= IBXM.FP_MASK;
|
||||
}
|
||||
}
|
||||
frames = ( end - offset + 2 ) >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
public void resample_sinc(
|
||||
int sample_idx, int sample_frac, int step, int left_gain, int right_gain,
|
||||
int[] mix_buffer, int frame_offset, int frames ) {
|
||||
int offset, end, loop_end, table_idx, a1, a2, amplitude;
|
||||
loop_end = loop_start + loop_length - 1;
|
||||
offset = frame_offset << 1;
|
||||
end = ( frame_offset + frames - 1 ) << 1;
|
||||
while( offset <= end ) {
|
||||
if( sample_idx > loop_end ) {
|
||||
if( loop_length <= 1 ) {
|
||||
break;
|
||||
}
|
||||
sample_idx = loop_start + ( sample_idx - loop_start ) % loop_length;
|
||||
}
|
||||
table_idx = ( sample_frac >> INTERP_SHIFT ) << POINT_SHIFT;
|
||||
a1 = sinc_table[ table_idx + 0 ] * sample_data[ sample_idx + 0 ] >> 15;
|
||||
a1 += sinc_table[ table_idx + 1 ] * sample_data[ sample_idx + 1 ] >> 15;
|
||||
a1 += sinc_table[ table_idx + 2 ] * sample_data[ sample_idx + 2 ] >> 15;
|
||||
a1 += sinc_table[ table_idx + 3 ] * sample_data[ sample_idx + 3 ] >> 15;
|
||||
a1 += sinc_table[ table_idx + 4 ] * sample_data[ sample_idx + 4 ] >> 15;
|
||||
a1 += sinc_table[ table_idx + 5 ] * sample_data[ sample_idx + 5 ] >> 15;
|
||||
a1 += sinc_table[ table_idx + 6 ] * sample_data[ sample_idx + 6 ] >> 15;
|
||||
a1 += sinc_table[ table_idx + 7 ] * sample_data[ sample_idx + 7 ] >> 15;
|
||||
a1 += sinc_table[ table_idx + 8 ] * sample_data[ sample_idx + 8 ] >> 15;
|
||||
a1 += sinc_table[ table_idx + 9 ] * sample_data[ sample_idx + 9 ] >> 15;
|
||||
a1 += sinc_table[ table_idx + 10 ] * sample_data[ sample_idx + 10 ] >> 15;
|
||||
a1 += sinc_table[ table_idx + 11 ] * sample_data[ sample_idx + 11 ] >> 15;
|
||||
a1 += sinc_table[ table_idx + 12 ] * sample_data[ sample_idx + 12 ] >> 15;
|
||||
a1 += sinc_table[ table_idx + 13 ] * sample_data[ sample_idx + 13 ] >> 15;
|
||||
a1 += sinc_table[ table_idx + 14 ] * sample_data[ sample_idx + 14 ] >> 15;
|
||||
a1 += sinc_table[ table_idx + 15 ] * sample_data[ sample_idx + 15 ] >> 15;
|
||||
a2 = sinc_table[ table_idx + 16 ] * sample_data[ sample_idx + 0 ] >> 15;
|
||||
a2 += sinc_table[ table_idx + 17 ] * sample_data[ sample_idx + 1 ] >> 15;
|
||||
a2 += sinc_table[ table_idx + 18 ] * sample_data[ sample_idx + 2 ] >> 15;
|
||||
a2 += sinc_table[ table_idx + 19 ] * sample_data[ sample_idx + 3 ] >> 15;
|
||||
a2 += sinc_table[ table_idx + 20 ] * sample_data[ sample_idx + 4 ] >> 15;
|
||||
a2 += sinc_table[ table_idx + 21 ] * sample_data[ sample_idx + 5 ] >> 15;
|
||||
a2 += sinc_table[ table_idx + 22 ] * sample_data[ sample_idx + 6 ] >> 15;
|
||||
a2 += sinc_table[ table_idx + 23 ] * sample_data[ sample_idx + 7 ] >> 15;
|
||||
a2 += sinc_table[ table_idx + 24 ] * sample_data[ sample_idx + 8 ] >> 15;
|
||||
a2 += sinc_table[ table_idx + 25 ] * sample_data[ sample_idx + 9 ] >> 15;
|
||||
a2 += sinc_table[ table_idx + 26 ] * sample_data[ sample_idx + 10 ] >> 15;
|
||||
a2 += sinc_table[ table_idx + 27 ] * sample_data[ sample_idx + 11 ] >> 15;
|
||||
a2 += sinc_table[ table_idx + 28 ] * sample_data[ sample_idx + 12 ] >> 15;
|
||||
a2 += sinc_table[ table_idx + 29 ] * sample_data[ sample_idx + 13 ] >> 15;
|
||||
a2 += sinc_table[ table_idx + 30 ] * sample_data[ sample_idx + 14 ] >> 15;
|
||||
a2 += sinc_table[ table_idx + 31 ] * sample_data[ sample_idx + 15 ] >> 15;
|
||||
amplitude = a1 + ( ( a2 - a1 ) * ( sample_frac & INTERP_BITMASK ) >> INTERP_SHIFT );
|
||||
mix_buffer[ offset ] += amplitude * left_gain >> IBXM.FP_SHIFT;
|
||||
mix_buffer[ offset + 1 ] += amplitude * right_gain >> IBXM.FP_SHIFT;
|
||||
offset += 2;
|
||||
sample_frac += step;
|
||||
sample_idx += sample_frac >> IBXM.FP_SHIFT;
|
||||
sample_frac &= IBXM.FP_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean has_finished( int sample_idx ) {
|
||||
boolean finished;
|
||||
finished = false;
|
||||
if( loop_length <= 1 && sample_idx > loop_start ) {
|
||||
finished = true;
|
||||
}
|
||||
return finished;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,489 +1,489 @@
|
|||
|
||||
package ibxm;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public class ScreamTracker3 {
|
||||
private static final int[] effect_map = new int[] {
|
||||
0xFF,
|
||||
0x25, /* A: Set Speed.*/
|
||||
0x0B, /* B: Pattern Jump.*/
|
||||
0x0D, /* C: Pattern Break.*/
|
||||
0x0A, /* D: Volume Slide.*/
|
||||
0x02, /* E: Portamento Down.*/
|
||||
0x01, /* F: Portamento Up.*/
|
||||
0x03, /* G: Tone Portamento.*/
|
||||
0x04, /* H: Vibrato.*/
|
||||
0x1D, /* I: Tremor.*/
|
||||
0x00, /* J: Arpeggio.*/
|
||||
0x06, /* K: Vibrato + Volume Slide.*/
|
||||
0x05, /* L: Tone Portamento + Volume Slide.*/
|
||||
0xFF, /* M: */
|
||||
0xFF, /* N: */
|
||||
0x09, /* O: Sample Offset.*/
|
||||
0xFF, /* P: */
|
||||
0x1B, /* Q: Retrig + Volume Slide.*/
|
||||
0x07, /* R: Tremolo.*/
|
||||
0x0E, /* S: Extended Effects.*/
|
||||
0x0F, /* T: Set Tempo.*/
|
||||
0x24, /* U: Fine Vibrato.*/
|
||||
0x10, /* V: Set Global Volume. */
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF
|
||||
};
|
||||
|
||||
private static final int[] effect_s_map = new int[] {
|
||||
0x00, /* 0: Set Filter.*/
|
||||
0x03, /* 1: Glissando.*/
|
||||
0x05, /* 2: Set Fine Tune.*/
|
||||
0x04, /* 3: Set Vibrato Waveform.*/
|
||||
0x07, /* 4: Set Tremolo Waveform.*/
|
||||
0xFF, /* 5: */
|
||||
0xFF, /* 6: */
|
||||
0xFF, /* 7: */
|
||||
0x08, /* 8: Set Panning.*/
|
||||
0xFF, /* 9: */
|
||||
0x09, /* A: Stereo Control.*/
|
||||
0x06, /* B: Pattern Loop.*/
|
||||
0x0C, /* C: Note Cut.*/
|
||||
0x0D, /* D: Note Delay.*/
|
||||
0x0E, /* E: Pattern Delay.*/
|
||||
0x0F /* F: Invert Loop.*/
|
||||
};
|
||||
|
||||
public static boolean is_s3m( byte[] header_96_bytes ) {
|
||||
String s3m_identifier;
|
||||
s3m_identifier = ascii_text( header_96_bytes, 44, 4 );
|
||||
return s3m_identifier.equals( "SCRM" );
|
||||
}
|
||||
|
||||
public static Module load_s3m( byte[] header_96_bytes, DataInput data_input ) throws IOException {
|
||||
int num_pattern_orders, num_instruments, num_patterns, num_channels;
|
||||
int flags, tracker_version, master_volume, panning, channel_config, sequence_length;
|
||||
int instrument_idx, pattern_idx, channel_idx, order_idx, panning_offset;
|
||||
boolean signed_samples, stereo_mode, default_panning;
|
||||
int[] channel_map, sequence;
|
||||
byte[] s3m_file;
|
||||
Module module;
|
||||
Instrument instrument;
|
||||
s3m_file = read_s3m_file( header_96_bytes, data_input );
|
||||
module = new Module();
|
||||
module.song_title = ascii_text( s3m_file, 0, 28 );
|
||||
num_pattern_orders = get_num_pattern_orders( s3m_file );
|
||||
num_instruments = get_num_instruments( s3m_file );
|
||||
num_patterns = get_num_patterns( s3m_file );
|
||||
flags = unsigned_short_le( s3m_file, 38 );
|
||||
tracker_version = unsigned_short_le( s3m_file, 40 );
|
||||
if( ( flags & 0x40 ) == 0x40 || tracker_version == 0x1300 ) {
|
||||
module.fast_volume_slides = true;
|
||||
}
|
||||
signed_samples = false;
|
||||
if( unsigned_short_le( s3m_file, 42 ) == 0x01 ) {
|
||||
signed_samples = true;
|
||||
}
|
||||
module.global_volume = s3m_file[ 48 ] & 0xFF;
|
||||
module.default_speed = s3m_file[ 49 ] & 0xFF;
|
||||
module.default_tempo = s3m_file[ 50 ] & 0xFF;
|
||||
master_volume = s3m_file[ 51 ] & 0x7F;
|
||||
module.channel_gain = ( master_volume << IBXM.FP_SHIFT ) >> 7;
|
||||
stereo_mode = ( s3m_file[ 51 ] & 0x80 ) == 0x80;
|
||||
default_panning = ( s3m_file[ 53 ] & 0xFF ) == 0xFC;
|
||||
channel_map = new int[ 32 ];
|
||||
num_channels = 0;
|
||||
for( channel_idx = 0; channel_idx < 32; channel_idx++ ) {
|
||||
channel_config = s3m_file[ 64 + channel_idx ] & 0xFF;
|
||||
channel_map[ channel_idx ] = -1;
|
||||
if( channel_config < 16 ) {
|
||||
channel_map[ channel_idx ] = num_channels;
|
||||
num_channels += 1;
|
||||
}
|
||||
}
|
||||
module.set_num_channels( num_channels );
|
||||
panning_offset = 96 + num_pattern_orders + num_instruments * 2 + num_patterns * 2;
|
||||
for( channel_idx = 0; channel_idx < 32; channel_idx++ ) {
|
||||
if( channel_map[ channel_idx ] < 0 ) continue;
|
||||
panning = 7;
|
||||
if( stereo_mode ) {
|
||||
panning = 12;
|
||||
if( ( s3m_file[ 64 + channel_idx ] & 0xFF ) < 8 ) {
|
||||
panning = 3;
|
||||
}
|
||||
}
|
||||
if( default_panning ) {
|
||||
flags = s3m_file[ panning_offset + channel_idx ] & 0xFF;
|
||||
if( ( flags & 0x20 ) == 0x20 ) {
|
||||
panning = flags & 0xF;
|
||||
}
|
||||
}
|
||||
module.set_initial_panning( channel_map[ channel_idx ], panning * 17 );
|
||||
}
|
||||
sequence = read_s3m_sequence( s3m_file );
|
||||
module.set_sequence_length( sequence.length );
|
||||
for( order_idx = 0; order_idx < sequence.length; order_idx++ ) {
|
||||
module.set_sequence( order_idx, sequence[ order_idx ] );
|
||||
}
|
||||
module.set_num_instruments( num_instruments );
|
||||
for( instrument_idx = 0; instrument_idx < num_instruments; instrument_idx++ ) {
|
||||
instrument = read_s3m_instrument( s3m_file, instrument_idx, signed_samples );
|
||||
module.set_instrument( instrument_idx + 1, instrument );
|
||||
}
|
||||
module.set_num_patterns( num_patterns );
|
||||
for( pattern_idx = 0; pattern_idx < num_patterns; pattern_idx++ ) {
|
||||
module.set_pattern( pattern_idx, read_s3m_pattern( s3m_file, pattern_idx, channel_map ) );
|
||||
}
|
||||
return module;
|
||||
}
|
||||
|
||||
private static int[] read_s3m_sequence( byte[] s3m_file ) {
|
||||
int num_pattern_orders, sequence_length;
|
||||
int sequence_idx, order_idx, pattern_order;
|
||||
int[] sequence;
|
||||
num_pattern_orders = get_num_pattern_orders( s3m_file );
|
||||
sequence_length = 0;
|
||||
for( order_idx = 0; order_idx < num_pattern_orders; order_idx++ ) {
|
||||
pattern_order = s3m_file[ 96 + order_idx ] & 0xFF;
|
||||
if( pattern_order == 255 ) {
|
||||
break;
|
||||
} else if( pattern_order < 254 ) {
|
||||
sequence_length += 1;
|
||||
}
|
||||
}
|
||||
sequence = new int[ sequence_length ];
|
||||
sequence_idx = 0;
|
||||
for( order_idx = 0; order_idx < num_pattern_orders; order_idx++ ) {
|
||||
pattern_order = s3m_file[ 96 + order_idx ] & 0xFF;
|
||||
if( pattern_order == 255 ) {
|
||||
break;
|
||||
} else if( pattern_order < 254 ) {
|
||||
sequence[ sequence_idx ] = pattern_order;
|
||||
sequence_idx += 1;
|
||||
}
|
||||
}
|
||||
return sequence;
|
||||
}
|
||||
|
||||
private static Instrument read_s3m_instrument( byte[] s3m_file, int instrument_idx, boolean signed_samples ) {
|
||||
int instrument_offset;
|
||||
int sample_data_offset, sample_data_length;
|
||||
int loop_start, loop_length, c2_rate, sample_idx, amplitude;
|
||||
boolean sixteen_bit;
|
||||
Instrument instrument;
|
||||
Sample sample;
|
||||
short[] sample_data;
|
||||
instrument_offset = get_instrument_offset( s3m_file, instrument_idx );
|
||||
instrument = new Instrument();
|
||||
instrument.name = ascii_text( s3m_file, instrument_offset + 48, 28 );
|
||||
sample = new Sample();
|
||||
if( s3m_file[ instrument_offset ] == 1 ) {
|
||||
sample_data_length = get_sample_data_length( s3m_file, instrument_offset );
|
||||
loop_start = unsigned_short_le( s3m_file, instrument_offset + 20 );
|
||||
loop_length = unsigned_short_le( s3m_file, instrument_offset + 24 ) - loop_start;
|
||||
sample.volume = s3m_file[ instrument_offset + 28 ] & 0xFF;
|
||||
if( s3m_file[ instrument_offset + 30 ] != 0 ) {
|
||||
throw new IllegalArgumentException( "ScreamTracker3: Packed samples not supported!" );
|
||||
}
|
||||
if( ( s3m_file[ instrument_offset + 31 ] & 0x01 ) == 0 ) {
|
||||
loop_length = 0;
|
||||
}
|
||||
if( ( s3m_file[ instrument_offset + 31 ] & 0x02 ) != 0 ) {
|
||||
throw new IllegalArgumentException( "ScreamTracker3: Stereo samples not supported!" );
|
||||
}
|
||||
sixteen_bit = ( s3m_file[ instrument_offset + 31 ] & 0x04 ) != 0;
|
||||
c2_rate = unsigned_short_le( s3m_file, instrument_offset + 32 );
|
||||
sample.transpose = LogTable.log_2( c2_rate ) - LogTable.log_2( 8363 );
|
||||
sample_data_offset = get_sample_data_offset( s3m_file, instrument_offset );
|
||||
if( sixteen_bit ) {
|
||||
if( signed_samples ) {
|
||||
throw new IllegalArgumentException( "ScreamTracker3: Signed 16-bit samples not supported!" );
|
||||
}
|
||||
sample_data_length >>= 1;
|
||||
sample_data = new short[ sample_data_length ];
|
||||
for( sample_idx = 0; sample_idx < sample_data_length; sample_idx++ ) {
|
||||
amplitude = s3m_file[ sample_data_offset + sample_idx * 2 ] & 0xFF;
|
||||
amplitude |= ( s3m_file[ sample_data_offset + sample_idx * 2 + 1 ] & 0xFF ) << 8;
|
||||
sample_data[ sample_idx ] = ( short ) ( amplitude - 32768 );
|
||||
}
|
||||
} else {
|
||||
sample_data = new short[ sample_data_length ];
|
||||
if( signed_samples ) {
|
||||
for( sample_idx = 0; sample_idx < sample_data_length; sample_idx++ ) {
|
||||
amplitude = s3m_file[ sample_data_offset + sample_idx ] << 8;
|
||||
sample_data[ sample_idx ] = ( short ) amplitude;
|
||||
}
|
||||
} else {
|
||||
for( sample_idx = 0; sample_idx < sample_data_length; sample_idx++ ) {
|
||||
amplitude = ( s3m_file[ sample_data_offset + sample_idx ] & 0xFF ) << 8;
|
||||
sample_data[ sample_idx ] = ( short ) ( amplitude - 32768 );
|
||||
}
|
||||
}
|
||||
}
|
||||
sample.set_sample_data( sample_data, loop_start, loop_length, false );
|
||||
}
|
||||
instrument.set_num_samples( 1 );
|
||||
instrument.set_sample( 0, sample );
|
||||
return instrument;
|
||||
}
|
||||
|
||||
private static Pattern read_s3m_pattern( byte[] s3m_file, int pattern_idx, int[] channel_map ) {
|
||||
int pattern_offset;
|
||||
int num_channels, num_notes;
|
||||
int row_idx, channel_idx, note_idx;
|
||||
int token, key, volume_column, effect, effect_param;
|
||||
byte[] pattern_data;
|
||||
Pattern pattern;
|
||||
num_channels = 0;
|
||||
for( channel_idx = 0; channel_idx < 32; channel_idx++ ) {
|
||||
if( channel_map[ channel_idx ] >= num_channels ) {
|
||||
num_channels = channel_idx + 1;
|
||||
}
|
||||
}
|
||||
num_notes = num_channels * 64;
|
||||
pattern_data = new byte[ num_notes * 5 ];
|
||||
row_idx = 0;
|
||||
pattern_offset = get_pattern_offset( s3m_file, pattern_idx ) + 2;
|
||||
while( row_idx < 64 ) {
|
||||
token = s3m_file[ pattern_offset ] & 0xFF;
|
||||
pattern_offset += 1;
|
||||
if( token > 0 ) {
|
||||
channel_idx = channel_map[ token & 0x1F ];
|
||||
note_idx = ( num_channels * row_idx + channel_idx ) * 5;
|
||||
if( ( token & 0x20 ) == 0x20 ) {
|
||||
/* Key + Instrument.*/
|
||||
if( channel_idx >= 0 ) {
|
||||
key = s3m_file[ pattern_offset ] & 0xFF;
|
||||
if( key == 255 ) {
|
||||
key = 0;
|
||||
} else if( key == 254 ) {
|
||||
key = 97;
|
||||
} else {
|
||||
key = ( ( key & 0xF0 ) >> 4 ) * 12 + ( key & 0x0F ) + 1;
|
||||
while( key > 96 ) {
|
||||
key = key - 12;
|
||||
}
|
||||
}
|
||||
pattern_data[ note_idx ] = ( byte ) key;
|
||||
pattern_data[ note_idx + 1 ] = s3m_file[ pattern_offset + 1 ];
|
||||
}
|
||||
pattern_offset += 2;
|
||||
}
|
||||
if( ( token & 0x40 ) == 0x40 ) {
|
||||
/* Volume.*/
|
||||
if( channel_idx >= 0 ) {
|
||||
volume_column = ( s3m_file[ pattern_offset ] & 0xFF ) + 0x10;
|
||||
pattern_data[ note_idx + 2 ] = ( byte ) volume_column;
|
||||
}
|
||||
pattern_offset += 1;
|
||||
}
|
||||
if( ( token & 0x80 ) == 0x80 ) {
|
||||
/* Effect + Param.*/
|
||||
if( channel_idx >= 0 ) {
|
||||
effect = s3m_file[ pattern_offset ] & 0xFF;
|
||||
effect_param = s3m_file[ pattern_offset + 1 ] & 0xFF;
|
||||
effect = effect_map[ effect & 0x1F ];
|
||||
if( effect == 0xFF ) {
|
||||
effect = 0;
|
||||
effect_param = 0;
|
||||
}
|
||||
if( effect == 0x0E ) {
|
||||
effect = effect_s_map[ ( effect_param & 0xF0 ) >> 4 ];
|
||||
effect_param = effect_param & 0x0F;
|
||||
switch( effect ) {
|
||||
case 0x08:
|
||||
effect = 0x08;
|
||||
effect_param = effect_param * 17;
|
||||
break;
|
||||
case 0x09:
|
||||
effect = 0x08;
|
||||
if( effect_param > 7 ) {
|
||||
effect_param -= 8;
|
||||
} else {
|
||||
effect_param += 8;
|
||||
}
|
||||
effect_param = effect_param * 17;
|
||||
break;
|
||||
case 0xFF:
|
||||
effect = 0;
|
||||
effect_param = 0;
|
||||
break;
|
||||
default:
|
||||
effect_param = ( ( effect & 0x0F ) << 4 ) | ( effect_param & 0x0F );
|
||||
effect = 0x0E;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pattern_data[ note_idx + 3 ] = ( byte ) effect;
|
||||
pattern_data[ note_idx + 4 ] = ( byte ) effect_param;
|
||||
}
|
||||
pattern_offset += 2;
|
||||
}
|
||||
} else {
|
||||
row_idx += 1;
|
||||
}
|
||||
}
|
||||
pattern = new Pattern();
|
||||
pattern.num_rows = 64;
|
||||
pattern.set_pattern_data( pattern_data );
|
||||
return pattern;
|
||||
}
|
||||
|
||||
private static byte[] read_s3m_file( byte[] header_96_bytes, DataInput data_input ) throws IOException {
|
||||
int s3m_file_length;
|
||||
int num_pattern_orders, num_instruments, num_patterns;
|
||||
int instrument_idx, pattern_idx;
|
||||
int instrument_offset, sample_data_offset, pattern_offset;
|
||||
byte[] s3m_file;
|
||||
if( !is_s3m( header_96_bytes ) ) {
|
||||
throw new IllegalArgumentException( "ScreamTracker3: Not an S3M file!" );
|
||||
}
|
||||
s3m_file = header_96_bytes;
|
||||
s3m_file_length = header_96_bytes.length;
|
||||
num_pattern_orders = get_num_pattern_orders( s3m_file );
|
||||
num_instruments = get_num_instruments( s3m_file );
|
||||
num_patterns = get_num_patterns( s3m_file );
|
||||
s3m_file_length += num_pattern_orders;
|
||||
s3m_file_length += num_instruments * 2;
|
||||
s3m_file_length += num_patterns * 2;
|
||||
/* Read enough of file to calculate the length.*/
|
||||
s3m_file = read_more( s3m_file, s3m_file_length, data_input );
|
||||
for( instrument_idx = 0; instrument_idx < num_instruments; instrument_idx++ ) {
|
||||
instrument_offset = get_instrument_offset( s3m_file, instrument_idx );
|
||||
instrument_offset += 80;
|
||||
if( instrument_offset > s3m_file_length ) {
|
||||
s3m_file_length = instrument_offset;
|
||||
}
|
||||
}
|
||||
for( pattern_idx = 0; pattern_idx < num_patterns; pattern_idx++ ) {
|
||||
pattern_offset = get_pattern_offset( s3m_file, pattern_idx );
|
||||
pattern_offset += 2;
|
||||
if( pattern_offset > s3m_file_length ) {
|
||||
s3m_file_length = pattern_offset;
|
||||
}
|
||||
}
|
||||
s3m_file = read_more( s3m_file, s3m_file_length, data_input );
|
||||
/* Read rest of file.*/
|
||||
for( instrument_idx = 0; instrument_idx < num_instruments; instrument_idx++ ) {
|
||||
instrument_offset = get_instrument_offset( s3m_file, instrument_idx );
|
||||
sample_data_offset = get_sample_data_offset( s3m_file, instrument_offset );
|
||||
sample_data_offset += get_sample_data_length( s3m_file, instrument_offset );
|
||||
if( sample_data_offset > s3m_file_length ) {
|
||||
s3m_file_length = sample_data_offset;
|
||||
}
|
||||
}
|
||||
for( pattern_idx = 0; pattern_idx < num_patterns; pattern_idx++ ) {
|
||||
pattern_offset = get_pattern_offset( s3m_file, pattern_idx );
|
||||
pattern_offset += get_pattern_length( s3m_file, pattern_offset );
|
||||
pattern_offset += 2;
|
||||
if( pattern_offset > s3m_file_length ) {
|
||||
s3m_file_length = pattern_offset;
|
||||
}
|
||||
}
|
||||
s3m_file = read_more( s3m_file, s3m_file_length, data_input );
|
||||
return s3m_file;
|
||||
}
|
||||
|
||||
private static int get_num_pattern_orders( byte[] s3m_file ) {
|
||||
int num_pattern_orders;
|
||||
num_pattern_orders = unsigned_short_le( s3m_file, 32 );
|
||||
return num_pattern_orders;
|
||||
}
|
||||
|
||||
private static int get_num_instruments( byte[] s3m_file ) {
|
||||
int num_instruments;
|
||||
num_instruments = unsigned_short_le( s3m_file, 34 );
|
||||
return num_instruments;
|
||||
}
|
||||
|
||||
private static int get_num_patterns( byte[] s3m_file ) {
|
||||
int num_patterns;
|
||||
num_patterns = unsigned_short_le( s3m_file, 36 );
|
||||
return num_patterns;
|
||||
}
|
||||
|
||||
private static int get_instrument_offset( byte[] s3m_file, int instrument_idx ) {
|
||||
int instrument_offset, pointer_offset;
|
||||
pointer_offset = 96 + get_num_pattern_orders( s3m_file );
|
||||
instrument_offset = unsigned_short_le( s3m_file, pointer_offset + instrument_idx * 2 ) << 4;
|
||||
return instrument_offset;
|
||||
}
|
||||
|
||||
private static int get_sample_data_offset( byte[] s3m_file, int instrument_offset ) {
|
||||
int sample_data_offset;
|
||||
sample_data_offset = 0;
|
||||
if( s3m_file[ instrument_offset ] == 1 ) {
|
||||
sample_data_offset = ( s3m_file[ instrument_offset + 13 ] & 0xFF ) << 20;
|
||||
sample_data_offset |= unsigned_short_le( s3m_file, instrument_offset + 14 ) << 4;
|
||||
}
|
||||
return sample_data_offset;
|
||||
}
|
||||
|
||||
private static int get_sample_data_length( byte[] s3m_file, int instrument_offset ) {
|
||||
int sample_data_length;
|
||||
boolean sixteen_bit;
|
||||
sample_data_length = 0;
|
||||
if( s3m_file[ instrument_offset ] == 1 ) {
|
||||
sample_data_length = unsigned_short_le( s3m_file, instrument_offset + 16 );
|
||||
sixteen_bit = ( s3m_file[ instrument_offset + 31 ] & 0x04 ) != 0;
|
||||
if( sixteen_bit ) {
|
||||
sample_data_length <<= 1;
|
||||
}
|
||||
}
|
||||
return sample_data_length;
|
||||
}
|
||||
|
||||
private static int get_pattern_offset( byte[] s3m_file, int pattern_idx ) {
|
||||
int pattern_offset, pointer_offset;
|
||||
pointer_offset = 96 + get_num_pattern_orders( s3m_file );
|
||||
pointer_offset += get_num_instruments( s3m_file ) * 2;
|
||||
pattern_offset = unsigned_short_le( s3m_file, pointer_offset + pattern_idx * 2 ) << 4;
|
||||
return pattern_offset;
|
||||
}
|
||||
|
||||
private static int get_pattern_length( byte[] s3m_file, int pattern_offset ) {
|
||||
int pattern_length;
|
||||
pattern_length = unsigned_short_le( s3m_file, pattern_offset );
|
||||
return pattern_length;
|
||||
}
|
||||
|
||||
private static byte[] read_more( byte[] old_data, int new_length, DataInput data_input ) throws IOException {
|
||||
byte[] new_data;
|
||||
new_data = old_data;
|
||||
if( new_length > old_data.length ) {
|
||||
new_data = new byte[ new_length ];
|
||||
System.arraycopy( old_data, 0, new_data, 0, old_data.length );
|
||||
try {
|
||||
data_input.readFully( new_data, old_data.length, new_data.length - old_data.length );
|
||||
} catch( EOFException e ) {
|
||||
System.out.println( "ScreamTracker3: Module has been truncated!" );
|
||||
}
|
||||
}
|
||||
return new_data;
|
||||
}
|
||||
|
||||
private static int unsigned_short_le( byte[] buffer, int offset ) {
|
||||
int value;
|
||||
value = buffer[ offset ] & 0xFF;
|
||||
value = value | ( ( buffer[ offset + 1 ] & 0xFF ) << 8 );
|
||||
return value;
|
||||
}
|
||||
|
||||
private static String ascii_text( byte[] buffer, int offset, int length ) {
|
||||
int idx, chr;
|
||||
byte[] string_buffer;
|
||||
String string;
|
||||
string_buffer = new byte[ length ];
|
||||
for( idx = 0; idx < length; idx++ ) {
|
||||
chr = buffer[ offset + idx ];
|
||||
if( chr < 32 ) {
|
||||
chr = 32;
|
||||
}
|
||||
string_buffer[ idx ] = ( byte ) chr;
|
||||
}
|
||||
try {
|
||||
string = new String( string_buffer, 0, length, "ISO-8859-1" );
|
||||
} catch( UnsupportedEncodingException e ) {
|
||||
string = "";
|
||||
}
|
||||
return string;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
package ibxm;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public class ScreamTracker3 {
|
||||
private static final int[] effect_map = new int[] {
|
||||
0xFF,
|
||||
0x25, /* A: Set Speed.*/
|
||||
0x0B, /* B: Pattern Jump.*/
|
||||
0x0D, /* C: Pattern Break.*/
|
||||
0x0A, /* D: Volume Slide.*/
|
||||
0x02, /* E: Portamento Down.*/
|
||||
0x01, /* F: Portamento Up.*/
|
||||
0x03, /* G: Tone Portamento.*/
|
||||
0x04, /* H: Vibrato.*/
|
||||
0x1D, /* I: Tremor.*/
|
||||
0x00, /* J: Arpeggio.*/
|
||||
0x06, /* K: Vibrato + Volume Slide.*/
|
||||
0x05, /* L: Tone Portamento + Volume Slide.*/
|
||||
0xFF, /* M: */
|
||||
0xFF, /* N: */
|
||||
0x09, /* O: Sample Offset.*/
|
||||
0xFF, /* P: */
|
||||
0x1B, /* Q: Retrig + Volume Slide.*/
|
||||
0x07, /* R: Tremolo.*/
|
||||
0x0E, /* S: Extended Effects.*/
|
||||
0x0F, /* T: Set Tempo.*/
|
||||
0x24, /* U: Fine Vibrato.*/
|
||||
0x10, /* V: Set Global Volume. */
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF
|
||||
};
|
||||
|
||||
private static final int[] effect_s_map = new int[] {
|
||||
0x00, /* 0: Set Filter.*/
|
||||
0x03, /* 1: Glissando.*/
|
||||
0x05, /* 2: Set Fine Tune.*/
|
||||
0x04, /* 3: Set Vibrato Waveform.*/
|
||||
0x07, /* 4: Set Tremolo Waveform.*/
|
||||
0xFF, /* 5: */
|
||||
0xFF, /* 6: */
|
||||
0xFF, /* 7: */
|
||||
0x08, /* 8: Set Panning.*/
|
||||
0xFF, /* 9: */
|
||||
0x09, /* A: Stereo Control.*/
|
||||
0x06, /* B: Pattern Loop.*/
|
||||
0x0C, /* C: Note Cut.*/
|
||||
0x0D, /* D: Note Delay.*/
|
||||
0x0E, /* E: Pattern Delay.*/
|
||||
0x0F /* F: Invert Loop.*/
|
||||
};
|
||||
|
||||
public static boolean is_s3m( byte[] header_96_bytes ) {
|
||||
String s3m_identifier;
|
||||
s3m_identifier = ascii_text( header_96_bytes, 44, 4 );
|
||||
return s3m_identifier.equals( "SCRM" );
|
||||
}
|
||||
|
||||
public static Module load_s3m( byte[] header_96_bytes, DataInput data_input ) throws IOException {
|
||||
int num_pattern_orders, num_instruments, num_patterns, num_channels;
|
||||
int flags, tracker_version, master_volume, panning, channel_config, sequence_length;
|
||||
int instrument_idx, pattern_idx, channel_idx, order_idx, panning_offset;
|
||||
boolean signed_samples, stereo_mode, default_panning;
|
||||
int[] channel_map, sequence;
|
||||
byte[] s3m_file;
|
||||
Module module;
|
||||
Instrument instrument;
|
||||
s3m_file = read_s3m_file( header_96_bytes, data_input );
|
||||
module = new Module();
|
||||
module.song_title = ascii_text( s3m_file, 0, 28 );
|
||||
num_pattern_orders = get_num_pattern_orders( s3m_file );
|
||||
num_instruments = get_num_instruments( s3m_file );
|
||||
num_patterns = get_num_patterns( s3m_file );
|
||||
flags = unsigned_short_le( s3m_file, 38 );
|
||||
tracker_version = unsigned_short_le( s3m_file, 40 );
|
||||
if( ( flags & 0x40 ) == 0x40 || tracker_version == 0x1300 ) {
|
||||
module.fast_volume_slides = true;
|
||||
}
|
||||
signed_samples = false;
|
||||
if( unsigned_short_le( s3m_file, 42 ) == 0x01 ) {
|
||||
signed_samples = true;
|
||||
}
|
||||
module.global_volume = s3m_file[ 48 ] & 0xFF;
|
||||
module.default_speed = s3m_file[ 49 ] & 0xFF;
|
||||
module.default_tempo = s3m_file[ 50 ] & 0xFF;
|
||||
master_volume = s3m_file[ 51 ] & 0x7F;
|
||||
module.channel_gain = ( master_volume << IBXM.FP_SHIFT ) >> 7;
|
||||
stereo_mode = ( s3m_file[ 51 ] & 0x80 ) == 0x80;
|
||||
default_panning = ( s3m_file[ 53 ] & 0xFF ) == 0xFC;
|
||||
channel_map = new int[ 32 ];
|
||||
num_channels = 0;
|
||||
for( channel_idx = 0; channel_idx < 32; channel_idx++ ) {
|
||||
channel_config = s3m_file[ 64 + channel_idx ] & 0xFF;
|
||||
channel_map[ channel_idx ] = -1;
|
||||
if( channel_config < 16 ) {
|
||||
channel_map[ channel_idx ] = num_channels;
|
||||
num_channels += 1;
|
||||
}
|
||||
}
|
||||
module.set_num_channels( num_channels );
|
||||
panning_offset = 96 + num_pattern_orders + num_instruments * 2 + num_patterns * 2;
|
||||
for( channel_idx = 0; channel_idx < 32; channel_idx++ ) {
|
||||
if( channel_map[ channel_idx ] < 0 ) continue;
|
||||
panning = 7;
|
||||
if( stereo_mode ) {
|
||||
panning = 12;
|
||||
if( ( s3m_file[ 64 + channel_idx ] & 0xFF ) < 8 ) {
|
||||
panning = 3;
|
||||
}
|
||||
}
|
||||
if( default_panning ) {
|
||||
flags = s3m_file[ panning_offset + channel_idx ] & 0xFF;
|
||||
if( ( flags & 0x20 ) == 0x20 ) {
|
||||
panning = flags & 0xF;
|
||||
}
|
||||
}
|
||||
module.set_initial_panning( channel_map[ channel_idx ], panning * 17 );
|
||||
}
|
||||
sequence = read_s3m_sequence( s3m_file );
|
||||
module.set_sequence_length( sequence.length );
|
||||
for( order_idx = 0; order_idx < sequence.length; order_idx++ ) {
|
||||
module.set_sequence( order_idx, sequence[ order_idx ] );
|
||||
}
|
||||
module.set_num_instruments( num_instruments );
|
||||
for( instrument_idx = 0; instrument_idx < num_instruments; instrument_idx++ ) {
|
||||
instrument = read_s3m_instrument( s3m_file, instrument_idx, signed_samples );
|
||||
module.set_instrument( instrument_idx + 1, instrument );
|
||||
}
|
||||
module.set_num_patterns( num_patterns );
|
||||
for( pattern_idx = 0; pattern_idx < num_patterns; pattern_idx++ ) {
|
||||
module.set_pattern( pattern_idx, read_s3m_pattern( s3m_file, pattern_idx, channel_map ) );
|
||||
}
|
||||
return module;
|
||||
}
|
||||
|
||||
private static int[] read_s3m_sequence( byte[] s3m_file ) {
|
||||
int num_pattern_orders, sequence_length;
|
||||
int sequence_idx, order_idx, pattern_order;
|
||||
int[] sequence;
|
||||
num_pattern_orders = get_num_pattern_orders( s3m_file );
|
||||
sequence_length = 0;
|
||||
for( order_idx = 0; order_idx < num_pattern_orders; order_idx++ ) {
|
||||
pattern_order = s3m_file[ 96 + order_idx ] & 0xFF;
|
||||
if( pattern_order == 255 ) {
|
||||
break;
|
||||
} else if( pattern_order < 254 ) {
|
||||
sequence_length += 1;
|
||||
}
|
||||
}
|
||||
sequence = new int[ sequence_length ];
|
||||
sequence_idx = 0;
|
||||
for( order_idx = 0; order_idx < num_pattern_orders; order_idx++ ) {
|
||||
pattern_order = s3m_file[ 96 + order_idx ] & 0xFF;
|
||||
if( pattern_order == 255 ) {
|
||||
break;
|
||||
} else if( pattern_order < 254 ) {
|
||||
sequence[ sequence_idx ] = pattern_order;
|
||||
sequence_idx += 1;
|
||||
}
|
||||
}
|
||||
return sequence;
|
||||
}
|
||||
|
||||
private static Instrument read_s3m_instrument( byte[] s3m_file, int instrument_idx, boolean signed_samples ) {
|
||||
int instrument_offset;
|
||||
int sample_data_offset, sample_data_length;
|
||||
int loop_start, loop_length, c2_rate, sample_idx, amplitude;
|
||||
boolean sixteen_bit;
|
||||
Instrument instrument;
|
||||
Sample sample;
|
||||
short[] sample_data;
|
||||
instrument_offset = get_instrument_offset( s3m_file, instrument_idx );
|
||||
instrument = new Instrument();
|
||||
instrument.name = ascii_text( s3m_file, instrument_offset + 48, 28 );
|
||||
sample = new Sample();
|
||||
if( s3m_file[ instrument_offset ] == 1 ) {
|
||||
sample_data_length = get_sample_data_length( s3m_file, instrument_offset );
|
||||
loop_start = unsigned_short_le( s3m_file, instrument_offset + 20 );
|
||||
loop_length = unsigned_short_le( s3m_file, instrument_offset + 24 ) - loop_start;
|
||||
sample.volume = s3m_file[ instrument_offset + 28 ] & 0xFF;
|
||||
if( s3m_file[ instrument_offset + 30 ] != 0 ) {
|
||||
throw new IllegalArgumentException( "ScreamTracker3: Packed samples not supported!" );
|
||||
}
|
||||
if( ( s3m_file[ instrument_offset + 31 ] & 0x01 ) == 0 ) {
|
||||
loop_length = 0;
|
||||
}
|
||||
if( ( s3m_file[ instrument_offset + 31 ] & 0x02 ) != 0 ) {
|
||||
throw new IllegalArgumentException( "ScreamTracker3: Stereo samples not supported!" );
|
||||
}
|
||||
sixteen_bit = ( s3m_file[ instrument_offset + 31 ] & 0x04 ) != 0;
|
||||
c2_rate = unsigned_short_le( s3m_file, instrument_offset + 32 );
|
||||
sample.transpose = LogTable.log_2( c2_rate ) - LogTable.log_2( 8363 );
|
||||
sample_data_offset = get_sample_data_offset( s3m_file, instrument_offset );
|
||||
if( sixteen_bit ) {
|
||||
if( signed_samples ) {
|
||||
throw new IllegalArgumentException( "ScreamTracker3: Signed 16-bit samples not supported!" );
|
||||
}
|
||||
sample_data_length >>= 1;
|
||||
sample_data = new short[ sample_data_length ];
|
||||
for( sample_idx = 0; sample_idx < sample_data_length; sample_idx++ ) {
|
||||
amplitude = s3m_file[ sample_data_offset + sample_idx * 2 ] & 0xFF;
|
||||
amplitude |= ( s3m_file[ sample_data_offset + sample_idx * 2 + 1 ] & 0xFF ) << 8;
|
||||
sample_data[ sample_idx ] = ( short ) ( amplitude - 32768 );
|
||||
}
|
||||
} else {
|
||||
sample_data = new short[ sample_data_length ];
|
||||
if( signed_samples ) {
|
||||
for( sample_idx = 0; sample_idx < sample_data_length; sample_idx++ ) {
|
||||
amplitude = s3m_file[ sample_data_offset + sample_idx ] << 8;
|
||||
sample_data[ sample_idx ] = ( short ) amplitude;
|
||||
}
|
||||
} else {
|
||||
for( sample_idx = 0; sample_idx < sample_data_length; sample_idx++ ) {
|
||||
amplitude = ( s3m_file[ sample_data_offset + sample_idx ] & 0xFF ) << 8;
|
||||
sample_data[ sample_idx ] = ( short ) ( amplitude - 32768 );
|
||||
}
|
||||
}
|
||||
}
|
||||
sample.set_sample_data( sample_data, loop_start, loop_length, false );
|
||||
}
|
||||
instrument.set_num_samples( 1 );
|
||||
instrument.set_sample( 0, sample );
|
||||
return instrument;
|
||||
}
|
||||
|
||||
private static Pattern read_s3m_pattern( byte[] s3m_file, int pattern_idx, int[] channel_map ) {
|
||||
int pattern_offset;
|
||||
int num_channels, num_notes;
|
||||
int row_idx, channel_idx, note_idx;
|
||||
int token, key, volume_column, effect, effect_param;
|
||||
byte[] pattern_data;
|
||||
Pattern pattern;
|
||||
num_channels = 0;
|
||||
for( channel_idx = 0; channel_idx < 32; channel_idx++ ) {
|
||||
if( channel_map[ channel_idx ] >= num_channels ) {
|
||||
num_channels = channel_idx + 1;
|
||||
}
|
||||
}
|
||||
num_notes = num_channels * 64;
|
||||
pattern_data = new byte[ num_notes * 5 ];
|
||||
row_idx = 0;
|
||||
pattern_offset = get_pattern_offset( s3m_file, pattern_idx ) + 2;
|
||||
while( row_idx < 64 ) {
|
||||
token = s3m_file[ pattern_offset ] & 0xFF;
|
||||
pattern_offset += 1;
|
||||
if( token > 0 ) {
|
||||
channel_idx = channel_map[ token & 0x1F ];
|
||||
note_idx = ( num_channels * row_idx + channel_idx ) * 5;
|
||||
if( ( token & 0x20 ) == 0x20 ) {
|
||||
/* Key + Instrument.*/
|
||||
if( channel_idx >= 0 ) {
|
||||
key = s3m_file[ pattern_offset ] & 0xFF;
|
||||
if( key == 255 ) {
|
||||
key = 0;
|
||||
} else if( key == 254 ) {
|
||||
key = 97;
|
||||
} else {
|
||||
key = ( ( key & 0xF0 ) >> 4 ) * 12 + ( key & 0x0F ) + 1;
|
||||
while( key > 96 ) {
|
||||
key = key - 12;
|
||||
}
|
||||
}
|
||||
pattern_data[ note_idx ] = ( byte ) key;
|
||||
pattern_data[ note_idx + 1 ] = s3m_file[ pattern_offset + 1 ];
|
||||
}
|
||||
pattern_offset += 2;
|
||||
}
|
||||
if( ( token & 0x40 ) == 0x40 ) {
|
||||
/* Volume.*/
|
||||
if( channel_idx >= 0 ) {
|
||||
volume_column = ( s3m_file[ pattern_offset ] & 0xFF ) + 0x10;
|
||||
pattern_data[ note_idx + 2 ] = ( byte ) volume_column;
|
||||
}
|
||||
pattern_offset += 1;
|
||||
}
|
||||
if( ( token & 0x80 ) == 0x80 ) {
|
||||
/* Effect + Param.*/
|
||||
if( channel_idx >= 0 ) {
|
||||
effect = s3m_file[ pattern_offset ] & 0xFF;
|
||||
effect_param = s3m_file[ pattern_offset + 1 ] & 0xFF;
|
||||
effect = effect_map[ effect & 0x1F ];
|
||||
if( effect == 0xFF ) {
|
||||
effect = 0;
|
||||
effect_param = 0;
|
||||
}
|
||||
if( effect == 0x0E ) {
|
||||
effect = effect_s_map[ ( effect_param & 0xF0 ) >> 4 ];
|
||||
effect_param = effect_param & 0x0F;
|
||||
switch( effect ) {
|
||||
case 0x08:
|
||||
effect = 0x08;
|
||||
effect_param = effect_param * 17;
|
||||
break;
|
||||
case 0x09:
|
||||
effect = 0x08;
|
||||
if( effect_param > 7 ) {
|
||||
effect_param -= 8;
|
||||
} else {
|
||||
effect_param += 8;
|
||||
}
|
||||
effect_param = effect_param * 17;
|
||||
break;
|
||||
case 0xFF:
|
||||
effect = 0;
|
||||
effect_param = 0;
|
||||
break;
|
||||
default:
|
||||
effect_param = ( ( effect & 0x0F ) << 4 ) | ( effect_param & 0x0F );
|
||||
effect = 0x0E;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pattern_data[ note_idx + 3 ] = ( byte ) effect;
|
||||
pattern_data[ note_idx + 4 ] = ( byte ) effect_param;
|
||||
}
|
||||
pattern_offset += 2;
|
||||
}
|
||||
} else {
|
||||
row_idx += 1;
|
||||
}
|
||||
}
|
||||
pattern = new Pattern();
|
||||
pattern.num_rows = 64;
|
||||
pattern.set_pattern_data( pattern_data );
|
||||
return pattern;
|
||||
}
|
||||
|
||||
private static byte[] read_s3m_file( byte[] header_96_bytes, DataInput data_input ) throws IOException {
|
||||
int s3m_file_length;
|
||||
int num_pattern_orders, num_instruments, num_patterns;
|
||||
int instrument_idx, pattern_idx;
|
||||
int instrument_offset, sample_data_offset, pattern_offset;
|
||||
byte[] s3m_file;
|
||||
if( !is_s3m( header_96_bytes ) ) {
|
||||
throw new IllegalArgumentException( "ScreamTracker3: Not an S3M file!" );
|
||||
}
|
||||
s3m_file = header_96_bytes;
|
||||
s3m_file_length = header_96_bytes.length;
|
||||
num_pattern_orders = get_num_pattern_orders( s3m_file );
|
||||
num_instruments = get_num_instruments( s3m_file );
|
||||
num_patterns = get_num_patterns( s3m_file );
|
||||
s3m_file_length += num_pattern_orders;
|
||||
s3m_file_length += num_instruments * 2;
|
||||
s3m_file_length += num_patterns * 2;
|
||||
/* Read enough of file to calculate the length.*/
|
||||
s3m_file = read_more( s3m_file, s3m_file_length, data_input );
|
||||
for( instrument_idx = 0; instrument_idx < num_instruments; instrument_idx++ ) {
|
||||
instrument_offset = get_instrument_offset( s3m_file, instrument_idx );
|
||||
instrument_offset += 80;
|
||||
if( instrument_offset > s3m_file_length ) {
|
||||
s3m_file_length = instrument_offset;
|
||||
}
|
||||
}
|
||||
for( pattern_idx = 0; pattern_idx < num_patterns; pattern_idx++ ) {
|
||||
pattern_offset = get_pattern_offset( s3m_file, pattern_idx );
|
||||
pattern_offset += 2;
|
||||
if( pattern_offset > s3m_file_length ) {
|
||||
s3m_file_length = pattern_offset;
|
||||
}
|
||||
}
|
||||
s3m_file = read_more( s3m_file, s3m_file_length, data_input );
|
||||
/* Read rest of file.*/
|
||||
for( instrument_idx = 0; instrument_idx < num_instruments; instrument_idx++ ) {
|
||||
instrument_offset = get_instrument_offset( s3m_file, instrument_idx );
|
||||
sample_data_offset = get_sample_data_offset( s3m_file, instrument_offset );
|
||||
sample_data_offset += get_sample_data_length( s3m_file, instrument_offset );
|
||||
if( sample_data_offset > s3m_file_length ) {
|
||||
s3m_file_length = sample_data_offset;
|
||||
}
|
||||
}
|
||||
for( pattern_idx = 0; pattern_idx < num_patterns; pattern_idx++ ) {
|
||||
pattern_offset = get_pattern_offset( s3m_file, pattern_idx );
|
||||
pattern_offset += get_pattern_length( s3m_file, pattern_offset );
|
||||
pattern_offset += 2;
|
||||
if( pattern_offset > s3m_file_length ) {
|
||||
s3m_file_length = pattern_offset;
|
||||
}
|
||||
}
|
||||
s3m_file = read_more( s3m_file, s3m_file_length, data_input );
|
||||
return s3m_file;
|
||||
}
|
||||
|
||||
private static int get_num_pattern_orders( byte[] s3m_file ) {
|
||||
int num_pattern_orders;
|
||||
num_pattern_orders = unsigned_short_le( s3m_file, 32 );
|
||||
return num_pattern_orders;
|
||||
}
|
||||
|
||||
private static int get_num_instruments( byte[] s3m_file ) {
|
||||
int num_instruments;
|
||||
num_instruments = unsigned_short_le( s3m_file, 34 );
|
||||
return num_instruments;
|
||||
}
|
||||
|
||||
private static int get_num_patterns( byte[] s3m_file ) {
|
||||
int num_patterns;
|
||||
num_patterns = unsigned_short_le( s3m_file, 36 );
|
||||
return num_patterns;
|
||||
}
|
||||
|
||||
private static int get_instrument_offset( byte[] s3m_file, int instrument_idx ) {
|
||||
int instrument_offset, pointer_offset;
|
||||
pointer_offset = 96 + get_num_pattern_orders( s3m_file );
|
||||
instrument_offset = unsigned_short_le( s3m_file, pointer_offset + instrument_idx * 2 ) << 4;
|
||||
return instrument_offset;
|
||||
}
|
||||
|
||||
private static int get_sample_data_offset( byte[] s3m_file, int instrument_offset ) {
|
||||
int sample_data_offset;
|
||||
sample_data_offset = 0;
|
||||
if( s3m_file[ instrument_offset ] == 1 ) {
|
||||
sample_data_offset = ( s3m_file[ instrument_offset + 13 ] & 0xFF ) << 20;
|
||||
sample_data_offset |= unsigned_short_le( s3m_file, instrument_offset + 14 ) << 4;
|
||||
}
|
||||
return sample_data_offset;
|
||||
}
|
||||
|
||||
private static int get_sample_data_length( byte[] s3m_file, int instrument_offset ) {
|
||||
int sample_data_length;
|
||||
boolean sixteen_bit;
|
||||
sample_data_length = 0;
|
||||
if( s3m_file[ instrument_offset ] == 1 ) {
|
||||
sample_data_length = unsigned_short_le( s3m_file, instrument_offset + 16 );
|
||||
sixteen_bit = ( s3m_file[ instrument_offset + 31 ] & 0x04 ) != 0;
|
||||
if( sixteen_bit ) {
|
||||
sample_data_length <<= 1;
|
||||
}
|
||||
}
|
||||
return sample_data_length;
|
||||
}
|
||||
|
||||
private static int get_pattern_offset( byte[] s3m_file, int pattern_idx ) {
|
||||
int pattern_offset, pointer_offset;
|
||||
pointer_offset = 96 + get_num_pattern_orders( s3m_file );
|
||||
pointer_offset += get_num_instruments( s3m_file ) * 2;
|
||||
pattern_offset = unsigned_short_le( s3m_file, pointer_offset + pattern_idx * 2 ) << 4;
|
||||
return pattern_offset;
|
||||
}
|
||||
|
||||
private static int get_pattern_length( byte[] s3m_file, int pattern_offset ) {
|
||||
int pattern_length;
|
||||
pattern_length = unsigned_short_le( s3m_file, pattern_offset );
|
||||
return pattern_length;
|
||||
}
|
||||
|
||||
private static byte[] read_more( byte[] old_data, int new_length, DataInput data_input ) throws IOException {
|
||||
byte[] new_data;
|
||||
new_data = old_data;
|
||||
if( new_length > old_data.length ) {
|
||||
new_data = new byte[ new_length ];
|
||||
System.arraycopy( old_data, 0, new_data, 0, old_data.length );
|
||||
try {
|
||||
data_input.readFully( new_data, old_data.length, new_data.length - old_data.length );
|
||||
} catch( EOFException e ) {
|
||||
System.out.println( "ScreamTracker3: Module has been truncated!" );
|
||||
}
|
||||
}
|
||||
return new_data;
|
||||
}
|
||||
|
||||
private static int unsigned_short_le( byte[] buffer, int offset ) {
|
||||
int value;
|
||||
value = buffer[ offset ] & 0xFF;
|
||||
value = value | ( ( buffer[ offset + 1 ] & 0xFF ) << 8 );
|
||||
return value;
|
||||
}
|
||||
|
||||
private static String ascii_text( byte[] buffer, int offset, int length ) {
|
||||
int idx, chr;
|
||||
byte[] string_buffer;
|
||||
String string;
|
||||
string_buffer = new byte[ length ];
|
||||
for( idx = 0; idx < length; idx++ ) {
|
||||
chr = buffer[ offset + idx ];
|
||||
if( chr < 32 ) {
|
||||
chr = 32;
|
||||
}
|
||||
string_buffer[ idx ] = ( byte ) chr;
|
||||
}
|
||||
try {
|
||||
string = new String( string_buffer, 0, length, "ISO-8859-1" );
|
||||
} catch( UnsupportedEncodingException e ) {
|
||||
string = "";
|
||||
}
|
||||
return string;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,109 +1,109 @@
|
|||
package net.minecraft.src.forge;
|
||||
|
||||
import net.minecraft.src.Entity;
|
||||
import net.minecraft.src.SoundManager;
|
||||
import net.minecraft.src.SoundPoolEntry;
|
||||
|
||||
public interface ISoundHandler
|
||||
{
|
||||
/**
|
||||
* This event is raised by the SoundManager when it does its first setup of the
|
||||
* SoundSystemConfig's codecs, use this function to add your own codecs.
|
||||
* @param soundManager The SoundManager instance
|
||||
*/
|
||||
void onSetupAudio(SoundManager soundManager);
|
||||
|
||||
/**
|
||||
* Raised by the SoundManager.loadSoundSettings, this would be a good place for
|
||||
* adding your custom sounds to the SoundPool.
|
||||
*
|
||||
* @param soundManager The SoundManager instance
|
||||
*/
|
||||
void onLoadSoundSettings(SoundManager soundManager);
|
||||
|
||||
/**
|
||||
* Raised when the SoundManager tries to play a Background Music file,
|
||||
* If you return null from this function it will prevent the sound from being played,
|
||||
* you can return a different entry if you want to change the sound being played.
|
||||
*
|
||||
* If you do not want to change anything, just return the passed in entry.
|
||||
*
|
||||
* @param soundManager The SoundManager instance
|
||||
* @param entry The current entry that will be played
|
||||
* @return The new sound entry to play, or the current one passed in.
|
||||
*/
|
||||
SoundPoolEntry onPlayBackgroundMusic(SoundManager soundManager, SoundPoolEntry entry);
|
||||
|
||||
/**
|
||||
* Raised when the SoundManager tries to play a 'Streaming' file,
|
||||
* in vanilla it is only the Jukebox that uses this function.
|
||||
*
|
||||
* If you return null from this function it will prevent the sound from being played,
|
||||
* you can return a different entry if you want to change the sound being played.
|
||||
*
|
||||
* If you do not want to change anything, just return the passed in entry.
|
||||
*
|
||||
* @param soundManager The SoundManager instance
|
||||
* @param entry The current entry that will be played
|
||||
* @param soundName The name of the request sound
|
||||
* @param x The X position where the sound will be played
|
||||
* @param y The Y position where the sound will be played
|
||||
* @param z The Z position where the sound will be played
|
||||
* @return The new sound entry to play, or the current one passed in.
|
||||
*/
|
||||
SoundPoolEntry onPlayStreaming(SoundManager soundManager, SoundPoolEntry entry, String soundName, float x, float y, float z);
|
||||
|
||||
/***
|
||||
* Raised when the SoundManager tries to play a normal sound,
|
||||
* dogs barking, footsteps, etc. THe majority of all sounds during normal game play.
|
||||
*
|
||||
* If you return null from this function it will prevent the sound from being played,
|
||||
* you can return a different entry if you want to change the sound being played.
|
||||
*
|
||||
* If you do not want to change anything, just return the passed in entry.
|
||||
*
|
||||
* @param soundManager The SoundManager instance
|
||||
* @param entry The current entry that will be played
|
||||
* @param soundName The name of the request sound
|
||||
* @param x The X position where the sound will be played
|
||||
* @param y The Y position where the sound will be played
|
||||
* @param z The Z position where the sound will be played
|
||||
* @param volume The sound's volume, between 0.0 and 1.0
|
||||
* @param pitch The sound's pitch
|
||||
* @return The new sound entry to play, or the current one passed in.
|
||||
*/
|
||||
SoundPoolEntry onPlaySound(SoundManager soundManager, SoundPoolEntry entry, String soundName, float x, float y, float z, float volume, float pitch);
|
||||
|
||||
/**
|
||||
* Raised when the SoundManager tries to play a effect sound,
|
||||
* currently the only known sounds are 'random.click' when a GUI button is clicked,
|
||||
* or 'portal.trigger' and 'portal.travel' when the player is near/inside a portal.
|
||||
*
|
||||
* If you return null from this function it will prevent the sound from being played,
|
||||
* you can return a different entry if you want to change the sound being played.
|
||||
*
|
||||
* If you do not want to change anything, just return the passed in entry.
|
||||
*
|
||||
* @param soundManager The SoundManager instance
|
||||
* @param entry The current entry that will be played
|
||||
* @param soundName The name of the request sound
|
||||
* @param volume The sound's volume, between 0.0 and 1.0
|
||||
* @param pitch The sound's pitch
|
||||
* @return The new sound entry to play, or the current one passed in.
|
||||
*/
|
||||
SoundPoolEntry onPlaySoundEffect(SoundManager soundManager, SoundPoolEntry entry, String soundName, float volume, float pitch);
|
||||
|
||||
/**
|
||||
* Raised when an entity attempts to play a sound via World's playSoundAtEntity
|
||||
* function. This is so that additional data about the state of the entity can
|
||||
* be obtained efficiently without using AABBs. An important thing to note:
|
||||
* This hook will be called even if the sound is off.
|
||||
*
|
||||
* @param entity The entity that the sound should be played at. Always the calling Entity or the Player.
|
||||
* @param soundName The name of the requested sound.
|
||||
* @param volume The sound's volume, between 0.0 and 1.0.
|
||||
* @param pitch The sound's pitch
|
||||
* @return The sound to play, null to cancel the event.
|
||||
*/
|
||||
String onPlaySoundAtEntity(Entity entity, String soundName, float volume, float pitch);
|
||||
}
|
||||
package net.minecraft.src.forge;
|
||||
|
||||
import net.minecraft.src.Entity;
|
||||
import net.minecraft.src.SoundManager;
|
||||
import net.minecraft.src.SoundPoolEntry;
|
||||
|
||||
public interface ISoundHandler
|
||||
{
|
||||
/**
|
||||
* This event is raised by the SoundManager when it does its first setup of the
|
||||
* SoundSystemConfig's codecs, use this function to add your own codecs.
|
||||
* @param soundManager The SoundManager instance
|
||||
*/
|
||||
void onSetupAudio(SoundManager soundManager);
|
||||
|
||||
/**
|
||||
* Raised by the SoundManager.loadSoundSettings, this would be a good place for
|
||||
* adding your custom sounds to the SoundPool.
|
||||
*
|
||||
* @param soundManager The SoundManager instance
|
||||
*/
|
||||
void onLoadSoundSettings(SoundManager soundManager);
|
||||
|
||||
/**
|
||||
* Raised when the SoundManager tries to play a Background Music file,
|
||||
* If you return null from this function it will prevent the sound from being played,
|
||||
* you can return a different entry if you want to change the sound being played.
|
||||
*
|
||||
* If you do not want to change anything, just return the passed in entry.
|
||||
*
|
||||
* @param soundManager The SoundManager instance
|
||||
* @param entry The current entry that will be played
|
||||
* @return The new sound entry to play, or the current one passed in.
|
||||
*/
|
||||
SoundPoolEntry onPlayBackgroundMusic(SoundManager soundManager, SoundPoolEntry entry);
|
||||
|
||||
/**
|
||||
* Raised when the SoundManager tries to play a 'Streaming' file,
|
||||
* in vanilla it is only the Jukebox that uses this function.
|
||||
*
|
||||
* If you return null from this function it will prevent the sound from being played,
|
||||
* you can return a different entry if you want to change the sound being played.
|
||||
*
|
||||
* If you do not want to change anything, just return the passed in entry.
|
||||
*
|
||||
* @param soundManager The SoundManager instance
|
||||
* @param entry The current entry that will be played
|
||||
* @param soundName The name of the request sound
|
||||
* @param x The X position where the sound will be played
|
||||
* @param y The Y position where the sound will be played
|
||||
* @param z The Z position where the sound will be played
|
||||
* @return The new sound entry to play, or the current one passed in.
|
||||
*/
|
||||
SoundPoolEntry onPlayStreaming(SoundManager soundManager, SoundPoolEntry entry, String soundName, float x, float y, float z);
|
||||
|
||||
/***
|
||||
* Raised when the SoundManager tries to play a normal sound,
|
||||
* dogs barking, footsteps, etc. THe majority of all sounds during normal game play.
|
||||
*
|
||||
* If you return null from this function it will prevent the sound from being played,
|
||||
* you can return a different entry if you want to change the sound being played.
|
||||
*
|
||||
* If you do not want to change anything, just return the passed in entry.
|
||||
*
|
||||
* @param soundManager The SoundManager instance
|
||||
* @param entry The current entry that will be played
|
||||
* @param soundName The name of the request sound
|
||||
* @param x The X position where the sound will be played
|
||||
* @param y The Y position where the sound will be played
|
||||
* @param z The Z position where the sound will be played
|
||||
* @param volume The sound's volume, between 0.0 and 1.0
|
||||
* @param pitch The sound's pitch
|
||||
* @return The new sound entry to play, or the current one passed in.
|
||||
*/
|
||||
SoundPoolEntry onPlaySound(SoundManager soundManager, SoundPoolEntry entry, String soundName, float x, float y, float z, float volume, float pitch);
|
||||
|
||||
/**
|
||||
* Raised when the SoundManager tries to play a effect sound,
|
||||
* currently the only known sounds are 'random.click' when a GUI button is clicked,
|
||||
* or 'portal.trigger' and 'portal.travel' when the player is near/inside a portal.
|
||||
*
|
||||
* If you return null from this function it will prevent the sound from being played,
|
||||
* you can return a different entry if you want to change the sound being played.
|
||||
*
|
||||
* If you do not want to change anything, just return the passed in entry.
|
||||
*
|
||||
* @param soundManager The SoundManager instance
|
||||
* @param entry The current entry that will be played
|
||||
* @param soundName The name of the request sound
|
||||
* @param volume The sound's volume, between 0.0 and 1.0
|
||||
* @param pitch The sound's pitch
|
||||
* @return The new sound entry to play, or the current one passed in.
|
||||
*/
|
||||
SoundPoolEntry onPlaySoundEffect(SoundManager soundManager, SoundPoolEntry entry, String soundName, float volume, float pitch);
|
||||
|
||||
/**
|
||||
* Raised when an entity attempts to play a sound via World's playSoundAtEntity
|
||||
* function. This is so that additional data about the state of the entity can
|
||||
* be obtained efficiently without using AABBs. An important thing to note:
|
||||
* This hook will be called even if the sound is off.
|
||||
*
|
||||
* @param entity The entity that the sound should be played at. Always the calling Entity or the Player.
|
||||
* @param soundName The name of the requested sound.
|
||||
* @param volume The sound's volume, between 0.0 and 1.0.
|
||||
* @param pitch The sound's pitch
|
||||
* @return The sound to play, null to cancel the event.
|
||||
*/
|
||||
String onPlaySoundAtEntity(Entity entity, String soundName, float volume, float pitch);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package net.minecraft.src.forge;
|
||||
|
||||
public interface ITextureLoadHandler
|
||||
{
|
||||
public void onTextureLoad(String textureName, int textureID);
|
||||
}
|
||||
package net.minecraft.src.forge;
|
||||
|
||||
public interface ITextureLoadHandler
|
||||
{
|
||||
public void onTextureLoad(String textureName, int textureID);
|
||||
}
|
||||
|
|
|
@ -1,268 +1,268 @@
|
|||
package net.minecraft.src.forge;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import paulscode.sound.SoundSystemConfig;
|
||||
import paulscode.sound.codecs.CodecIBXM;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.src.*;
|
||||
|
||||
public class ModCompatibilityClient
|
||||
{
|
||||
/**
|
||||
* Trys to get the class for the specified name, will also try the
|
||||
* net.minecraft.src package in case we are in MCP
|
||||
* Returns null if not found.
|
||||
*
|
||||
* @param name The class name
|
||||
* @return The Class, or null if not found
|
||||
*/
|
||||
private static Class getClass(String name)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Class.forName(name);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Class.forName("net.minecraft.src." + name);
|
||||
}
|
||||
catch (Exception e2)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* Risugami's AudioMod Compatibility
|
||||
* http://www.minecraftforum.net/topic/75440-
|
||||
*
|
||||
* AudioMod adds a few extra codecs, loads audio from /resources/mods/*,
|
||||
* introduces the concept of 'cave' sounds, which are determined by if
|
||||
* the player is underneath a solid block.
|
||||
*
|
||||
* It also lowers the interval between background music songs to 6000
|
||||
*/
|
||||
public static SoundPool audioModSoundPoolCave;
|
||||
|
||||
/**
|
||||
* Populates the sound pools with with sounds from the /resources/mods folder
|
||||
* And sets the interval between background music to 6000
|
||||
*
|
||||
* @param mngr The SoundManager instance
|
||||
*/
|
||||
public static void audioModLoad(SoundManager mngr)
|
||||
{
|
||||
audioModSoundPoolCave = new SoundPool();
|
||||
audioModLoadModAudio("resources/mod/sound", mngr.getSoundsPool());
|
||||
audioModLoadModAudio("resources/mod/streaming", mngr.getStreamingPool());
|
||||
audioModLoadModAudio("resources/mod/music", mngr.getMusicPool());
|
||||
audioModLoadModAudio("resources/mod/cavemusic", audioModSoundPoolCave);
|
||||
|
||||
if (mngr.MUSIC_INTERVAL == 12000)
|
||||
{
|
||||
mngr.MUSIC_INTERVAL = 6000;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks the given path in the Minecraft app directory and adds audio to the SoundPool
|
||||
* @param path The path to walk
|
||||
* @param pool The pool to add sound to
|
||||
*/
|
||||
private static void audioModLoadModAudio(String path, SoundPool pool)
|
||||
{
|
||||
File folder = new File(Minecraft.getMinecraftDir(), path);
|
||||
|
||||
try
|
||||
{
|
||||
audioModWalkFolder(folder, folder, pool);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
ModLoader.getLogger().fine("Loading Mod audio failed for folder: " + path);
|
||||
ModLoader.getLogger().fine(ex.toString());
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks the folder path recursively and calls pool.addSound on any file it finds.
|
||||
*
|
||||
* @param base The base path for the folder, determines the name when calling addSound
|
||||
* @param folder The current folder
|
||||
* @param pool The SoundPool to add the sound to
|
||||
* @throws IOException
|
||||
*/
|
||||
private static void audioModWalkFolder(File base, File folder, SoundPool pool) throws IOException
|
||||
{
|
||||
if (folder.exists() || folder.mkdirs())
|
||||
{
|
||||
for (File file : folder.listFiles())
|
||||
{
|
||||
if (!file.getName().startsWith("."))
|
||||
{
|
||||
if (file.isDirectory())
|
||||
{
|
||||
audioModWalkFolder(base, file, pool);
|
||||
}
|
||||
else if (file.isFile())
|
||||
{
|
||||
String subpath = file.getPath().substring(base.getPath().length() + 1).replace('\\', '/');
|
||||
pool.addSound(subpath, file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the IBXM codec and associates it with .xm, .s3m, and .mod
|
||||
*/
|
||||
public static void audioModAddCodecs()
|
||||
{
|
||||
SoundSystemConfig.setCodec("xm", CodecIBXM.class);
|
||||
SoundSystemConfig.setCodec("s3m", CodecIBXM.class);
|
||||
SoundSystemConfig.setCodec("mod", CodecIBXM.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the current player is underground, it picks a random song from the cave sound pool,
|
||||
* if they are not it returns the passed in entry.
|
||||
*
|
||||
* @param soundManager The SoundManager instance
|
||||
* @param current The currently selected entry
|
||||
* @return A soundPool entry to be played as the background music
|
||||
*/
|
||||
public static SoundPoolEntry audioModPickBackgroundMusic(SoundManager soundManager, SoundPoolEntry current)
|
||||
{
|
||||
Minecraft mc = ModLoader.getMinecraftInstance();
|
||||
if (mc != null && mc.theWorld != null && audioModSoundPoolCave != null)
|
||||
{
|
||||
Entity ent = mc.renderViewEntity;
|
||||
int x = MathHelper.func_40346_b(ent.posX);
|
||||
int y = MathHelper.func_40346_b(ent.posY);
|
||||
int z = MathHelper.func_40346_b(ent.posZ);
|
||||
return (mc.theWorld.canBlockSeeTheSky(x, y, z) ? current : audioModSoundPoolCave.getRandomSound());
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
/***********************************************************************************************************
|
||||
* SDK's ModLoaderMP
|
||||
* http://www.minecraftforum.net/topic/86765-
|
||||
*
|
||||
* ModLoaderMP was supposed to be a reliable server side version of ModLoader, however it has
|
||||
* gotten the reputation of being really slow to update. Never having bugfixes, breaking compatibility
|
||||
* with the client side ModLoader.
|
||||
*
|
||||
* So we have replaced it with our own system called FML (Forge ModLoader)
|
||||
* it is a stand alone mod, that Forge relies on, and that is open source/community driven.
|
||||
* https://github.com/cpw/FML
|
||||
*
|
||||
* However, for compatibilities sake, we provide the ModLoaderMP's hooks so that the end user
|
||||
* does not need to make a choice between the two on the client side.
|
||||
**/
|
||||
private static int isMLMPInstalled = -1;
|
||||
|
||||
/**
|
||||
* Determine if ModLoaderMP is installed by checking for the existence of the BaseModMp class.
|
||||
* @return True if BaseModMp was installed (indicating the existance of MLMP)
|
||||
*/
|
||||
public static boolean isMLMPInstalled()
|
||||
{
|
||||
if (isMLMPInstalled == -1)
|
||||
{
|
||||
isMLMPInstalled = (getClass("ModLoaderMp") != null ? 1 : 0);
|
||||
}
|
||||
return isMLMPInstalled == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to spawn a vehicle using ModLoaderMP's vehicle spawn registry, if MLMP is not installed
|
||||
* it returns the passed in currentEntity
|
||||
*
|
||||
* @param type The Type ID of the vehicle
|
||||
* @param world The current world
|
||||
* @param x The spawn X position
|
||||
* @param y The spawn Y position
|
||||
* @param z The spawn Z position
|
||||
* @param thrower The entity that spawned the vehicle {possibly null}
|
||||
* @param currentEntity The current value to return if MLMP is not installed
|
||||
* @return The new spawned entity
|
||||
* @throws Exception
|
||||
*/
|
||||
public static Object mlmpVehicleSpawn(int type, World world, double x, double y, double z, Entity thrower, Object currentEntity) throws Exception
|
||||
{
|
||||
Class mlmp = getClass("ModLoaderMp");
|
||||
if (!isMLMPInstalled() || mlmp == null)
|
||||
{
|
||||
return currentEntity;
|
||||
}
|
||||
|
||||
Object entry = mlmp.getDeclaredMethod("handleNetClientHandlerEntities", int.class).invoke(null, type);
|
||||
if (entry == null)
|
||||
{
|
||||
return currentEntity;
|
||||
}
|
||||
|
||||
Class entityClass = (Class)entry.getClass().getDeclaredField("entityClass").get(entry);
|
||||
Object ret = (Entity)entityClass.getConstructor(World.class, Double.TYPE, Double.TYPE, Double.TYPE).newInstance(world, x, y, z);
|
||||
|
||||
if (entry.getClass().getDeclaredField("entityHasOwner").getBoolean(entry))
|
||||
{
|
||||
Field owner = entityClass.getField("owner");
|
||||
|
||||
if (!Entity.class.isAssignableFrom(owner.getType()))
|
||||
{
|
||||
throw new Exception(String.format("Entity\'s owner field must be of type Entity, but it is of type %s.", owner.getType()));
|
||||
}
|
||||
|
||||
if (thrower == null)
|
||||
{
|
||||
System.out.println("Received spawn packet for entity with owner, but owner was not found.");
|
||||
ModLoader.getLogger().fine("Received spawn packet for entity with owner, but owner was not found.");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!owner.getType().isAssignableFrom(thrower.getClass()))
|
||||
{
|
||||
throw new Exception(String.format("Tried to assign an entity of type %s to entity owner, which is of type %s.", thrower.getClass(), owner.getType()));
|
||||
}
|
||||
|
||||
owner.set(ret, thrower);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to invoke ModLoaderMp.handleGUI if ModLoaderMP is installed.
|
||||
* If not, it does nothing
|
||||
*
|
||||
* @param pkt The open window packet
|
||||
*/
|
||||
public static void mlmpOpenWindow(Packet100OpenWindow pkt)
|
||||
{
|
||||
Class mlmp = getClass("ModLoaderMp");
|
||||
if (!isMLMPInstalled() || mlmp == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
mlmp.getDeclaredMethod("handleGUI", Packet100OpenWindow.class).invoke(null, pkt);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
package net.minecraft.src.forge;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import paulscode.sound.SoundSystemConfig;
|
||||
import paulscode.sound.codecs.CodecIBXM;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.src.*;
|
||||
|
||||
public class ModCompatibilityClient
|
||||
{
|
||||
/**
|
||||
* Trys to get the class for the specified name, will also try the
|
||||
* net.minecraft.src package in case we are in MCP
|
||||
* Returns null if not found.
|
||||
*
|
||||
* @param name The class name
|
||||
* @return The Class, or null if not found
|
||||
*/
|
||||
private static Class getClass(String name)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Class.forName(name);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Class.forName("net.minecraft.src." + name);
|
||||
}
|
||||
catch (Exception e2)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* Risugami's AudioMod Compatibility
|
||||
* http://www.minecraftforum.net/topic/75440-
|
||||
*
|
||||
* AudioMod adds a few extra codecs, loads audio from /resources/mods/*,
|
||||
* introduces the concept of 'cave' sounds, which are determined by if
|
||||
* the player is underneath a solid block.
|
||||
*
|
||||
* It also lowers the interval between background music songs to 6000
|
||||
*/
|
||||
public static SoundPool audioModSoundPoolCave;
|
||||
|
||||
/**
|
||||
* Populates the sound pools with with sounds from the /resources/mods folder
|
||||
* And sets the interval between background music to 6000
|
||||
*
|
||||
* @param mngr The SoundManager instance
|
||||
*/
|
||||
public static void audioModLoad(SoundManager mngr)
|
||||
{
|
||||
audioModSoundPoolCave = new SoundPool();
|
||||
audioModLoadModAudio("resources/mod/sound", mngr.getSoundsPool());
|
||||
audioModLoadModAudio("resources/mod/streaming", mngr.getStreamingPool());
|
||||
audioModLoadModAudio("resources/mod/music", mngr.getMusicPool());
|
||||
audioModLoadModAudio("resources/mod/cavemusic", audioModSoundPoolCave);
|
||||
|
||||
if (mngr.MUSIC_INTERVAL == 12000)
|
||||
{
|
||||
mngr.MUSIC_INTERVAL = 6000;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks the given path in the Minecraft app directory and adds audio to the SoundPool
|
||||
* @param path The path to walk
|
||||
* @param pool The pool to add sound to
|
||||
*/
|
||||
private static void audioModLoadModAudio(String path, SoundPool pool)
|
||||
{
|
||||
File folder = new File(Minecraft.getMinecraftDir(), path);
|
||||
|
||||
try
|
||||
{
|
||||
audioModWalkFolder(folder, folder, pool);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
ModLoader.getLogger().fine("Loading Mod audio failed for folder: " + path);
|
||||
ModLoader.getLogger().fine(ex.toString());
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks the folder path recursively and calls pool.addSound on any file it finds.
|
||||
*
|
||||
* @param base The base path for the folder, determines the name when calling addSound
|
||||
* @param folder The current folder
|
||||
* @param pool The SoundPool to add the sound to
|
||||
* @throws IOException
|
||||
*/
|
||||
private static void audioModWalkFolder(File base, File folder, SoundPool pool) throws IOException
|
||||
{
|
||||
if (folder.exists() || folder.mkdirs())
|
||||
{
|
||||
for (File file : folder.listFiles())
|
||||
{
|
||||
if (!file.getName().startsWith("."))
|
||||
{
|
||||
if (file.isDirectory())
|
||||
{
|
||||
audioModWalkFolder(base, file, pool);
|
||||
}
|
||||
else if (file.isFile())
|
||||
{
|
||||
String subpath = file.getPath().substring(base.getPath().length() + 1).replace('\\', '/');
|
||||
pool.addSound(subpath, file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the IBXM codec and associates it with .xm, .s3m, and .mod
|
||||
*/
|
||||
public static void audioModAddCodecs()
|
||||
{
|
||||
SoundSystemConfig.setCodec("xm", CodecIBXM.class);
|
||||
SoundSystemConfig.setCodec("s3m", CodecIBXM.class);
|
||||
SoundSystemConfig.setCodec("mod", CodecIBXM.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the current player is underground, it picks a random song from the cave sound pool,
|
||||
* if they are not it returns the passed in entry.
|
||||
*
|
||||
* @param soundManager The SoundManager instance
|
||||
* @param current The currently selected entry
|
||||
* @return A soundPool entry to be played as the background music
|
||||
*/
|
||||
public static SoundPoolEntry audioModPickBackgroundMusic(SoundManager soundManager, SoundPoolEntry current)
|
||||
{
|
||||
Minecraft mc = ModLoader.getMinecraftInstance();
|
||||
if (mc != null && mc.theWorld != null && audioModSoundPoolCave != null)
|
||||
{
|
||||
Entity ent = mc.renderViewEntity;
|
||||
int x = MathHelper.func_40346_b(ent.posX);
|
||||
int y = MathHelper.func_40346_b(ent.posY);
|
||||
int z = MathHelper.func_40346_b(ent.posZ);
|
||||
return (mc.theWorld.canBlockSeeTheSky(x, y, z) ? current : audioModSoundPoolCave.getRandomSound());
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
/***********************************************************************************************************
|
||||
* SDK's ModLoaderMP
|
||||
* http://www.minecraftforum.net/topic/86765-
|
||||
*
|
||||
* ModLoaderMP was supposed to be a reliable server side version of ModLoader, however it has
|
||||
* gotten the reputation of being really slow to update. Never having bugfixes, breaking compatibility
|
||||
* with the client side ModLoader.
|
||||
*
|
||||
* So we have replaced it with our own system called FML (Forge ModLoader)
|
||||
* it is a stand alone mod, that Forge relies on, and that is open source/community driven.
|
||||
* https://github.com/cpw/FML
|
||||
*
|
||||
* However, for compatibilities sake, we provide the ModLoaderMP's hooks so that the end user
|
||||
* does not need to make a choice between the two on the client side.
|
||||
**/
|
||||
private static int isMLMPInstalled = -1;
|
||||
|
||||
/**
|
||||
* Determine if ModLoaderMP is installed by checking for the existence of the BaseModMp class.
|
||||
* @return True if BaseModMp was installed (indicating the existance of MLMP)
|
||||
*/
|
||||
public static boolean isMLMPInstalled()
|
||||
{
|
||||
if (isMLMPInstalled == -1)
|
||||
{
|
||||
isMLMPInstalled = (getClass("ModLoaderMp") != null ? 1 : 0);
|
||||
}
|
||||
return isMLMPInstalled == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to spawn a vehicle using ModLoaderMP's vehicle spawn registry, if MLMP is not installed
|
||||
* it returns the passed in currentEntity
|
||||
*
|
||||
* @param type The Type ID of the vehicle
|
||||
* @param world The current world
|
||||
* @param x The spawn X position
|
||||
* @param y The spawn Y position
|
||||
* @param z The spawn Z position
|
||||
* @param thrower The entity that spawned the vehicle {possibly null}
|
||||
* @param currentEntity The current value to return if MLMP is not installed
|
||||
* @return The new spawned entity
|
||||
* @throws Exception
|
||||
*/
|
||||
public static Object mlmpVehicleSpawn(int type, World world, double x, double y, double z, Entity thrower, Object currentEntity) throws Exception
|
||||
{
|
||||
Class mlmp = getClass("ModLoaderMp");
|
||||
if (!isMLMPInstalled() || mlmp == null)
|
||||
{
|
||||
return currentEntity;
|
||||
}
|
||||
|
||||
Object entry = mlmp.getDeclaredMethod("handleNetClientHandlerEntities", int.class).invoke(null, type);
|
||||
if (entry == null)
|
||||
{
|
||||
return currentEntity;
|
||||
}
|
||||
|
||||
Class entityClass = (Class)entry.getClass().getDeclaredField("entityClass").get(entry);
|
||||
Object ret = (Entity)entityClass.getConstructor(World.class, Double.TYPE, Double.TYPE, Double.TYPE).newInstance(world, x, y, z);
|
||||
|
||||
if (entry.getClass().getDeclaredField("entityHasOwner").getBoolean(entry))
|
||||
{
|
||||
Field owner = entityClass.getField("owner");
|
||||
|
||||
if (!Entity.class.isAssignableFrom(owner.getType()))
|
||||
{
|
||||
throw new Exception(String.format("Entity\'s owner field must be of type Entity, but it is of type %s.", owner.getType()));
|
||||
}
|
||||
|
||||
if (thrower == null)
|
||||
{
|
||||
System.out.println("Received spawn packet for entity with owner, but owner was not found.");
|
||||
ModLoader.getLogger().fine("Received spawn packet for entity with owner, but owner was not found.");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!owner.getType().isAssignableFrom(thrower.getClass()))
|
||||
{
|
||||
throw new Exception(String.format("Tried to assign an entity of type %s to entity owner, which is of type %s.", thrower.getClass(), owner.getType()));
|
||||
}
|
||||
|
||||
owner.set(ret, thrower);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to invoke ModLoaderMp.handleGUI if ModLoaderMP is installed.
|
||||
* If not, it does nothing
|
||||
*
|
||||
* @param pkt The open window packet
|
||||
*/
|
||||
public static void mlmpOpenWindow(Packet100OpenWindow pkt)
|
||||
{
|
||||
Class mlmp = getClass("ModLoaderMp");
|
||||
if (!isMLMPInstalled() || mlmp == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
mlmp.getDeclaredMethod("handleGUI", Packet100OpenWindow.class).invoke(null, pkt);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,49 +1,49 @@
|
|||
package net.minecraft.src.forge.adaptors;
|
||||
|
||||
import net.minecraft.src.Entity;
|
||||
import net.minecraft.src.SoundManager;
|
||||
import net.minecraft.src.SoundPoolEntry;
|
||||
import net.minecraft.src.forge.ISoundHandler;
|
||||
|
||||
/**
|
||||
* Adaptor class for convince sake when implementing ISoundHandler, as most
|
||||
* mods will only actually care about onSetupAudio/onLoadSoundSettings.
|
||||
*/
|
||||
public class SoundHandlerAdaptor implements ISoundHandler
|
||||
{
|
||||
@Override
|
||||
public void onSetupAudio(SoundManager soundManager){}
|
||||
|
||||
@Override
|
||||
public void onLoadSoundSettings(SoundManager soundManager){}
|
||||
|
||||
@Override
|
||||
public SoundPoolEntry onPlayBackgroundMusic(SoundManager soundManager, SoundPoolEntry entry)
|
||||
{
|
||||
return entry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoundPoolEntry onPlayStreaming(SoundManager soundManager, SoundPoolEntry entry, String soundName, float x, float y, float z)
|
||||
{
|
||||
return entry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoundPoolEntry onPlaySound(SoundManager soundManager, SoundPoolEntry entry, String soundName, float x, float y, float z, float volume, float pitch)
|
||||
{
|
||||
return entry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoundPoolEntry onPlaySoundEffect(SoundManager soundManager, SoundPoolEntry entry, String soundName, float volume, float pitch)
|
||||
{
|
||||
return entry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String onPlaySoundAtEntity(Entity entity, String soundName, float volume, float pitch)
|
||||
{
|
||||
return soundName;
|
||||
}
|
||||
}
|
||||
package net.minecraft.src.forge.adaptors;
|
||||
|
||||
import net.minecraft.src.Entity;
|
||||
import net.minecraft.src.SoundManager;
|
||||
import net.minecraft.src.SoundPoolEntry;
|
||||
import net.minecraft.src.forge.ISoundHandler;
|
||||
|
||||
/**
|
||||
* Adaptor class for convince sake when implementing ISoundHandler, as most
|
||||
* mods will only actually care about onSetupAudio/onLoadSoundSettings.
|
||||
*/
|
||||
public class SoundHandlerAdaptor implements ISoundHandler
|
||||
{
|
||||
@Override
|
||||
public void onSetupAudio(SoundManager soundManager){}
|
||||
|
||||
@Override
|
||||
public void onLoadSoundSettings(SoundManager soundManager){}
|
||||
|
||||
@Override
|
||||
public SoundPoolEntry onPlayBackgroundMusic(SoundManager soundManager, SoundPoolEntry entry)
|
||||
{
|
||||
return entry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoundPoolEntry onPlayStreaming(SoundManager soundManager, SoundPoolEntry entry, String soundName, float x, float y, float z)
|
||||
{
|
||||
return entry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoundPoolEntry onPlaySound(SoundManager soundManager, SoundPoolEntry entry, String soundName, float x, float y, float z, float volume, float pitch)
|
||||
{
|
||||
return entry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SoundPoolEntry onPlaySoundEffect(SoundManager soundManager, SoundPoolEntry entry, String soundName, float volume, float pitch)
|
||||
{
|
||||
return entry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String onPlaySoundAtEntity(Entity entity, String soundName, float volume, float pitch)
|
||||
{
|
||||
return soundName;
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,20 +1,20 @@
|
|||
[
|
||||
{
|
||||
"modid" : "mod_MinecraftForge",
|
||||
"name" : "Minecraft Forge",
|
||||
"version" : "{version}",
|
||||
"url" : "http://MinecraftForge.net",
|
||||
"credits" : "Lots of people have contributed to MinecraftForge",
|
||||
"authors": [
|
||||
"LexManos",
|
||||
"Eloraam",
|
||||
"Spacetoad"
|
||||
],
|
||||
"description": "Minecraft Forge is a common open source API allowing a broad range of mods to work cooperatively together.\nIt allows many mods to be created without them editing the main Minecraft code.",
|
||||
"logoFile" : "/forge_logo.png",
|
||||
"updateUrl" : "http://minecraftforge.net/forum/index.php/topic,5.0.html",
|
||||
"parent" : "",
|
||||
"screenshots": [
|
||||
]
|
||||
}
|
||||
[
|
||||
{
|
||||
"modid" : "mod_MinecraftForge",
|
||||
"name" : "Minecraft Forge",
|
||||
"version" : "{version}",
|
||||
"url" : "http://MinecraftForge.net",
|
||||
"credits" : "Lots of people have contributed to MinecraftForge",
|
||||
"authors": [
|
||||
"LexManos",
|
||||
"Eloraam",
|
||||
"Spacetoad"
|
||||
],
|
||||
"description": "Minecraft Forge is a common open source API allowing a broad range of mods to work cooperatively together.\nIt allows many mods to be created without them editing the main Minecraft code.",
|
||||
"logoFile" : "/forge_logo.png",
|
||||
"updateUrl" : "http://minecraftforge.net/forum/index.php/topic,5.0.html",
|
||||
"parent" : "",
|
||||
"screenshots": [
|
||||
]
|
||||
}
|
||||
]
|
|
@ -1,34 +1,34 @@
|
|||
/**
|
||||
* This software is provided under the terms of the Minecraft Forge Public
|
||||
* License v1.0.
|
||||
*/
|
||||
|
||||
package net.minecraft.src.forge;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.src.Achievement;
|
||||
|
||||
public class AchievementPage
|
||||
{
|
||||
private String name;
|
||||
private LinkedList<Achievement> achievements;
|
||||
|
||||
public AchievementPage(String name, Achievement... achievements)
|
||||
{
|
||||
this.name = name;
|
||||
this.achievements = new LinkedList<Achievement>(Arrays.asList(achievements));
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public List<Achievement> getAchievements()
|
||||
{
|
||||
return achievements;
|
||||
}
|
||||
/**
|
||||
* This software is provided under the terms of the Minecraft Forge Public
|
||||
* License v1.0.
|
||||
*/
|
||||
|
||||
package net.minecraft.src.forge;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.src.Achievement;
|
||||
|
||||
public class AchievementPage
|
||||
{
|
||||
private String name;
|
||||
private LinkedList<Achievement> achievements;
|
||||
|
||||
public AchievementPage(String name, Achievement... achievements)
|
||||
{
|
||||
this.name = name;
|
||||
this.achievements = new LinkedList<Achievement>(Arrays.asList(achievements));
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public List<Achievement> getAchievements()
|
||||
{
|
||||
return achievements;
|
||||
}
|
||||
}
|
|
@ -1,76 +1,76 @@
|
|||
package net.minecraft.src.forge;
|
||||
|
||||
import net.minecraft.src.EntityPlayer;
|
||||
|
||||
public interface IChatHandler
|
||||
{
|
||||
/**
|
||||
* Called when a player sends a normal chat message to the server,
|
||||
* you can manipulate the message parameter by returning a modified
|
||||
* version from this function.
|
||||
*
|
||||
* This is only called on the server side.
|
||||
*
|
||||
* @param player The player issuing the message
|
||||
* @param message The message the player is sending
|
||||
* @return The message to be displayed, normal case is the 'message' parameter. Return null to cancel displaying this message.
|
||||
*/
|
||||
public String onServerChat(EntityPlayer player, String message);
|
||||
|
||||
/**
|
||||
* Called when a player sends a normal chat message to the server
|
||||
* that starts with a '/'.
|
||||
*
|
||||
* This is only called on the server side.
|
||||
*
|
||||
* Return true from this function to indicate that you have
|
||||
* handled the command and no further processing is necessary.
|
||||
*
|
||||
* @param player The player trying to issue the command
|
||||
* @param isOp True if the player is on the Op list
|
||||
* @param command The command trying to be issued
|
||||
* @return True if no further processing is necessary, false to continue processing.
|
||||
*/
|
||||
public boolean onChatCommand(EntityPlayer player, boolean isOp, String command);
|
||||
|
||||
/**
|
||||
* Called when either the console or a player issues a / command that is not handled elsewhere.
|
||||
*
|
||||
* This is only called on the server side.
|
||||
*
|
||||
* Return true from this function to indicate that you have
|
||||
* handled the command and no further processing is necessary.
|
||||
*
|
||||
* The listener will always be a instance of ICommandListener, but because the client does
|
||||
* not have this class it is defined as a Object to allow client compilation.
|
||||
*
|
||||
* @param listener The source of the command, will always be a instance of ICommandListener
|
||||
* @param username The username of the person issuing the command, 'CONSOLE' if it's not a player.
|
||||
* @param command The command trying to be issued
|
||||
* @return True if no further processing is necessary, false to continue processing.
|
||||
*/
|
||||
public boolean onServerCommand(Object listener, String username, String command);
|
||||
|
||||
/**
|
||||
*
|
||||
* Called when either the console or a player issues the /say command
|
||||
*
|
||||
* This is only called on the server side.
|
||||
*
|
||||
* @param listener The source of the command, will always be a instance of ICommandListener
|
||||
* @param username The username of the person issuing the command, 'CONSOLE' if it's not a player.
|
||||
* @param message The message trying to be sent, without the /say
|
||||
* @return The message to be displayed, normal case is the 'message' parameter. Return null to cancel displaying this message.
|
||||
*/
|
||||
public String onServerCommandSay(Object listener, String username, String message);
|
||||
|
||||
/**
|
||||
* Called when the client receives a Chat packet.
|
||||
*
|
||||
* This is only called on the client side
|
||||
*
|
||||
* @param message The chat message received
|
||||
* @return The message to be displayed, normal case is the 'message' parameter. Return null to cancel displaying this message.
|
||||
*/
|
||||
public String onClientChatRecv(String message);
|
||||
}
|
||||
package net.minecraft.src.forge;
|
||||
|
||||
import net.minecraft.src.EntityPlayer;
|
||||
|
||||
public interface IChatHandler
|
||||
{
|
||||
/**
|
||||
* Called when a player sends a normal chat message to the server,
|
||||
* you can manipulate the message parameter by returning a modified
|
||||
* version from this function.
|
||||
*
|
||||
* This is only called on the server side.
|
||||
*
|
||||
* @param player The player issuing the message
|
||||
* @param message The message the player is sending
|
||||
* @return The message to be displayed, normal case is the 'message' parameter. Return null to cancel displaying this message.
|
||||
*/
|
||||
public String onServerChat(EntityPlayer player, String message);
|
||||
|
||||
/**
|
||||
* Called when a player sends a normal chat message to the server
|
||||
* that starts with a '/'.
|
||||
*
|
||||
* This is only called on the server side.
|
||||
*
|
||||
* Return true from this function to indicate that you have
|
||||
* handled the command and no further processing is necessary.
|
||||
*
|
||||
* @param player The player trying to issue the command
|
||||
* @param isOp True if the player is on the Op list
|
||||
* @param command The command trying to be issued
|
||||
* @return True if no further processing is necessary, false to continue processing.
|
||||
*/
|
||||
public boolean onChatCommand(EntityPlayer player, boolean isOp, String command);
|
||||
|
||||
/**
|
||||
* Called when either the console or a player issues a / command that is not handled elsewhere.
|
||||
*
|
||||
* This is only called on the server side.
|
||||
*
|
||||
* Return true from this function to indicate that you have
|
||||
* handled the command and no further processing is necessary.
|
||||
*
|
||||
* The listener will always be a instance of ICommandListener, but because the client does
|
||||
* not have this class it is defined as a Object to allow client compilation.
|
||||
*
|
||||
* @param listener The source of the command, will always be a instance of ICommandListener
|
||||
* @param username The username of the person issuing the command, 'CONSOLE' if it's not a player.
|
||||
* @param command The command trying to be issued
|
||||
* @return True if no further processing is necessary, false to continue processing.
|
||||
*/
|
||||
public boolean onServerCommand(Object listener, String username, String command);
|
||||
|
||||
/**
|
||||
*
|
||||
* Called when either the console or a player issues the /say command
|
||||
*
|
||||
* This is only called on the server side.
|
||||
*
|
||||
* @param listener The source of the command, will always be a instance of ICommandListener
|
||||
* @param username The username of the person issuing the command, 'CONSOLE' if it's not a player.
|
||||
* @param message The message trying to be sent, without the /say
|
||||
* @return The message to be displayed, normal case is the 'message' parameter. Return null to cancel displaying this message.
|
||||
*/
|
||||
public String onServerCommandSay(Object listener, String username, String message);
|
||||
|
||||
/**
|
||||
* Called when the client receives a Chat packet.
|
||||
*
|
||||
* This is only called on the client side
|
||||
*
|
||||
* @param message The chat message received
|
||||
* @return The message to be displayed, normal case is the 'message' parameter. Return null to cancel displaying this message.
|
||||
*/
|
||||
public String onClientChatRecv(String message);
|
||||
}
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
/**
|
||||
* This software is provided under the terms of the Minecraft Forge Public
|
||||
* License v1.0.
|
||||
*/
|
||||
|
||||
package net.minecraft.src.forge;
|
||||
|
||||
import net.minecraft.src.EntityPlayer;
|
||||
import net.minecraft.src.Entity;
|
||||
|
||||
public interface IEntityInteractHandler
|
||||
{
|
||||
/**
|
||||
* This is called before a player attacks, or interacts {left or right click by default}
|
||||
* with another entity. Before any damage, or other interaction code is run.
|
||||
* In multiplayer, this is called by both the client and the server.
|
||||
*
|
||||
* @param player The player doing the interacting
|
||||
* @param entity The entity being interacted with
|
||||
* @param isAttack True if it is a attack {left click} false if it is a interact {right click}
|
||||
* @return True to continue processing, false to cancel.
|
||||
*/
|
||||
public boolean onEntityInteract(EntityPlayer player, Entity entity, boolean isAttack);
|
||||
/**
|
||||
* This software is provided under the terms of the Minecraft Forge Public
|
||||
* License v1.0.
|
||||
*/
|
||||
|
||||
package net.minecraft.src.forge;
|
||||
|
||||
import net.minecraft.src.EntityPlayer;
|
||||
import net.minecraft.src.Entity;
|
||||
|
||||
public interface IEntityInteractHandler
|
||||
{
|
||||
/**
|
||||
* This is called before a player attacks, or interacts {left or right click by default}
|
||||
* with another entity. Before any damage, or other interaction code is run.
|
||||
* In multiplayer, this is called by both the client and the server.
|
||||
*
|
||||
* @param player The player doing the interacting
|
||||
* @param entity The entity being interacted with
|
||||
* @param isAttack True if it is a attack {left click} false if it is a interact {right click}
|
||||
* @return True to continue processing, false to cancel.
|
||||
*/
|
||||
public boolean onEntityInteract(EntityPlayer player, Entity entity, boolean isAttack);
|
||||
}
|
|
@ -1,127 +1,127 @@
|
|||
/**
|
||||
* This software is provided under the terms of the Minecraft Forge Public
|
||||
* License v1.0.
|
||||
*/
|
||||
|
||||
package net.minecraft.src.forge;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import net.minecraft.src.EntityItem;
|
||||
import net.minecraft.src.EntityLiving;
|
||||
import net.minecraft.src.DamageSource;
|
||||
import net.minecraft.src.World;
|
||||
|
||||
public interface IEntityLivingHandler
|
||||
{
|
||||
/**
|
||||
* Raised when an EntityLiving is spawned into the world from natural means, meaning
|
||||
* not by command, MobSpawner, cheat, etc.. Just naturally throughout the world.
|
||||
*
|
||||
* This allows the mod to create special functionality that runs on a mob natural
|
||||
* spawn. The Vanilla minecraft mechanic of having 'Spider Jockies', the color of
|
||||
* sheep's wool, and Ocelot's spawning with babies can be canceled by returning
|
||||
* true from this function
|
||||
*
|
||||
* Returning true will indicate that you have performed your special spawning,
|
||||
* and no more handling will be done.
|
||||
*
|
||||
* @param entity The newly spawned entity
|
||||
* @param world The world the entity is in
|
||||
* @param x The Entitie's X Position
|
||||
* @param y The Entitie's Y Position
|
||||
* @param z The Entitie's Z Position
|
||||
* @return True if the event was handled and no more processing should be done, false to continue processing
|
||||
*/
|
||||
public boolean onEntityLivingSpawn(EntityLiving entity, World world, float x, float y, float z);
|
||||
|
||||
/**
|
||||
* This is called when any EntityLiving's health reaches 0.
|
||||
* You can cancel the death here, but you must raise the health or it will die again.
|
||||
* In multiplayer, this is called by both the client and the server.
|
||||
*
|
||||
* @param entity Entity about to die
|
||||
* @param killer DamageSource instance causing the death
|
||||
* @return True to continue processing, false to cancel.
|
||||
*/
|
||||
public boolean onEntityLivingDeath(EntityLiving entity, DamageSource killer);
|
||||
|
||||
/**
|
||||
* This is called immediately after an EntityLiving receives a new attack target from AI classes.
|
||||
* eg when a Zombie 'spots' a player. Handles friendly fire (setRevengeTarget) as well.
|
||||
* In multiplayer, this is called by the server only.
|
||||
*
|
||||
* @param entity Entity attacking
|
||||
* @param target Entity designated as new target
|
||||
*/
|
||||
public void onEntityLivingSetAttackTarget(EntityLiving entity, EntityLiving target);
|
||||
|
||||
/**
|
||||
* This is called when any EntityLiving takes damage from any DamageSource.
|
||||
* In multiplayer, this is called by both the client and the server.
|
||||
*
|
||||
* @param entity Entity being attacked
|
||||
* @param attack DamageSource instance of the attack
|
||||
* @param damage Unmitigated damage the attack would cause
|
||||
* @return True if the event was handled and no more processing should be done, false to continue processing
|
||||
*/
|
||||
public boolean onEntityLivingAttacked(EntityLiving entity, DamageSource attack, int damage);
|
||||
|
||||
/**
|
||||
* This is called immediately after an EntityLiving started a jump
|
||||
* Velocity will already be set and can be modified.
|
||||
*
|
||||
* @param entity Entity starting the jump
|
||||
*/
|
||||
public void onEntityLivingJump(EntityLiving entity);
|
||||
|
||||
/**
|
||||
* This is called when an EntityLiving reconnects with the ground.
|
||||
* Aborting this would stop both damage and the landing sound.
|
||||
*
|
||||
* @param entity Entity which fell
|
||||
* @param distance absolute height between the last position touching the ground and the current.
|
||||
* @return True if the event was handled and no more processing should be done, false to continue processing
|
||||
*/
|
||||
public boolean onEntityLivingFall(EntityLiving entity, float distance);
|
||||
|
||||
/**
|
||||
* This is called before EntityLiving's Base Update Tick.
|
||||
* Aborting this process will freeze both Movement and Actions.
|
||||
*
|
||||
* @param entity Entity being ticked
|
||||
* @return True if the event was handled and no more processing should be done, false to continue processing
|
||||
*/
|
||||
public boolean onEntityLivingUpdate(EntityLiving entity);
|
||||
|
||||
/**
|
||||
* This is called whenever a EntityLiving is hurt, before any armor calculations are taken into effect.
|
||||
* Before any blocking, or potions are taken into account.
|
||||
* Returning 0 from this will stop all processing.
|
||||
* For the client's entity, this is only called in Single player, or if you are the server.
|
||||
*
|
||||
* @param entity The entity being hurt
|
||||
* @param source The type of damage being dealt
|
||||
* @param damage The amount of damage being dealt
|
||||
* @return The amount of damage to let through. Returning 0 will prevent any further processing.
|
||||
*/
|
||||
public int onEntityLivingHurt(EntityLiving entity, DamageSource source, int damage);
|
||||
|
||||
/**
|
||||
* This is called after a EntityLiving die, and it spawns it's loot. The drop list should contain any item that the entity spawned at death.
|
||||
* May not work properly on all Mod entities if they do not use dropFewItems/dropRareDrop/entityDropItem
|
||||
* This will not contain the special record that creepers drop when they are killed by a Skeleton, or the apple notch drops.
|
||||
* Or the player's inventory.
|
||||
*
|
||||
* If you need to deal with the Player's inventory, do so in onEntityLivingDeath
|
||||
* In most cases, drops will be empty if the entity was a baby that hadn't reached full size yet.
|
||||
*
|
||||
* @param entity The entity that is droping the items
|
||||
* @param source The damage source that caused the entities death
|
||||
* @param drops An ArrayList containing all items to drop, AYou must make sure to not cause any concurancy exceptions with this
|
||||
* @param lootingLevel The Looting enchantment level if the attacker was a player and they had the enchantment, else 0
|
||||
* @param recentlyHit Signifying if the entity was recently hit by a player.
|
||||
* @param specialDropValue Random number used to determine if the 'special' loot should be dropped. 0 if the entity was a child
|
||||
*/
|
||||
public void onEntityLivingDrops(EntityLiving entity, DamageSource source, ArrayList<EntityItem> drops, int lootingLevel, boolean recentlyHit, int specialDropValue);
|
||||
/**
|
||||
* This software is provided under the terms of the Minecraft Forge Public
|
||||
* License v1.0.
|
||||
*/
|
||||
|
||||
package net.minecraft.src.forge;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import net.minecraft.src.EntityItem;
|
||||
import net.minecraft.src.EntityLiving;
|
||||
import net.minecraft.src.DamageSource;
|
||||
import net.minecraft.src.World;
|
||||
|
||||
public interface IEntityLivingHandler
|
||||
{
|
||||
/**
|
||||
* Raised when an EntityLiving is spawned into the world from natural means, meaning
|
||||
* not by command, MobSpawner, cheat, etc.. Just naturally throughout the world.
|
||||
*
|
||||
* This allows the mod to create special functionality that runs on a mob natural
|
||||
* spawn. The Vanilla minecraft mechanic of having 'Spider Jockies', the color of
|
||||
* sheep's wool, and Ocelot's spawning with babies can be canceled by returning
|
||||
* true from this function
|
||||
*
|
||||
* Returning true will indicate that you have performed your special spawning,
|
||||
* and no more handling will be done.
|
||||
*
|
||||
* @param entity The newly spawned entity
|
||||
* @param world The world the entity is in
|
||||
* @param x The Entitie's X Position
|
||||
* @param y The Entitie's Y Position
|
||||
* @param z The Entitie's Z Position
|
||||
* @return True if the event was handled and no more processing should be done, false to continue processing
|
||||
*/
|
||||
public boolean onEntityLivingSpawn(EntityLiving entity, World world, float x, float y, float z);
|
||||
|
||||
/**
|
||||
* This is called when any EntityLiving's health reaches 0.
|
||||
* You can cancel the death here, but you must raise the health or it will die again.
|
||||
* In multiplayer, this is called by both the client and the server.
|
||||
*
|
||||
* @param entity Entity about to die
|
||||
* @param killer DamageSource instance causing the death
|
||||
* @return True to continue processing, false to cancel.
|
||||
*/
|
||||
public boolean onEntityLivingDeath(EntityLiving entity, DamageSource killer);
|
||||
|
||||
/**
|
||||
* This is called immediately after an EntityLiving receives a new attack target from AI classes.
|
||||
* eg when a Zombie 'spots' a player. Handles friendly fire (setRevengeTarget) as well.
|
||||
* In multiplayer, this is called by the server only.
|
||||
*
|
||||
* @param entity Entity attacking
|
||||
* @param target Entity designated as new target
|
||||
*/
|
||||
public void onEntityLivingSetAttackTarget(EntityLiving entity, EntityLiving target);
|
||||
|
||||
/**
|
||||
* This is called when any EntityLiving takes damage from any DamageSource.
|
||||
* In multiplayer, this is called by both the client and the server.
|
||||
*
|
||||
* @param entity Entity being attacked
|
||||
* @param attack DamageSource instance of the attack
|
||||
* @param damage Unmitigated damage the attack would cause
|
||||
* @return True if the event was handled and no more processing should be done, false to continue processing
|
||||
*/
|
||||
public boolean onEntityLivingAttacked(EntityLiving entity, DamageSource attack, int damage);
|
||||
|
||||
/**
|
||||
* This is called immediately after an EntityLiving started a jump
|
||||
* Velocity will already be set and can be modified.
|
||||
*
|
||||
* @param entity Entity starting the jump
|
||||
*/
|
||||
public void onEntityLivingJump(EntityLiving entity);
|
||||
|
||||
/**
|
||||
* This is called when an EntityLiving reconnects with the ground.
|
||||
* Aborting this would stop both damage and the landing sound.
|
||||
*
|
||||
* @param entity Entity which fell
|
||||
* @param distance absolute height between the last position touching the ground and the current.
|
||||
* @return True if the event was handled and no more processing should be done, false to continue processing
|
||||
*/
|
||||
public boolean onEntityLivingFall(EntityLiving entity, float distance);
|
||||
|
||||
/**
|
||||
* This is called before EntityLiving's Base Update Tick.
|
||||
* Aborting this process will freeze both Movement and Actions.
|
||||
*
|
||||
* @param entity Entity being ticked
|
||||
* @return True if the event was handled and no more processing should be done, false to continue processing
|
||||
*/
|
||||
public boolean onEntityLivingUpdate(EntityLiving entity);
|
||||
|
||||
/**
|
||||
* This is called whenever a EntityLiving is hurt, before any armor calculations are taken into effect.
|
||||
* Before any blocking, or potions are taken into account.
|
||||
* Returning 0 from this will stop all processing.
|
||||
* For the client's entity, this is only called in Single player, or if you are the server.
|
||||
*
|
||||
* @param entity The entity being hurt
|
||||
* @param source The type of damage being dealt
|
||||
* @param damage The amount of damage being dealt
|
||||
* @return The amount of damage to let through. Returning 0 will prevent any further processing.
|
||||
*/
|
||||
public int onEntityLivingHurt(EntityLiving entity, DamageSource source, int damage);
|
||||
|
||||
/**
|
||||
* This is called after a EntityLiving die, and it spawns it's loot. The drop list should contain any item that the entity spawned at death.
|
||||
* May not work properly on all Mod entities if they do not use dropFewItems/dropRareDrop/entityDropItem
|
||||
* This will not contain the special record that creepers drop when they are killed by a Skeleton, or the apple notch drops.
|
||||
* Or the player's inventory.
|
||||
*
|
||||
* If you need to deal with the Player's inventory, do so in onEntityLivingDeath
|
||||
* In most cases, drops will be empty if the entity was a baby that hadn't reached full size yet.
|
||||
*
|
||||
* @param entity The entity that is droping the items
|
||||
* @param source The damage source that caused the entities death
|
||||
* @param drops An ArrayList containing all items to drop, AYou must make sure to not cause any concurancy exceptions with this
|
||||
* @param lootingLevel The Looting enchantment level if the attacker was a player and they had the enchantment, else 0
|
||||
* @param recentlyHit Signifying if the entity was recently hit by a player.
|
||||
* @param specialDropValue Random number used to determine if the 'special' loot should be dropped. 0 if the entity was a child
|
||||
*/
|
||||
public void onEntityLivingDrops(EntityLiving entity, DamageSource source, ArrayList<EntityItem> drops, int lootingLevel, boolean recentlyHit, int specialDropValue);
|
||||
}
|
|
@ -1,16 +1,16 @@
|
|||
/**
|
||||
* This software is provided under the terms of the Minecraft Forge Public
|
||||
* License v1.0.
|
||||
*/
|
||||
|
||||
package net.minecraft.src.forge;
|
||||
|
||||
import net.minecraft.src.ItemStack;
|
||||
|
||||
public interface IFuelHandler
|
||||
{
|
||||
/** Called when a furnace gains fuel to get its burn time.
|
||||
* @return fuel burn time in ticks or 0 to continue processing
|
||||
*/
|
||||
public int getItemBurnTime(ItemStack stack);
|
||||
/**
|
||||
* This software is provided under the terms of the Minecraft Forge Public
|
||||
* License v1.0.
|
||||
*/
|
||||
|
||||
package net.minecraft.src.forge;
|
||||
|
||||
import net.minecraft.src.ItemStack;
|
||||
|
||||
public interface IFuelHandler
|
||||
{
|
||||
/** Called when a furnace gains fuel to get its burn time.
|
||||
* @return fuel burn time in ticks or 0 to continue processing
|
||||
*/
|
||||
public int getItemBurnTime(ItemStack stack);
|
||||
}
|
|
@ -1,50 +1,50 @@
|
|||
package net.minecraft.src.forge;
|
||||
|
||||
import net.minecraft.src.Chunk;
|
||||
import net.minecraft.src.NBTTagCompound;
|
||||
import net.minecraft.src.World;
|
||||
|
||||
public interface ISaveEventHandler
|
||||
{
|
||||
/**
|
||||
* Called when the world is created, either newly created or loaded from a save file
|
||||
* @param world The world being loaded.
|
||||
*/
|
||||
public void onWorldLoad(World world);
|
||||
|
||||
/**
|
||||
* Called whenever the world is saving. Use this to save extra data alongside the world, eg. maps.
|
||||
* @param world The world being saved.
|
||||
*/
|
||||
public void onWorldSave(World world);
|
||||
|
||||
/**
|
||||
* Called when a chunk is created, either newly generated or loaded from a save file
|
||||
* @param world The world containing this chunk.
|
||||
* @param chunk The chunk being loaded.
|
||||
*/
|
||||
public void onChunkLoad(World world, Chunk chunk);
|
||||
|
||||
/**
|
||||
* Called when a chunk is unloaded and removed from the world
|
||||
* @param world The world containing this chunk.
|
||||
* @param chunk The chunk being loaded.
|
||||
*/
|
||||
public void onChunkUnload(World world, Chunk chunk);
|
||||
|
||||
/**
|
||||
* Use this to save extra data in with the chunk file.
|
||||
* @param world The world containing this chunk.
|
||||
* @param chunk The chunk being saved.
|
||||
* @param data The compound to save data into and be written to disk
|
||||
*/
|
||||
public void onChunkSaveData(World world, Chunk chunk, NBTTagCompound data);
|
||||
|
||||
/**
|
||||
* Use this to load extra save data from a chunk file.
|
||||
* @param world The world containing this chunk.
|
||||
* @param chunk The chunk being loaded.
|
||||
* @param data The compound to load data from
|
||||
*/
|
||||
public void onChunkLoadData(World world, Chunk chunk, NBTTagCompound data);
|
||||
package net.minecraft.src.forge;
|
||||
|
||||
import net.minecraft.src.Chunk;
|
||||
import net.minecraft.src.NBTTagCompound;
|
||||
import net.minecraft.src.World;
|
||||
|
||||
public interface ISaveEventHandler
|
||||
{
|
||||
/**
|
||||
* Called when the world is created, either newly created or loaded from a save file
|
||||
* @param world The world being loaded.
|
||||
*/
|
||||
public void onWorldLoad(World world);
|
||||
|
||||
/**
|
||||
* Called whenever the world is saving. Use this to save extra data alongside the world, eg. maps.
|
||||
* @param world The world being saved.
|
||||
*/
|
||||
public void onWorldSave(World world);
|
||||
|
||||
/**
|
||||
* Called when a chunk is created, either newly generated or loaded from a save file
|
||||
* @param world The world containing this chunk.
|
||||
* @param chunk The chunk being loaded.
|
||||
*/
|
||||
public void onChunkLoad(World world, Chunk chunk);
|
||||
|
||||
/**
|
||||
* Called when a chunk is unloaded and removed from the world
|
||||
* @param world The world containing this chunk.
|
||||
* @param chunk The chunk being loaded.
|
||||
*/
|
||||
public void onChunkUnload(World world, Chunk chunk);
|
||||
|
||||
/**
|
||||
* Use this to save extra data in with the chunk file.
|
||||
* @param world The world containing this chunk.
|
||||
* @param chunk The chunk being saved.
|
||||
* @param data The compound to save data into and be written to disk
|
||||
*/
|
||||
public void onChunkSaveData(World world, Chunk chunk, NBTTagCompound data);
|
||||
|
||||
/**
|
||||
* Use this to load extra save data from a chunk file.
|
||||
* @param world The world containing this chunk.
|
||||
* @param chunk The chunk being loaded.
|
||||
* @param data The compound to load data from
|
||||
*/
|
||||
public void onChunkLoadData(World world, Chunk chunk, NBTTagCompound data);
|
||||
}
|
|
@ -1,29 +1,29 @@
|
|||
package net.minecraft.src.forge;
|
||||
|
||||
import net.minecraft.src.EntityLiving;
|
||||
import net.minecraft.src.World;
|
||||
|
||||
@Deprecated //See IEntityLivingHandler
|
||||
public interface ISpecialMobSpawnHandler
|
||||
{
|
||||
/**
|
||||
* Raised when a Entity is spawned into the world from natural means, meaning
|
||||
* not by command, MobSpawner, cheat, etc.. Just naturally throughout the world.
|
||||
*
|
||||
* This allows the mod to create special functionality that runs on a mob natural
|
||||
* spawn. The Vanilla minecraft mechanic of having 'Spider Jockies', the color of
|
||||
* sheep's wool, and Ocelot's spawning with babies can be canceled by returning
|
||||
* true from this function
|
||||
*
|
||||
* Returning true will indicate that you have performed your special spawning,
|
||||
* and no more handling will be done.
|
||||
*
|
||||
* @param entity The newly spawned entity
|
||||
* @param world The world the entity is in
|
||||
* @param x The Entitie's X Position
|
||||
* @param y The Entitie's Y Position
|
||||
* @param z The Entitie's Z Position
|
||||
* @return True to prevent any further special case handling from executing.
|
||||
*/
|
||||
public boolean onSpecialEntitySpawn(EntityLiving entity, World world, float x, float y, float z);
|
||||
}
|
||||
package net.minecraft.src.forge;
|
||||
|
||||
import net.minecraft.src.EntityLiving;
|
||||
import net.minecraft.src.World;
|
||||
|
||||
@Deprecated //See IEntityLivingHandler
|
||||
public interface ISpecialMobSpawnHandler
|
||||
{
|
||||
/**
|
||||
* Raised when a Entity is spawned into the world from natural means, meaning
|
||||
* not by command, MobSpawner, cheat, etc.. Just naturally throughout the world.
|
||||
*
|
||||
* This allows the mod to create special functionality that runs on a mob natural
|
||||
* spawn. The Vanilla minecraft mechanic of having 'Spider Jockies', the color of
|
||||
* sheep's wool, and Ocelot's spawning with babies can be canceled by returning
|
||||
* true from this function
|
||||
*
|
||||
* Returning true will indicate that you have performed your special spawning,
|
||||
* and no more handling will be done.
|
||||
*
|
||||
* @param entity The newly spawned entity
|
||||
* @param world The world the entity is in
|
||||
* @param x The Entitie's X Position
|
||||
* @param y The Entitie's Y Position
|
||||
* @param z The Entitie's Z Position
|
||||
* @return True to prevent any further special case handling from executing.
|
||||
*/
|
||||
public boolean onSpecialEntitySpawn(EntityLiving entity, World world, float x, float y, float z);
|
||||
}
|
||||
|
|
|
@ -1,64 +1,64 @@
|
|||
package net.minecraft.src.forge.adaptors;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import net.minecraft.src.DamageSource;
|
||||
import net.minecraft.src.EntityItem;
|
||||
import net.minecraft.src.EntityLiving;
|
||||
import net.minecraft.src.World;
|
||||
import net.minecraft.src.forge.IEntityLivingHandler;
|
||||
|
||||
public class EntityLivingHandlerAdaptor implements IEntityLivingHandler
|
||||
{
|
||||
|
||||
@Override
|
||||
public boolean onEntityLivingSpawn(EntityLiving entity, World world, float x, float y, float z)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onEntityLivingDeath(EntityLiving entity, DamageSource killer)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntityLivingSetAttackTarget(EntityLiving entity, EntityLiving target)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onEntityLivingAttacked(EntityLiving entity, DamageSource attack, int damage)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntityLivingJump(EntityLiving entity)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onEntityLivingFall(EntityLiving entity, float distance)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onEntityLivingUpdate(EntityLiving entity)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onEntityLivingHurt(EntityLiving entity, DamageSource source, int damage)
|
||||
{
|
||||
return damage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntityLivingDrops(EntityLiving entity, DamageSource source, ArrayList<EntityItem> drops, int lootingLevel, boolean recentlyHit, int specialDropValue)
|
||||
{
|
||||
}
|
||||
}
|
||||
package net.minecraft.src.forge.adaptors;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import net.minecraft.src.DamageSource;
|
||||
import net.minecraft.src.EntityItem;
|
||||
import net.minecraft.src.EntityLiving;
|
||||
import net.minecraft.src.World;
|
||||
import net.minecraft.src.forge.IEntityLivingHandler;
|
||||
|
||||
public class EntityLivingHandlerAdaptor implements IEntityLivingHandler
|
||||
{
|
||||
|
||||
@Override
|
||||
public boolean onEntityLivingSpawn(EntityLiving entity, World world, float x, float y, float z)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onEntityLivingDeath(EntityLiving entity, DamageSource killer)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntityLivingSetAttackTarget(EntityLiving entity, EntityLiving target)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onEntityLivingAttacked(EntityLiving entity, DamageSource attack, int damage)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntityLivingJump(EntityLiving entity)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onEntityLivingFall(EntityLiving entity, float distance)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onEntityLivingUpdate(EntityLiving entity)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onEntityLivingHurt(EntityLiving entity, DamageSource source, int damage)
|
||||
{
|
||||
return damage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntityLivingDrops(EntityLiving entity, DamageSource source, ArrayList<EntityItem> drops, int lootingLevel, boolean recentlyHit, int specialDropValue)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,138 +1,138 @@
|
|||
package net.minecraft.src.forge.oredict;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import net.minecraft.src.Block;
|
||||
import net.minecraft.src.Item;
|
||||
import net.minecraft.src.ItemStack;
|
||||
import net.minecraft.src.forge.IOreHandler;
|
||||
|
||||
public class OreDictionary
|
||||
{
|
||||
private static int maxID = 0;
|
||||
private static HashMap<String, Integer> oreIDs = new HashMap<String, Integer>();
|
||||
private static HashMap<Integer, ArrayList<ItemStack>> oreStacks = new HashMap<Integer, ArrayList<ItemStack>>();
|
||||
private static ArrayList<IOreHandler> oreHandlers = new ArrayList<IOreHandler>();
|
||||
|
||||
/**
|
||||
* Gets the integer ID for the specified ore name.
|
||||
* If the name does not have a ID it assigns it a new one.
|
||||
*
|
||||
* @param name The unique name for this ore 'oreIron', 'ingotIron', etc..
|
||||
* @return A number representing the ID for this ore type
|
||||
*/
|
||||
public static int getOreID(String name)
|
||||
{
|
||||
Integer val = oreIDs.get(name);
|
||||
if (val == null)
|
||||
{
|
||||
val = maxID++;
|
||||
oreIDs.put(name, val);
|
||||
oreStacks.put(val, new ArrayList<ItemStack>());
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse of getOreID, will not create new entries.
|
||||
*
|
||||
* @param id The ID to translate to a string
|
||||
* @return The String name, or "Unknown" if not found.
|
||||
*/
|
||||
public static String getOreName(int id)
|
||||
{
|
||||
for (Map.Entry<String, Integer> entry : oreIDs.entrySet())
|
||||
{
|
||||
if (id == entry.getValue())
|
||||
{
|
||||
return entry.getKey();
|
||||
}
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the ArrayList of items that are registered to this ore type.
|
||||
* Creates the list as empty if it did not exist.
|
||||
*
|
||||
* @param id The ore ID, see getOreID
|
||||
* @return An arrayList containing ItemStacks registered for this ore
|
||||
*/
|
||||
public static ArrayList<ItemStack> getOres(String name)
|
||||
{
|
||||
return getOres(getOreID(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the ArrayList of items that are registered to this ore type.
|
||||
* Creates the list as empty if it did not exist.
|
||||
*
|
||||
* @param id The ore ID, see getOreID
|
||||
* @return An arrayList containing ItemStacks registered for this ore
|
||||
*/
|
||||
public static ArrayList<ItemStack> getOres(Integer id)
|
||||
{
|
||||
ArrayList<ItemStack> val = oreStacks.get(id);
|
||||
if (val == null)
|
||||
{
|
||||
val = new ArrayList<ItemStack>();
|
||||
oreStacks.put(id, val);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new ore handler.
|
||||
* This will automatically call the handler with all current ores during
|
||||
* registration, and every time a new ore is added later.
|
||||
*
|
||||
* @param handler The Ore Handler
|
||||
*/
|
||||
public static void registerOreHandler(IOreHandler handler)
|
||||
{
|
||||
oreHandlers.add(handler);
|
||||
|
||||
HashMap<String, Integer> tmp = (HashMap<String, Integer>)oreIDs.clone();
|
||||
|
||||
for(Map.Entry<String, Integer> entry : tmp.entrySet())
|
||||
{
|
||||
for(ItemStack stack : getOres(entry.getValue()))
|
||||
{
|
||||
handler.registerOre(entry.getKey(), stack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Convenience functions that make for cleaner code mod side. They all drill down to registerOre(String, int, ItemStack)
|
||||
public static void registerOre(String name, Item ore){ registerOre(name, new ItemStack(ore)); }
|
||||
public static void registerOre(String name, Block ore){ registerOre(name, new ItemStack(ore)); }
|
||||
public static void registerOre(String name, ItemStack ore){ registerOre(name, getOreID(name), ore); }
|
||||
public static void registerOre(int id, Item ore){ registerOre(id, new ItemStack(ore)); }
|
||||
public static void registerOre(int id, Block ore){ registerOre(id, new ItemStack(ore)); }
|
||||
public static void registerOre(int id, ItemStack ore){ registerOre(getOreName(id), id, ore); }
|
||||
|
||||
/**
|
||||
* Registers a ore item into the dictionary.
|
||||
* Raises the registerOre function in all registered handlers.
|
||||
*
|
||||
* @param name The name of the ore
|
||||
* @param id The ID of the ore
|
||||
* @param ore The ore's ItemStack
|
||||
*/
|
||||
private static void registerOre(String name, int id, ItemStack ore)
|
||||
{
|
||||
ArrayList<ItemStack> ores = getOres(id);
|
||||
ore = ore.copy();
|
||||
ores.add(ore);
|
||||
|
||||
for (IOreHandler handler : oreHandlers)
|
||||
{
|
||||
handler.registerOre(name, ore);
|
||||
}
|
||||
}
|
||||
}
|
||||
package net.minecraft.src.forge.oredict;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import net.minecraft.src.Block;
|
||||
import net.minecraft.src.Item;
|
||||
import net.minecraft.src.ItemStack;
|
||||
import net.minecraft.src.forge.IOreHandler;
|
||||
|
||||
public class OreDictionary
|
||||
{
|
||||
private static int maxID = 0;
|
||||
private static HashMap<String, Integer> oreIDs = new HashMap<String, Integer>();
|
||||
private static HashMap<Integer, ArrayList<ItemStack>> oreStacks = new HashMap<Integer, ArrayList<ItemStack>>();
|
||||
private static ArrayList<IOreHandler> oreHandlers = new ArrayList<IOreHandler>();
|
||||
|
||||
/**
|
||||
* Gets the integer ID for the specified ore name.
|
||||
* If the name does not have a ID it assigns it a new one.
|
||||
*
|
||||
* @param name The unique name for this ore 'oreIron', 'ingotIron', etc..
|
||||
* @return A number representing the ID for this ore type
|
||||
*/
|
||||
public static int getOreID(String name)
|
||||
{
|
||||
Integer val = oreIDs.get(name);
|
||||
if (val == null)
|
||||
{
|
||||
val = maxID++;
|
||||
oreIDs.put(name, val);
|
||||
oreStacks.put(val, new ArrayList<ItemStack>());
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse of getOreID, will not create new entries.
|
||||
*
|
||||
* @param id The ID to translate to a string
|
||||
* @return The String name, or "Unknown" if not found.
|
||||
*/
|
||||
public static String getOreName(int id)
|
||||
{
|
||||
for (Map.Entry<String, Integer> entry : oreIDs.entrySet())
|
||||
{
|
||||
if (id == entry.getValue())
|
||||
{
|
||||
return entry.getKey();
|
||||
}
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the ArrayList of items that are registered to this ore type.
|
||||
* Creates the list as empty if it did not exist.
|
||||
*
|
||||
* @param id The ore ID, see getOreID
|
||||
* @return An arrayList containing ItemStacks registered for this ore
|
||||
*/
|
||||
public static ArrayList<ItemStack> getOres(String name)
|
||||
{
|
||||
return getOres(getOreID(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the ArrayList of items that are registered to this ore type.
|
||||
* Creates the list as empty if it did not exist.
|
||||
*
|
||||
* @param id The ore ID, see getOreID
|
||||
* @return An arrayList containing ItemStacks registered for this ore
|
||||
*/
|
||||
public static ArrayList<ItemStack> getOres(Integer id)
|
||||
{
|
||||
ArrayList<ItemStack> val = oreStacks.get(id);
|
||||
if (val == null)
|
||||
{
|
||||
val = new ArrayList<ItemStack>();
|
||||
oreStacks.put(id, val);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new ore handler.
|
||||
* This will automatically call the handler with all current ores during
|
||||
* registration, and every time a new ore is added later.
|
||||
*
|
||||
* @param handler The Ore Handler
|
||||
*/
|
||||
public static void registerOreHandler(IOreHandler handler)
|
||||
{
|
||||
oreHandlers.add(handler);
|
||||
|
||||
HashMap<String, Integer> tmp = (HashMap<String, Integer>)oreIDs.clone();
|
||||
|
||||
for(Map.Entry<String, Integer> entry : tmp.entrySet())
|
||||
{
|
||||
for(ItemStack stack : getOres(entry.getValue()))
|
||||
{
|
||||
handler.registerOre(entry.getKey(), stack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Convenience functions that make for cleaner code mod side. They all drill down to registerOre(String, int, ItemStack)
|
||||
public static void registerOre(String name, Item ore){ registerOre(name, new ItemStack(ore)); }
|
||||
public static void registerOre(String name, Block ore){ registerOre(name, new ItemStack(ore)); }
|
||||
public static void registerOre(String name, ItemStack ore){ registerOre(name, getOreID(name), ore); }
|
||||
public static void registerOre(int id, Item ore){ registerOre(id, new ItemStack(ore)); }
|
||||
public static void registerOre(int id, Block ore){ registerOre(id, new ItemStack(ore)); }
|
||||
public static void registerOre(int id, ItemStack ore){ registerOre(getOreName(id), id, ore); }
|
||||
|
||||
/**
|
||||
* Registers a ore item into the dictionary.
|
||||
* Raises the registerOre function in all registered handlers.
|
||||
*
|
||||
* @param name The name of the ore
|
||||
* @param id The ID of the ore
|
||||
* @param ore The ore's ItemStack
|
||||
*/
|
||||
private static void registerOre(String name, int id, ItemStack ore)
|
||||
{
|
||||
ArrayList<ItemStack> ores = getOres(id);
|
||||
ore = ore.copy();
|
||||
ores.add(ore);
|
||||
|
||||
for (IOreHandler handler : oreHandlers)
|
||||
{
|
||||
handler.registerOre(name, ore);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,216 +1,216 @@
|
|||
package net.minecraft.src.forge.oredict;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
import net.minecraft.src.Block;
|
||||
import net.minecraft.src.IRecipe;
|
||||
import net.minecraft.src.InventoryCrafting;
|
||||
import net.minecraft.src.Item;
|
||||
import net.minecraft.src.ItemStack;
|
||||
import net.minecraft.src.ShapedRecipes;
|
||||
|
||||
public class ShapedOreRecipe implements IRecipe
|
||||
{
|
||||
//Added in for future ease of change, but hard coded for now.
|
||||
private static final int MAX_CRAFT_GRID_WIDTH = 3;
|
||||
private static final int MAX_CRAFT_GRID_HEIGHT = 3;
|
||||
|
||||
private ItemStack output = null;
|
||||
private Object[] input = null;
|
||||
private int width = 0;
|
||||
private int height = 0;
|
||||
private boolean mirriored = true;
|
||||
|
||||
public ShapedOreRecipe(Block result, Object... recipe){ this(result, true, recipe);}
|
||||
public ShapedOreRecipe(Item result, Object... recipe){ this(result, true, recipe); }
|
||||
public ShapedOreRecipe(ItemStack result, Object... recipe){ this(result, true, recipe); }
|
||||
public ShapedOreRecipe(Block result, boolean mirrior, Object... recipe){ this(new ItemStack(result), mirrior, recipe);}
|
||||
public ShapedOreRecipe(Item result, boolean mirrior, Object... recipe){ this(new ItemStack(result), mirrior, recipe); }
|
||||
|
||||
public ShapedOreRecipe(ItemStack result, boolean mirrior, Object... recipe)
|
||||
{
|
||||
output = result.copy();
|
||||
mirriored = mirrior;
|
||||
|
||||
String shape = "";
|
||||
int idx = 0;
|
||||
|
||||
if (recipe[idx] instanceof String[])
|
||||
{
|
||||
String[] parts = ((String[])recipe[idx++]);
|
||||
|
||||
for (String s : parts)
|
||||
{
|
||||
width = s.length();
|
||||
shape += s;
|
||||
}
|
||||
|
||||
height = parts.length;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (recipe[idx] instanceof String)
|
||||
{
|
||||
String s = (String)recipe[idx++];
|
||||
shape += s;
|
||||
width = s.length();
|
||||
height++;
|
||||
}
|
||||
}
|
||||
|
||||
if (width * height != shape.length())
|
||||
{
|
||||
String ret = "Invalid shaped ore recipe: ";
|
||||
for (Object tmp : recipe)
|
||||
{
|
||||
ret += tmp + ", ";
|
||||
}
|
||||
ret += output;
|
||||
throw new RuntimeException(ret);
|
||||
}
|
||||
|
||||
HashMap<Character, Object> itemMap = new HashMap<Character, Object>();
|
||||
|
||||
for (; idx < recipe.length; idx += 2)
|
||||
{
|
||||
Character chr = (Character)recipe[idx];
|
||||
Object in = recipe[idx + 1];
|
||||
Object val = null;
|
||||
|
||||
if (in instanceof ItemStack)
|
||||
{
|
||||
itemMap.put(chr, ((ItemStack)in).copy());
|
||||
}
|
||||
else if (in instanceof Item)
|
||||
{
|
||||
itemMap.put(chr, new ItemStack((Item)in));
|
||||
}
|
||||
else if (in instanceof Block)
|
||||
{
|
||||
itemMap.put(chr, new ItemStack((Block)in, 1, -1));
|
||||
}
|
||||
else if (in instanceof String)
|
||||
{
|
||||
itemMap.put(chr, OreDictionary.getOres((String)in));
|
||||
}
|
||||
else
|
||||
{
|
||||
String ret = "Invalid shaped ore recipe: ";
|
||||
for (Object tmp : recipe)
|
||||
{
|
||||
ret += tmp + ", ";
|
||||
}
|
||||
ret += output;
|
||||
throw new RuntimeException(ret);
|
||||
}
|
||||
}
|
||||
|
||||
input = new Object[width * height];
|
||||
int x = 0;
|
||||
for (char chr : shape.toCharArray())
|
||||
{
|
||||
input[x++] = itemMap.get(chr);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getCraftingResult(InventoryCrafting var1){ return output.copy(); }
|
||||
|
||||
@Override
|
||||
public int getRecipeSize(){ return input.length; }
|
||||
|
||||
@Override
|
||||
public ItemStack getRecipeOutput(){ return output; }
|
||||
|
||||
@Override
|
||||
public boolean matches(InventoryCrafting inv)
|
||||
{
|
||||
for (int x = 0; x <= MAX_CRAFT_GRID_WIDTH - width; x++)
|
||||
{
|
||||
for (int y = 0; y <= MAX_CRAFT_GRID_HEIGHT - height; ++y)
|
||||
{
|
||||
if (checkMatch(inv, x, y, true))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mirriored && checkMatch(inv, x, y, false))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean checkMatch(InventoryCrafting inv, int startX, int startY, boolean mirrior)
|
||||
{
|
||||
for (int x = 0; x < MAX_CRAFT_GRID_WIDTH; x++)
|
||||
{
|
||||
for (int y = 0; y < MAX_CRAFT_GRID_HEIGHT; y++)
|
||||
{
|
||||
int subX = x - startX;
|
||||
int subY = y - startY;
|
||||
Object target = null;
|
||||
|
||||
if (subX >= 0 && subY >= 0 && subX < width && subY < height)
|
||||
{
|
||||
if (mirrior)
|
||||
{
|
||||
target = input[width - subX - 1 + subY * width];
|
||||
}
|
||||
else
|
||||
{
|
||||
target = input[subX + subY * width];
|
||||
}
|
||||
}
|
||||
|
||||
ItemStack slot = inv.getStackInRowAndColumn(x, y);
|
||||
|
||||
if (target instanceof ItemStack)
|
||||
{
|
||||
if (!checkItemEquals((ItemStack)target, slot))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (target instanceof ArrayList)
|
||||
{
|
||||
boolean matched = false;
|
||||
|
||||
for (ItemStack item : (ArrayList<ItemStack>)target)
|
||||
{
|
||||
matched = matched || checkItemEquals(item, slot);
|
||||
}
|
||||
|
||||
if (!matched)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (target == null && slot != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean checkItemEquals(ItemStack target, ItemStack input)
|
||||
{
|
||||
if (input == null && target != null || input != null && target == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return (target.itemID == input.itemID && (target.getItemDamage() == -1 || target.getItemDamage() == input.getItemDamage()));
|
||||
}
|
||||
|
||||
public void setMirriored(boolean mirrior)
|
||||
{
|
||||
mirriored = mirrior;
|
||||
}
|
||||
}
|
||||
package net.minecraft.src.forge.oredict;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
import net.minecraft.src.Block;
|
||||
import net.minecraft.src.IRecipe;
|
||||
import net.minecraft.src.InventoryCrafting;
|
||||
import net.minecraft.src.Item;
|
||||
import net.minecraft.src.ItemStack;
|
||||
import net.minecraft.src.ShapedRecipes;
|
||||
|
||||
public class ShapedOreRecipe implements IRecipe
|
||||
{
|
||||
//Added in for future ease of change, but hard coded for now.
|
||||
private static final int MAX_CRAFT_GRID_WIDTH = 3;
|
||||
private static final int MAX_CRAFT_GRID_HEIGHT = 3;
|
||||
|
||||
private ItemStack output = null;
|
||||
private Object[] input = null;
|
||||
private int width = 0;
|
||||
private int height = 0;
|
||||
private boolean mirriored = true;
|
||||
|
||||
public ShapedOreRecipe(Block result, Object... recipe){ this(result, true, recipe);}
|
||||
public ShapedOreRecipe(Item result, Object... recipe){ this(result, true, recipe); }
|
||||
public ShapedOreRecipe(ItemStack result, Object... recipe){ this(result, true, recipe); }
|
||||
public ShapedOreRecipe(Block result, boolean mirrior, Object... recipe){ this(new ItemStack(result), mirrior, recipe);}
|
||||
public ShapedOreRecipe(Item result, boolean mirrior, Object... recipe){ this(new ItemStack(result), mirrior, recipe); }
|
||||
|
||||
public ShapedOreRecipe(ItemStack result, boolean mirrior, Object... recipe)
|
||||
{
|
||||
output = result.copy();
|
||||
mirriored = mirrior;
|
||||
|
||||
String shape = "";
|
||||
int idx = 0;
|
||||
|
||||
if (recipe[idx] instanceof String[])
|
||||
{
|
||||
String[] parts = ((String[])recipe[idx++]);
|
||||
|
||||
for (String s : parts)
|
||||
{
|
||||
width = s.length();
|
||||
shape += s;
|
||||
}
|
||||
|
||||
height = parts.length;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (recipe[idx] instanceof String)
|
||||
{
|
||||
String s = (String)recipe[idx++];
|
||||
shape += s;
|
||||
width = s.length();
|
||||
height++;
|
||||
}
|
||||
}
|
||||
|
||||
if (width * height != shape.length())
|
||||
{
|
||||
String ret = "Invalid shaped ore recipe: ";
|
||||
for (Object tmp : recipe)
|
||||
{
|
||||
ret += tmp + ", ";
|
||||
}
|
||||
ret += output;
|
||||
throw new RuntimeException(ret);
|
||||
}
|
||||
|
||||
HashMap<Character, Object> itemMap = new HashMap<Character, Object>();
|
||||
|
||||
for (; idx < recipe.length; idx += 2)
|
||||
{
|
||||
Character chr = (Character)recipe[idx];
|
||||
Object in = recipe[idx + 1];
|
||||
Object val = null;
|
||||
|
||||
if (in instanceof ItemStack)
|
||||
{
|
||||
itemMap.put(chr, ((ItemStack)in).copy());
|
||||
}
|
||||
else if (in instanceof Item)
|
||||
{
|
||||
itemMap.put(chr, new ItemStack((Item)in));
|
||||
}
|
||||
else if (in instanceof Block)
|
||||
{
|
||||
itemMap.put(chr, new ItemStack((Block)in, 1, -1));
|
||||
}
|
||||
else if (in instanceof String)
|
||||
{
|
||||
itemMap.put(chr, OreDictionary.getOres((String)in));
|
||||
}
|
||||
else
|
||||
{
|
||||
String ret = "Invalid shaped ore recipe: ";
|
||||
for (Object tmp : recipe)
|
||||
{
|
||||
ret += tmp + ", ";
|
||||
}
|
||||
ret += output;
|
||||
throw new RuntimeException(ret);
|
||||
}
|
||||
}
|
||||
|
||||
input = new Object[width * height];
|
||||
int x = 0;
|
||||
for (char chr : shape.toCharArray())
|
||||
{
|
||||
input[x++] = itemMap.get(chr);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getCraftingResult(InventoryCrafting var1){ return output.copy(); }
|
||||
|
||||
@Override
|
||||
public int getRecipeSize(){ return input.length; }
|
||||
|
||||
@Override
|
||||
public ItemStack getRecipeOutput(){ return output; }
|
||||
|
||||
@Override
|
||||
public boolean matches(InventoryCrafting inv)
|
||||
{
|
||||
for (int x = 0; x <= MAX_CRAFT_GRID_WIDTH - width; x++)
|
||||
{
|
||||
for (int y = 0; y <= MAX_CRAFT_GRID_HEIGHT - height; ++y)
|
||||
{
|
||||
if (checkMatch(inv, x, y, true))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mirriored && checkMatch(inv, x, y, false))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean checkMatch(InventoryCrafting inv, int startX, int startY, boolean mirrior)
|
||||
{
|
||||
for (int x = 0; x < MAX_CRAFT_GRID_WIDTH; x++)
|
||||
{
|
||||
for (int y = 0; y < MAX_CRAFT_GRID_HEIGHT; y++)
|
||||
{
|
||||
int subX = x - startX;
|
||||
int subY = y - startY;
|
||||
Object target = null;
|
||||
|
||||
if (subX >= 0 && subY >= 0 && subX < width && subY < height)
|
||||
{
|
||||
if (mirrior)
|
||||
{
|
||||
target = input[width - subX - 1 + subY * width];
|
||||
}
|
||||
else
|
||||
{
|
||||
target = input[subX + subY * width];
|
||||
}
|
||||
}
|
||||
|
||||
ItemStack slot = inv.getStackInRowAndColumn(x, y);
|
||||
|
||||
if (target instanceof ItemStack)
|
||||
{
|
||||
if (!checkItemEquals((ItemStack)target, slot))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (target instanceof ArrayList)
|
||||
{
|
||||
boolean matched = false;
|
||||
|
||||
for (ItemStack item : (ArrayList<ItemStack>)target)
|
||||
{
|
||||
matched = matched || checkItemEquals(item, slot);
|
||||
}
|
||||
|
||||
if (!matched)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (target == null && slot != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean checkItemEquals(ItemStack target, ItemStack input)
|
||||
{
|
||||
if (input == null && target != null || input != null && target == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return (target.itemID == input.itemID && (target.getItemDamage() == -1 || target.getItemDamage() == input.getItemDamage()));
|
||||
}
|
||||
|
||||
public void setMirriored(boolean mirrior)
|
||||
{
|
||||
mirriored = mirrior;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,119 +1,119 @@
|
|||
package net.minecraft.src.forge.oredict;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
|
||||
import net.minecraft.src.Block;
|
||||
import net.minecraft.src.CraftingManager;
|
||||
import net.minecraft.src.IRecipe;
|
||||
import net.minecraft.src.InventoryCrafting;
|
||||
import net.minecraft.src.Item;
|
||||
import net.minecraft.src.ItemStack;
|
||||
import net.minecraft.src.ShapelessRecipes;
|
||||
|
||||
public class ShapelessOreRecipe implements IRecipe
|
||||
{
|
||||
private ItemStack output = null;
|
||||
private ArrayList input = new ArrayList();
|
||||
|
||||
public ShapelessOreRecipe(Block result, Object... recipe){ this(new ItemStack(result), recipe); }
|
||||
public ShapelessOreRecipe(Item result, Object... recipe){ this(new ItemStack(result), recipe); }
|
||||
|
||||
public ShapelessOreRecipe(ItemStack result, Object... recipe)
|
||||
{
|
||||
output = result.copy();
|
||||
for (Object in : recipe)
|
||||
{
|
||||
if (in instanceof ItemStack)
|
||||
{
|
||||
input.add(((ItemStack)in).copy());
|
||||
}
|
||||
else if (in instanceof Item)
|
||||
{
|
||||
input.add(new ItemStack((Item)in));
|
||||
}
|
||||
else if (in instanceof Block)
|
||||
{
|
||||
input.add(new ItemStack((Block)in));
|
||||
}
|
||||
else if (in instanceof String)
|
||||
{
|
||||
input.add(OreDictionary.getOres((String)in));
|
||||
}
|
||||
else
|
||||
{
|
||||
String ret = "Invalid shapeless ore recipe: ";
|
||||
for (Object tmp : recipe)
|
||||
{
|
||||
ret += tmp + ", ";
|
||||
}
|
||||
ret += output;
|
||||
throw new RuntimeException(ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRecipeSize(){ return input.size(); }
|
||||
|
||||
@Override
|
||||
public ItemStack getRecipeOutput(){ return output; }
|
||||
|
||||
@Override
|
||||
public ItemStack getCraftingResult(InventoryCrafting var1){ return output.copy(); }
|
||||
|
||||
@Override
|
||||
public boolean matches(InventoryCrafting var1)
|
||||
{
|
||||
ArrayList required = new ArrayList(input);
|
||||
|
||||
for (int x = 0; x < var1.getSizeInventory(); x++)
|
||||
{
|
||||
ItemStack slot = var1.getStackInSlot(x);
|
||||
|
||||
if (slot != null)
|
||||
{
|
||||
boolean inRecipe = false;
|
||||
Iterator req = required.iterator();
|
||||
|
||||
while (req.hasNext())
|
||||
{
|
||||
boolean match = false;
|
||||
|
||||
Object next = req.next();
|
||||
|
||||
if (next instanceof ItemStack)
|
||||
{
|
||||
match = checkItemEquals((ItemStack)next, slot);
|
||||
}
|
||||
else if (next instanceof ArrayList)
|
||||
{
|
||||
for (ItemStack item : (ArrayList<ItemStack>)next)
|
||||
{
|
||||
match = match || checkItemEquals(item, slot);
|
||||
}
|
||||
}
|
||||
|
||||
if (match)
|
||||
{
|
||||
inRecipe = true;
|
||||
required.remove(next);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!inRecipe)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return required.isEmpty();
|
||||
}
|
||||
|
||||
private boolean checkItemEquals(ItemStack target, ItemStack input)
|
||||
{
|
||||
return (target.itemID == input.itemID && (target.getItemDamage() == -1 || target.getItemDamage() == input.getItemDamage()));
|
||||
}
|
||||
}
|
||||
package net.minecraft.src.forge.oredict;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
|
||||
import net.minecraft.src.Block;
|
||||
import net.minecraft.src.CraftingManager;
|
||||
import net.minecraft.src.IRecipe;
|
||||
import net.minecraft.src.InventoryCrafting;
|
||||
import net.minecraft.src.Item;
|
||||
import net.minecraft.src.ItemStack;
|
||||
import net.minecraft.src.ShapelessRecipes;
|
||||
|
||||
public class ShapelessOreRecipe implements IRecipe
|
||||
{
|
||||
private ItemStack output = null;
|
||||
private ArrayList input = new ArrayList();
|
||||
|
||||
public ShapelessOreRecipe(Block result, Object... recipe){ this(new ItemStack(result), recipe); }
|
||||
public ShapelessOreRecipe(Item result, Object... recipe){ this(new ItemStack(result), recipe); }
|
||||
|
||||
public ShapelessOreRecipe(ItemStack result, Object... recipe)
|
||||
{
|
||||
output = result.copy();
|
||||
for (Object in : recipe)
|
||||
{
|
||||
if (in instanceof ItemStack)
|
||||
{
|
||||
input.add(((ItemStack)in).copy());
|
||||
}
|
||||
else if (in instanceof Item)
|
||||
{
|
||||
input.add(new ItemStack((Item)in));
|
||||
}
|
||||
else if (in instanceof Block)
|
||||
{
|
||||
input.add(new ItemStack((Block)in));
|
||||
}
|
||||
else if (in instanceof String)
|
||||
{
|
||||
input.add(OreDictionary.getOres((String)in));
|
||||
}
|
||||
else
|
||||
{
|
||||
String ret = "Invalid shapeless ore recipe: ";
|
||||
for (Object tmp : recipe)
|
||||
{
|
||||
ret += tmp + ", ";
|
||||
}
|
||||
ret += output;
|
||||
throw new RuntimeException(ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRecipeSize(){ return input.size(); }
|
||||
|
||||
@Override
|
||||
public ItemStack getRecipeOutput(){ return output; }
|
||||
|
||||
@Override
|
||||
public ItemStack getCraftingResult(InventoryCrafting var1){ return output.copy(); }
|
||||
|
||||
@Override
|
||||
public boolean matches(InventoryCrafting var1)
|
||||
{
|
||||
ArrayList required = new ArrayList(input);
|
||||
|
||||
for (int x = 0; x < var1.getSizeInventory(); x++)
|
||||
{
|
||||
ItemStack slot = var1.getStackInSlot(x);
|
||||
|
||||
if (slot != null)
|
||||
{
|
||||
boolean inRecipe = false;
|
||||
Iterator req = required.iterator();
|
||||
|
||||
while (req.hasNext())
|
||||
{
|
||||
boolean match = false;
|
||||
|
||||
Object next = req.next();
|
||||
|
||||
if (next instanceof ItemStack)
|
||||
{
|
||||
match = checkItemEquals((ItemStack)next, slot);
|
||||
}
|
||||
else if (next instanceof ArrayList)
|
||||
{
|
||||
for (ItemStack item : (ArrayList<ItemStack>)next)
|
||||
{
|
||||
match = match || checkItemEquals(item, slot);
|
||||
}
|
||||
}
|
||||
|
||||
if (match)
|
||||
{
|
||||
inRecipe = true;
|
||||
required.remove(next);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!inRecipe)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return required.isEmpty();
|
||||
}
|
||||
|
||||
private boolean checkItemEquals(ItemStack target, ItemStack input)
|
||||
{
|
||||
return (target.itemID == input.itemID && (target.getItemDamage() == -1 || target.getItemDamage() == input.getItemDamage()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
package net.minecraft.src.forge.packets;
|
||||
|
||||
import net.minecraft.src.NetworkManager;
|
||||
import net.minecraft.src.Packet;
|
||||
import net.minecraft.src.forge.IPacketHandler;
|
||||
|
||||
/**
|
||||
* A helper class used to make a shared interface for sending packets,
|
||||
* Should not be used outside the API itself.
|
||||
*/
|
||||
public abstract class PacketHandlerBase implements IPacketHandler
|
||||
{
|
||||
public static boolean DEBUG = false;
|
||||
|
||||
/**
|
||||
* Sends out a packet to the specified network manager.
|
||||
* This is necessary because NetClientHandler, and
|
||||
* NetServerHandler are not on both sides.
|
||||
*
|
||||
* @param network The manager to send the packet to
|
||||
* @param packet The packet to send
|
||||
*/
|
||||
public abstract void sendPacket(NetworkManager network, Packet packet);
|
||||
}
|
||||
package net.minecraft.src.forge.packets;
|
||||
|
||||
import net.minecraft.src.NetworkManager;
|
||||
import net.minecraft.src.Packet;
|
||||
import net.minecraft.src.forge.IPacketHandler;
|
||||
|
||||
/**
|
||||
* A helper class used to make a shared interface for sending packets,
|
||||
* Should not be used outside the API itself.
|
||||
*/
|
||||
public abstract class PacketHandlerBase implements IPacketHandler
|
||||
{
|
||||
public static boolean DEBUG = false;
|
||||
|
||||
/**
|
||||
* Sends out a packet to the specified network manager.
|
||||
* This is necessary because NetClientHandler, and
|
||||
* NetServerHandler are not on both sides.
|
||||
*
|
||||
* @param network The manager to send the packet to
|
||||
* @param packet The packet to send
|
||||
*/
|
||||
public abstract void sendPacket(NetworkManager network, Packet packet);
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="forge_common"/>
|
||||
<classpathentry kind="src" path="minecraft_server"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
|
||||
<classpathentry kind="lib" path="../../jars/bin/jinput.jar"/>
|
||||
<classpathentry kind="lib" path="../../jars/bin/lwjgl.jar"/>
|
||||
<classpathentry kind="lib" path="../../jars/bin/lwjgl_util.jar"/>
|
||||
<classpathentry kind="lib" path="../../jars/minecraft_server.jar"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="forge_common"/>
|
||||
<classpathentry kind="src" path="minecraft_server"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
|
||||
<classpathentry kind="lib" path="../../jars/bin/jinput.jar"/>
|
||||
<classpathentry kind="lib" path="../../jars/bin/lwjgl.jar"/>
|
||||
<classpathentry kind="lib" path="../../jars/bin/lwjgl_util.jar"/>
|
||||
<classpathentry kind="lib" path="../../jars/minecraft_server.jar"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
|
|
2
forge/forge_server/.gitignore
vendored
2
forge/forge_server/.gitignore
vendored
|
@ -1 +1 @@
|
|||
/bin/
|
||||
/bin/
|
||||
|
|
|
@ -1,29 +1,29 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>forge_server</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
<linkedResources>
|
||||
<link>
|
||||
<name>forge_common</name>
|
||||
<type>2</type>
|
||||
<locationURI>PARENT-1-PROJECT_LOC/forge_common</locationURI>
|
||||
</link>
|
||||
<link>
|
||||
<name>minecraft_server</name>
|
||||
<type>2</type>
|
||||
<locationURI>PARENT-1-WORKSPACE_LOC/src_work/minecraft_server</locationURI>
|
||||
</link>
|
||||
</linkedResources>
|
||||
</projectDescription>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>forge_server</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
<linkedResources>
|
||||
<link>
|
||||
<name>forge_common</name>
|
||||
<type>2</type>
|
||||
<locationURI>PARENT-1-PROJECT_LOC/forge_common</locationURI>
|
||||
</link>
|
||||
<link>
|
||||
<name>minecraft_server</name>
|
||||
<type>2</type>
|
||||
<locationURI>PARENT-1-WORKSPACE_LOC/src_work/minecraft_server</locationURI>
|
||||
</link>
|
||||
</linkedResources>
|
||||
</projectDescription>
|
||||
|
|
|
@ -1,65 +1,65 @@
|
|||
Minecraft Forge Public Licence
|
||||
==============================
|
||||
|
||||
Version 1.0
|
||||
|
||||
0. Definitions
|
||||
--------------
|
||||
|
||||
Minecraft: Denotes a copy of the Minecraft game licensed by Mojang AB
|
||||
|
||||
User: Anybody that interract with the software in one of the following ways:
|
||||
- play
|
||||
- decompile
|
||||
- recompile or compile
|
||||
- modify
|
||||
|
||||
Minecraft Forge: The Minecraft Forge code, in source form, class file form, as
|
||||
obtained in a standalone fashion or as part of a wider distribution.
|
||||
|
||||
Dependency: Code required to have Minecraft Forge working properly. That can
|
||||
include dependencies required to compile the code as well as modifications in
|
||||
the Minecraft sources that are required to have Minecraft Forge working.
|
||||
|
||||
1. Scope
|
||||
--------
|
||||
|
||||
The present license is granted to any user of Minecraft Forge. As a
|
||||
prerequisite, a user of Minecraft Forge must own a legally aquired copy of
|
||||
Minecraft
|
||||
|
||||
2. Play rights
|
||||
--------------
|
||||
|
||||
The user of Minecraft Forge is allowed to install the software on a client or
|
||||
a server and to play it without restriction.
|
||||
|
||||
3. Modification rights
|
||||
----------------------
|
||||
|
||||
The user has the right to decompile the source code, look at either the
|
||||
decompiled version or the original source code, and to modify it.
|
||||
|
||||
4. Derivation rights
|
||||
--------------------
|
||||
|
||||
The user has the rights to derive code from Minecraft Forge, that is to say to
|
||||
write code that either extends Minecraft Forge class and interfaces,
|
||||
instantiate the objects declared or calls the functions. This code is known as
|
||||
"derived" code, and can be licensed with conditions different from Minecraft
|
||||
Forge.
|
||||
|
||||
|
||||
5. Distribution rights
|
||||
----------------------
|
||||
|
||||
The user of Minecraft Forge is allowed to redistribute Minecraft Forge in
|
||||
partially, in totallity, or included in a distribution. When distributing
|
||||
binaries or class files, the user must provide means to obtain the sources of
|
||||
the distributed version of Minecraft Forge at no costs. This includes the
|
||||
files as well as any dependency that the code may rely on, including patches to
|
||||
minecraft original sources.
|
||||
|
||||
Modification of Minecraft Forge as well as dependencies, including patches to
|
||||
minecraft original sources, has to remain under the terms of the present
|
||||
license.
|
||||
Minecraft Forge Public Licence
|
||||
==============================
|
||||
|
||||
Version 1.0
|
||||
|
||||
0. Definitions
|
||||
--------------
|
||||
|
||||
Minecraft: Denotes a copy of the Minecraft game licensed by Mojang AB
|
||||
|
||||
User: Anybody that interract with the software in one of the following ways:
|
||||
- play
|
||||
- decompile
|
||||
- recompile or compile
|
||||
- modify
|
||||
|
||||
Minecraft Forge: The Minecraft Forge code, in source form, class file form, as
|
||||
obtained in a standalone fashion or as part of a wider distribution.
|
||||
|
||||
Dependency: Code required to have Minecraft Forge working properly. That can
|
||||
include dependencies required to compile the code as well as modifications in
|
||||
the Minecraft sources that are required to have Minecraft Forge working.
|
||||
|
||||
1. Scope
|
||||
--------
|
||||
|
||||
The present license is granted to any user of Minecraft Forge. As a
|
||||
prerequisite, a user of Minecraft Forge must own a legally aquired copy of
|
||||
Minecraft
|
||||
|
||||
2. Play rights
|
||||
--------------
|
||||
|
||||
The user of Minecraft Forge is allowed to install the software on a client or
|
||||
a server and to play it without restriction.
|
||||
|
||||
3. Modification rights
|
||||
----------------------
|
||||
|
||||
The user has the right to decompile the source code, look at either the
|
||||
decompiled version or the original source code, and to modify it.
|
||||
|
||||
4. Derivation rights
|
||||
--------------------
|
||||
|
||||
The user has the rights to derive code from Minecraft Forge, that is to say to
|
||||
write code that either extends Minecraft Forge class and interfaces,
|
||||
instantiate the objects declared or calls the functions. This code is known as
|
||||
"derived" code, and can be licensed with conditions different from Minecraft
|
||||
Forge.
|
||||
|
||||
|
||||
5. Distribution rights
|
||||
----------------------
|
||||
|
||||
The user of Minecraft Forge is allowed to redistribute Minecraft Forge in
|
||||
partially, in totallity, or included in a distribution. When distributing
|
||||
binaries or class files, the user must provide means to obtain the sources of
|
||||
the distributed version of Minecraft Forge at no costs. This includes the
|
||||
files as well as any dependency that the code may rely on, including patches to
|
||||
minecraft original sources.
|
||||
|
||||
Modification of Minecraft Forge as well as dependencies, including patches to
|
||||
minecraft original sources, has to remain under the terms of the present
|
||||
license.
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
IBXM is copyright (c) 2007, Martin Cameron, and is licensed under the BSD License.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
Neither the name of mumart nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
IBXM is copyright (c) 2007, Martin Cameron, and is licensed under the BSD License.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
Neither the name of mumart nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
|
|
@ -1,40 +1,40 @@
|
|||
SoundSystem CodecIBXM Class License:
|
||||
|
||||
You are free to use this class for any purpose, commercial or otherwise.
|
||||
You may modify this class or source code, and distribute it any way you
|
||||
like, provided the following conditions are met:
|
||||
|
||||
1) You may not falsely claim to be the author of this class or any
|
||||
unmodified portion of it.
|
||||
2) You may not copyright this class or a modified version of it and then
|
||||
sue me for copyright infringement.
|
||||
3) If you modify the source code, you must clearly document the changes
|
||||
made before redistributing the modified source code, so other users know
|
||||
it is not the original code.
|
||||
4) You are not required to give me credit for this class in any derived
|
||||
work, but if you do, you must also mention my website:
|
||||
http://www.paulscode.com
|
||||
5) I the author will not be responsible for any damages (physical,
|
||||
financial, or otherwise) caused by the use if this class or any
|
||||
portion of it.
|
||||
6) I the author do not guarantee, warrant, or make any representations,
|
||||
either expressed or implied, regarding the use of this class or any
|
||||
portion of it.
|
||||
|
||||
Author: Paul Lamb
|
||||
http://www.paulscode.com
|
||||
|
||||
|
||||
This software is based on or using the IBXM library available from
|
||||
http://www.geocities.com/sunet2000/
|
||||
|
||||
|
||||
IBXM is copyright (c) 2007, Martin Cameron, and is licensed under the BSD License.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
Neither the name of mumart nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
SoundSystem CodecIBXM Class License:
|
||||
|
||||
You are free to use this class for any purpose, commercial or otherwise.
|
||||
You may modify this class or source code, and distribute it any way you
|
||||
like, provided the following conditions are met:
|
||||
|
||||
1) You may not falsely claim to be the author of this class or any
|
||||
unmodified portion of it.
|
||||
2) You may not copyright this class or a modified version of it and then
|
||||
sue me for copyright infringement.
|
||||
3) If you modify the source code, you must clearly document the changes
|
||||
made before redistributing the modified source code, so other users know
|
||||
it is not the original code.
|
||||
4) You are not required to give me credit for this class in any derived
|
||||
work, but if you do, you must also mention my website:
|
||||
http://www.paulscode.com
|
||||
5) I the author will not be responsible for any damages (physical,
|
||||
financial, or otherwise) caused by the use if this class or any
|
||||
portion of it.
|
||||
6) I the author do not guarantee, warrant, or make any representations,
|
||||
either expressed or implied, regarding the use of this class or any
|
||||
portion of it.
|
||||
|
||||
Author: Paul Lamb
|
||||
http://www.paulscode.com
|
||||
|
||||
|
||||
This software is based on or using the IBXM library available from
|
||||
http://www.geocities.com/sunet2000/
|
||||
|
||||
|
||||
IBXM is copyright (c) 2007, Martin Cameron, and is licensed under the BSD License.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
Neither the name of mumart nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
*** HOW TO INSTALL ***
|
||||
|
||||
Extract the download archive directly into your MCP-directiory.
|
||||
It should create a folder "forge" within that directory, containing all
|
||||
extracted files.
|
||||
|
||||
You should use freshly downloaded jars, add NOTHING to the jars, ModLoader
|
||||
is no longer needed. Both client and server should be 100% clean.
|
||||
|
||||
You also need to install the FernFlower decompiler, you can download it at
|
||||
http://goo.gl/PnJHp. Extract fernflower.jar into your MCP's runtime/bin folder.
|
||||
|
||||
Now just start the install.cmd/.sh, MCForge will install itself into the proper
|
||||
locations and copy all needed files, as well as modifying the needed baseclasses.
|
||||
|
||||
Forge also includes a snapshot of the MCP mapings, this may not be the current
|
||||
version of the mapings. But you must use the provided mapings in order for the
|
||||
patch files to work together.
|
||||
|
||||
The install scripts should take care of everything for you, so you should not need
|
||||
to run ANY MCP script before installing forge.
|
||||
|
||||
*** HOW TO INSTALL ***
|
||||
|
||||
Extract the download archive directly into your MCP-directiory.
|
||||
It should create a folder "forge" within that directory, containing all
|
||||
extracted files.
|
||||
|
||||
You should use freshly downloaded jars, add NOTHING to the jars, ModLoader
|
||||
is no longer needed. Both client and server should be 100% clean.
|
||||
|
||||
You also need to install the FernFlower decompiler, you can download it at
|
||||
http://goo.gl/PnJHp. Extract fernflower.jar into your MCP's runtime/bin folder.
|
||||
|
||||
Now just start the install.cmd/.sh, MCForge will install itself into the proper
|
||||
locations and copy all needed files, as well as modifying the needed baseclasses.
|
||||
|
||||
Forge also includes a snapshot of the MCP mapings, this may not be the current
|
||||
version of the mapings. But you must use the provided mapings in order for the
|
||||
patch files to work together.
|
||||
|
||||
The install scripts should take care of everything for you, so you should not need
|
||||
to run ANY MCP script before installing forge.
|
||||
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
@echo off
|
||||
..\runtime\bin\python\python_mcp install.py
|
||||
@echo off
|
||||
..\runtime\bin\python\python_mcp install.py
|
||||
pause
|
|
@ -1,105 +1,105 @@
|
|||
import os, os.path, sys
|
||||
import urllib, zipfile
|
||||
import shutil, glob, fnmatch
|
||||
import subprocess, logging
|
||||
|
||||
forge_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
mcp_dir = os.path.abspath('..')
|
||||
src_dir = os.path.join(mcp_dir, 'src')
|
||||
|
||||
sys.path.append(mcp_dir)
|
||||
from runtime.decompile import decompile
|
||||
from runtime.updatenames import updatenames
|
||||
from runtime.updatemd5 import updatemd5
|
||||
from runtime.cleanup import cleanup
|
||||
from runtime.updatemcp import updatemcp
|
||||
|
||||
from forge import apply_patches, copytree, reset_logger, download_ff, cleanup_source, pre_decompile, post_decompile
|
||||
|
||||
def main():
|
||||
print '=================================== Minecraft Forge Setup Start ================================='
|
||||
|
||||
if os.path.isdir(os.path.join(mcp_dir, 'conf')):
|
||||
shutil.rmtree(os.path.join(mcp_dir, 'conf'))
|
||||
copytree(os.path.join(forge_dir, 'conf'), os.path.join(mcp_dir, 'conf'))
|
||||
|
||||
if os.path.isdir(src_dir):
|
||||
os.chdir(mcp_dir)
|
||||
cleanup(None, False)
|
||||
reset_logger()
|
||||
os.chdir(forge_dir)
|
||||
|
||||
if os.path.isdir(src_dir):
|
||||
print 'Please make sure to backup your modified files, and say yes when it asks you to do cleanup.'
|
||||
sys.exit(1)
|
||||
|
||||
if not download_ff(mcp_dir):
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
pre_decompile()
|
||||
|
||||
os.chdir(mcp_dir)
|
||||
# Conf JAD CSV -r -d -a -n -p -o -l -g
|
||||
decompile(None, False, False, True, True, False, True, False, False, False, False)
|
||||
reset_logger()
|
||||
os.chdir(forge_dir)
|
||||
|
||||
post_decompile()
|
||||
|
||||
except SystemExit, e:
|
||||
print 'Decompile Exception: %d ' % e.code
|
||||
raise e
|
||||
|
||||
if not os.path.isdir(src_dir):
|
||||
print 'Something went wrong, src folder not found at: %s' % src_dir
|
||||
sys.exit(1)
|
||||
|
||||
cleanup_source(src_dir)
|
||||
|
||||
has_client = os.path.isdir(os.path.join(mcp_dir, 'src', 'minecraft'))
|
||||
has_server = os.path.isdir(os.path.join(mcp_dir, 'src', 'minecraft_server'))
|
||||
|
||||
fml_dir = os.path.join(forge_dir, 'fml')
|
||||
print 'Applying Forge ModLoader patches'
|
||||
if has_client:
|
||||
if os.path.isdir(os.path.join(fml_dir, 'patches', 'minecraft')):
|
||||
apply_patches(os.path.join(fml_dir, 'patches', 'minecraft'), src_dir)
|
||||
if os.path.isdir(os.path.join(fml_dir, 'src', 'minecraft')):
|
||||
copytree(os.path.join(fml_dir, 'src', 'minecraft'), os.path.join(src_dir, 'minecraft'))
|
||||
if has_server:
|
||||
if os.path.isdir(os.path.join(fml_dir, 'patches', 'minecraft_server')):
|
||||
apply_patches(os.path.join(fml_dir, 'patches', 'minecraft_server'), src_dir)
|
||||
if os.path.isdir(os.path.join(fml_dir, 'src', 'minecraft_server')):
|
||||
copytree(os.path.join(fml_dir, 'src', 'minecraft_server'), os.path.join(src_dir, 'minecraft_server'))
|
||||
|
||||
os.chdir(mcp_dir)
|
||||
updatenames(None, True)
|
||||
reset_logger()
|
||||
os.chdir(forge_dir)
|
||||
|
||||
print 'Applying forge patches'
|
||||
if has_client:
|
||||
if os.path.isdir(os.path.join(forge_dir, 'patches', 'minecraft')):
|
||||
apply_patches(os.path.join(forge_dir, 'patches', 'minecraft'), src_dir)
|
||||
if os.path.isdir(os.path.join(forge_dir, 'src', 'minecraft')):
|
||||
copytree(os.path.join(forge_dir, 'src', 'minecraft'), os.path.join(src_dir, 'minecraft'))
|
||||
if has_server:
|
||||
if os.path.isdir(os.path.join(forge_dir, 'patches', 'minecraft_server')):
|
||||
apply_patches(os.path.join(forge_dir, 'patches', 'minecraft_server'), src_dir)
|
||||
if os.path.isdir(os.path.join(forge_dir, 'src', 'minecraft_server')):
|
||||
copytree(os.path.join(forge_dir, 'src', 'minecraft_server'), os.path.join(src_dir, 'minecraft_server'))
|
||||
|
||||
os.chdir(mcp_dir)
|
||||
updatemcp(None, True)
|
||||
reset_logger()
|
||||
updatenames(None, True)
|
||||
reset_logger()
|
||||
updatemd5(None, True)
|
||||
reset_logger()
|
||||
os.chdir(forge_dir)
|
||||
|
||||
print '=================================== Minecraft Forge Setup Finished ================================='
|
||||
|
||||
if __name__ == '__main__':
|
||||
import os, os.path, sys
|
||||
import urllib, zipfile
|
||||
import shutil, glob, fnmatch
|
||||
import subprocess, logging
|
||||
|
||||
forge_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
mcp_dir = os.path.abspath('..')
|
||||
src_dir = os.path.join(mcp_dir, 'src')
|
||||
|
||||
sys.path.append(mcp_dir)
|
||||
from runtime.decompile import decompile
|
||||
from runtime.updatenames import updatenames
|
||||
from runtime.updatemd5 import updatemd5
|
||||
from runtime.cleanup import cleanup
|
||||
from runtime.updatemcp import updatemcp
|
||||
|
||||
from forge import apply_patches, copytree, reset_logger, download_ff, cleanup_source, pre_decompile, post_decompile
|
||||
|
||||
def main():
|
||||
print '=================================== Minecraft Forge Setup Start ================================='
|
||||
|
||||
if os.path.isdir(os.path.join(mcp_dir, 'conf')):
|
||||
shutil.rmtree(os.path.join(mcp_dir, 'conf'))
|
||||
copytree(os.path.join(forge_dir, 'conf'), os.path.join(mcp_dir, 'conf'))
|
||||
|
||||
if os.path.isdir(src_dir):
|
||||
os.chdir(mcp_dir)
|
||||
cleanup(None, False)
|
||||
reset_logger()
|
||||
os.chdir(forge_dir)
|
||||
|
||||
if os.path.isdir(src_dir):
|
||||
print 'Please make sure to backup your modified files, and say yes when it asks you to do cleanup.'
|
||||
sys.exit(1)
|
||||
|
||||
if not download_ff(mcp_dir):
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
pre_decompile()
|
||||
|
||||
os.chdir(mcp_dir)
|
||||
# Conf JAD CSV -r -d -a -n -p -o -l -g
|
||||
decompile(None, False, False, True, True, False, True, False, False, False, False)
|
||||
reset_logger()
|
||||
os.chdir(forge_dir)
|
||||
|
||||
post_decompile()
|
||||
|
||||
except SystemExit, e:
|
||||
print 'Decompile Exception: %d ' % e.code
|
||||
raise e
|
||||
|
||||
if not os.path.isdir(src_dir):
|
||||
print 'Something went wrong, src folder not found at: %s' % src_dir
|
||||
sys.exit(1)
|
||||
|
||||
cleanup_source(src_dir)
|
||||
|
||||
has_client = os.path.isdir(os.path.join(mcp_dir, 'src', 'minecraft'))
|
||||
has_server = os.path.isdir(os.path.join(mcp_dir, 'src', 'minecraft_server'))
|
||||
|
||||
fml_dir = os.path.join(forge_dir, 'fml')
|
||||
print 'Applying Forge ModLoader patches'
|
||||
if has_client:
|
||||
if os.path.isdir(os.path.join(fml_dir, 'patches', 'minecraft')):
|
||||
apply_patches(os.path.join(fml_dir, 'patches', 'minecraft'), src_dir)
|
||||
if os.path.isdir(os.path.join(fml_dir, 'src', 'minecraft')):
|
||||
copytree(os.path.join(fml_dir, 'src', 'minecraft'), os.path.join(src_dir, 'minecraft'))
|
||||
if has_server:
|
||||
if os.path.isdir(os.path.join(fml_dir, 'patches', 'minecraft_server')):
|
||||
apply_patches(os.path.join(fml_dir, 'patches', 'minecraft_server'), src_dir)
|
||||
if os.path.isdir(os.path.join(fml_dir, 'src', 'minecraft_server')):
|
||||
copytree(os.path.join(fml_dir, 'src', 'minecraft_server'), os.path.join(src_dir, 'minecraft_server'))
|
||||
|
||||
os.chdir(mcp_dir)
|
||||
updatenames(None, True)
|
||||
reset_logger()
|
||||
os.chdir(forge_dir)
|
||||
|
||||
print 'Applying forge patches'
|
||||
if has_client:
|
||||
if os.path.isdir(os.path.join(forge_dir, 'patches', 'minecraft')):
|
||||
apply_patches(os.path.join(forge_dir, 'patches', 'minecraft'), src_dir)
|
||||
if os.path.isdir(os.path.join(forge_dir, 'src', 'minecraft')):
|
||||
copytree(os.path.join(forge_dir, 'src', 'minecraft'), os.path.join(src_dir, 'minecraft'))
|
||||
if has_server:
|
||||
if os.path.isdir(os.path.join(forge_dir, 'patches', 'minecraft_server')):
|
||||
apply_patches(os.path.join(forge_dir, 'patches', 'minecraft_server'), src_dir)
|
||||
if os.path.isdir(os.path.join(forge_dir, 'src', 'minecraft_server')):
|
||||
copytree(os.path.join(forge_dir, 'src', 'minecraft_server'), os.path.join(src_dir, 'minecraft_server'))
|
||||
|
||||
os.chdir(mcp_dir)
|
||||
updatemcp(None, True)
|
||||
reset_logger()
|
||||
updatenames(None, True)
|
||||
reset_logger()
|
||||
updatemd5(None, True)
|
||||
reset_logger()
|
||||
os.chdir(forge_dir)
|
||||
|
||||
print '=================================== Minecraft Forge Setup Finished ================================='
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -1,28 +1,28 @@
|
|||
@echo off
|
||||
if "%1"=="" (
|
||||
echo You must enter a build number to promote to the latest
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo Jenkins build script started for build #%1
|
||||
rmdir /S /Q ..\conf
|
||||
xcopy /Y /E /I conf\* ..\conf
|
||||
|
||||
..\runtime\bin\python\python_mcp setup.py -skipdecompile
|
||||
if %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL%
|
||||
|
||||
..\runtime\bin\python\python_mcp release.py %1
|
||||
if %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL%
|
||||
|
||||
cd forge-*%1
|
||||
if %ERRORLEVEL% NEQ 0 (
|
||||
echo Release failed to produce artifacts %1
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
for /f "delims=\" %%a in ("%cd%") do SET VERSION=%%~nxa
|
||||
SET VERSION=%VERSION:~6%
|
||||
echo Forge Version: %VERSION%
|
||||
|
||||
..\..\MediafireUploader.exe Forge-%VERSION% minecraftforge-client-%VERSION%.zip minecraftforge-server-%VERSION%.zip minecraftforge-src-%VERSION%.zip
|
||||
|
||||
@echo off
|
||||
if "%1"=="" (
|
||||
echo You must enter a build number to promote to the latest
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo Jenkins build script started for build #%1
|
||||
rmdir /S /Q ..\conf
|
||||
xcopy /Y /E /I conf\* ..\conf
|
||||
|
||||
..\runtime\bin\python\python_mcp setup.py -skipdecompile
|
||||
if %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL%
|
||||
|
||||
..\runtime\bin\python\python_mcp release.py %1
|
||||
if %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL%
|
||||
|
||||
cd forge-*%1
|
||||
if %ERRORLEVEL% NEQ 0 (
|
||||
echo Release failed to produce artifacts %1
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
for /f "delims=\" %%a in ("%cd%") do SET VERSION=%%~nxa
|
||||
SET VERSION=%VERSION:~6%
|
||||
echo Forge Version: %VERSION%
|
||||
|
||||
..\..\MediafireUploader.exe Forge-%VERSION% minecraftforge-client-%VERSION%.zip minecraftforge-server-%VERSION%.zip minecraftforge-src-%VERSION%.zip
|
||||
|
||||
|
|
406
forge/release.py
406
forge/release.py
|
@ -1,203 +1,203 @@
|
|||
import os, os.path, sys
|
||||
import shutil, fnmatch
|
||||
import logging, zipfile, re
|
||||
|
||||
forge_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
mcp_dir = os.path.abspath('..')
|
||||
src_dir = os.path.join(mcp_dir, 'src')
|
||||
|
||||
sys.path.append(mcp_dir)
|
||||
from runtime.reobfuscate import reobfuscate
|
||||
|
||||
from forge import reset_logger, load_version, zip_folder, zip_create, inject_version
|
||||
from build import build
|
||||
|
||||
reobf_dir = os.path.join(mcp_dir, 'reobf')
|
||||
client_dir = os.path.join(reobf_dir, 'minecraft')
|
||||
server_dir = os.path.join(reobf_dir, 'minecraft_server')
|
||||
zip = None
|
||||
zip_name = None
|
||||
zip_base = None
|
||||
version_str = None
|
||||
|
||||
def main():
|
||||
global version_str
|
||||
build_num = 0
|
||||
if len(sys.argv) > 1:
|
||||
try:
|
||||
build_num = int(sys.argv[1])
|
||||
except:
|
||||
pass
|
||||
ret = 0
|
||||
ret = build(build_num)
|
||||
if ret != 0:
|
||||
sys.exit(ret)
|
||||
|
||||
print '=================================== Release Start ================================='
|
||||
error_level = 0
|
||||
try:
|
||||
os.chdir(mcp_dir)
|
||||
reset_logger()
|
||||
reobfuscate(None, False, True, True)
|
||||
reset_logger()
|
||||
os.chdir(forge_dir)
|
||||
except SystemExit, e:
|
||||
print 'Reobfusicate Exception: %d ' % e.code
|
||||
error_level = e.code
|
||||
|
||||
extract_fml_obfed()
|
||||
version = load_version(build_num)
|
||||
version_str = '%d.%d.%d.%d' % (version['major'], version['minor'], version['revision'], version['build'])
|
||||
|
||||
out_folder = os.path.join(forge_dir, 'forge-%s' % version_str)
|
||||
if os.path.isdir(out_folder):
|
||||
shutil.rmtree(out_folder)
|
||||
|
||||
os.makedirs(out_folder)
|
||||
|
||||
update_info('forge_common/mod_MinecraftForge.info', version_str)
|
||||
|
||||
zip_start('minecraftforge-client-%s.zip' % version_str)
|
||||
zip_folder(client_dir, '', zip)
|
||||
zip_add('forge_common/mod_MinecraftForge.info', 'mod_MinecraftForge.info')
|
||||
zip_add('forge_client/src/forge_logo.png')
|
||||
zip_add('install/MinecraftForge-Credits.txt')
|
||||
zip_add('install/MinecraftForge-License.txt')
|
||||
zip_add('fml/CREDITS-fml.txt')
|
||||
zip_add('fml/LICENSE-fml.txt')
|
||||
zip_add('fml/README-fml.txt')
|
||||
zip_add('fml/src/minecraft/fmlversion.properties')
|
||||
zip_add('install/Paulscode IBXM Library License.txt')
|
||||
zip_add('install/Paulscode SoundSystem CodecIBXM License.txt')
|
||||
zip_end()
|
||||
|
||||
zip_start('minecraftforge-server-%s.zip' % version_str)
|
||||
zip_folder(server_dir, '', zip)
|
||||
zip_add('forge_common/mod_MinecraftForge.info', 'mod_MinecraftForge.info')
|
||||
zip_add('install/MinecraftForge-Credits.txt')
|
||||
zip_add('install/MinecraftForge-License.txt')
|
||||
zip_add('fml/CREDITS-fml.txt')
|
||||
zip_add('fml/LICENSE-fml.txt')
|
||||
zip_add('fml/README-fml.txt')
|
||||
zip_add('fml/src/minecraft_server/fmlversion.properties')
|
||||
zip_end()
|
||||
|
||||
inject_version(os.path.join(forge_dir, 'forge_common', 'net', 'minecraft', 'src', 'forge', 'ForgeHooks.java'), build_num)
|
||||
zip_start('minecraftforge-src-%s.zip' % version_str, 'forge')
|
||||
zip_add('forge_client/src', 'src/minecraft')
|
||||
zip_add('forge_server/src', 'src/minecraft_server')
|
||||
zip_add('forge_common', 'src/minecraft')
|
||||
zip_add('forge_common', 'src/minecraft_server')
|
||||
zip_add('patches', 'patches')
|
||||
zip_add('fml', 'fml')
|
||||
zip_add('conf', 'conf')
|
||||
zip_add('install/install.cmd')
|
||||
zip_add('install/install.sh')
|
||||
zip_add('install/README-MinecraftForge.txt')
|
||||
zip_add('install/install.py')
|
||||
zip_add('forge.py')
|
||||
zip_add('install/MinecraftForge-Credits.txt')
|
||||
zip_add('install/MinecraftForge-License.txt')
|
||||
zip_add('install/Paulscode IBXM Library License.txt')
|
||||
zip_add('install/Paulscode SoundSystem CodecIBXM License.txt')
|
||||
zip_end()
|
||||
inject_version(os.path.join(forge_dir, 'forge_common', 'net', 'minecraft', 'src', 'forge', 'ForgeHooks.java'), 0)
|
||||
|
||||
shutil.move(os.path.join(forge_dir, 'file.backup'), os.path.join(forge_dir, 'forge_common/mod_MinecraftForge.info'.replace('/', os.sep)))
|
||||
|
||||
print '=================================== Release Finished %d =================================' % error_level
|
||||
sys.exit(error_level)
|
||||
|
||||
|
||||
def zip_add(file, key=None):
|
||||
if key == None:
|
||||
key = os.path.basename(file)
|
||||
else:
|
||||
key = key.replace('/', os.sep)
|
||||
if not zip_base is None:
|
||||
key = os.path.join(zip_base, key)
|
||||
file = os.path.join(forge_dir, file.replace('/', os.sep))
|
||||
if os.path.isdir(file):
|
||||
zip_folder(file, key, zip)
|
||||
else:
|
||||
if os.path.isfile(file):
|
||||
print key
|
||||
zip.write(file, key)
|
||||
|
||||
def zip_add_perm(file, perm, key=None):
|
||||
if key == None:
|
||||
key = os.path.basename(file)
|
||||
else:
|
||||
key = key.replace('/', os.sep)
|
||||
if not zip_base is None:
|
||||
key = os.path.join(zip_base, key)
|
||||
file = os.path.join(forge_dir, file.replace('/', os.sep))
|
||||
if os.path.isfile(file):
|
||||
print key
|
||||
#zip.write(file, key)
|
||||
|
||||
with open(file, 'r') as fh: data = fh.read()
|
||||
info = zipfile.ZipInfo(key)
|
||||
info.external_attr = 0777 << 16L
|
||||
zip.writestr(info, data)
|
||||
|
||||
def zip_start(name, base=None):
|
||||
global zip, zip_name, zip_base
|
||||
zip_name = name
|
||||
|
||||
print '=================================== %s Start =================================' % zip_name
|
||||
zip_file = os.path.join(forge_dir, 'forge-%s' % version_str, name)
|
||||
zip = zipfile.ZipFile(zip_file, 'w', zipfile.ZIP_DEFLATED)
|
||||
zip_base = base
|
||||
|
||||
def zip_end():
|
||||
global zip, zip_name, zip_base
|
||||
zip.close()
|
||||
print '=================================== %s Finished =================================' % zip_name
|
||||
zip_name = None
|
||||
zip_base = None
|
||||
|
||||
def update_info(input, version):
|
||||
input = os.path.join(forge_dir, input.replace('/', os.sep))
|
||||
temp = os.path.join(forge_dir, 'file.backup')
|
||||
|
||||
shutil.move(input, temp)
|
||||
|
||||
with open(temp, 'r') as fh:
|
||||
buf = fh.read()
|
||||
|
||||
buf = re.sub(r'{version}', version, buf)
|
||||
|
||||
with open(input, 'w') as fh:
|
||||
fh.write(buf)
|
||||
|
||||
def extract_fml_obfed():
|
||||
fml_file = os.path.join(forge_dir, 'fml', 'difflist.txt')
|
||||
if not os.path.isfile(fml_file):
|
||||
print 'Could not find Forge ModLoader\'s DiffList, looking for it at: %s' % fml_file
|
||||
sys.exit(1)
|
||||
|
||||
with open(fml_file, 'r') as fh:
|
||||
lines = fh.readlines()
|
||||
|
||||
client = zipfile.ZipFile(os.path.join(mcp_dir, 'temp', 'client_reobf.jar'))
|
||||
server = zipfile.ZipFile(os.path.join(mcp_dir, 'temp', 'server_reobf.jar'))
|
||||
|
||||
print 'Extracting Reobfed Forge ModLoader classes'
|
||||
lines.append("minecraft/net/minecraft/client/MinecraftApplet.class") #Needed because users dont install Forge properly -.-
|
||||
|
||||
for line in lines:
|
||||
line = line.replace('\n', '').replace('\r', '').replace('/', os.sep)
|
||||
print line
|
||||
if not os.path.isfile(os.path.join(reobf_dir, line)):
|
||||
side = line.split(os.sep)[0]
|
||||
if side == 'minecraft':
|
||||
client.extract(line[10:].replace(os.sep, '/'), client_dir)
|
||||
else:
|
||||
server.extract(line[17:].replace(os.sep, '/'), server_dir)
|
||||
|
||||
client.close()
|
||||
server.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
import os, os.path, sys
|
||||
import shutil, fnmatch
|
||||
import logging, zipfile, re
|
||||
|
||||
forge_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
mcp_dir = os.path.abspath('..')
|
||||
src_dir = os.path.join(mcp_dir, 'src')
|
||||
|
||||
sys.path.append(mcp_dir)
|
||||
from runtime.reobfuscate import reobfuscate
|
||||
|
||||
from forge import reset_logger, load_version, zip_folder, zip_create, inject_version
|
||||
from build import build
|
||||
|
||||
reobf_dir = os.path.join(mcp_dir, 'reobf')
|
||||
client_dir = os.path.join(reobf_dir, 'minecraft')
|
||||
server_dir = os.path.join(reobf_dir, 'minecraft_server')
|
||||
zip = None
|
||||
zip_name = None
|
||||
zip_base = None
|
||||
version_str = None
|
||||
|
||||
def main():
|
||||
global version_str
|
||||
build_num = 0
|
||||
if len(sys.argv) > 1:
|
||||
try:
|
||||
build_num = int(sys.argv[1])
|
||||
except:
|
||||
pass
|
||||
ret = 0
|
||||
ret = build(build_num)
|
||||
if ret != 0:
|
||||
sys.exit(ret)
|
||||
|
||||
print '=================================== Release Start ================================='
|
||||
error_level = 0
|
||||
try:
|
||||
os.chdir(mcp_dir)
|
||||
reset_logger()
|
||||
reobfuscate(None, False, True, True)
|
||||
reset_logger()
|
||||
os.chdir(forge_dir)
|
||||
except SystemExit, e:
|
||||
print 'Reobfusicate Exception: %d ' % e.code
|
||||
error_level = e.code
|
||||
|
||||
extract_fml_obfed()
|
||||
version = load_version(build_num)
|
||||
version_str = '%d.%d.%d.%d' % (version['major'], version['minor'], version['revision'], version['build'])
|
||||
|
||||
out_folder = os.path.join(forge_dir, 'forge-%s' % version_str)
|
||||
if os.path.isdir(out_folder):
|
||||
shutil.rmtree(out_folder)
|
||||
|
||||
os.makedirs(out_folder)
|
||||
|
||||
update_info('forge_common/mod_MinecraftForge.info', version_str)
|
||||
|
||||
zip_start('minecraftforge-client-%s.zip' % version_str)
|
||||
zip_folder(client_dir, '', zip)
|
||||
zip_add('forge_common/mod_MinecraftForge.info', 'mod_MinecraftForge.info')
|
||||
zip_add('forge_client/src/forge_logo.png')
|
||||
zip_add('install/MinecraftForge-Credits.txt')
|
||||
zip_add('install/MinecraftForge-License.txt')
|
||||
zip_add('fml/CREDITS-fml.txt')
|
||||
zip_add('fml/LICENSE-fml.txt')
|
||||
zip_add('fml/README-fml.txt')
|
||||
zip_add('fml/src/minecraft/fmlversion.properties')
|
||||
zip_add('install/Paulscode IBXM Library License.txt')
|
||||
zip_add('install/Paulscode SoundSystem CodecIBXM License.txt')
|
||||
zip_end()
|
||||
|
||||
zip_start('minecraftforge-server-%s.zip' % version_str)
|
||||
zip_folder(server_dir, '', zip)
|
||||
zip_add('forge_common/mod_MinecraftForge.info', 'mod_MinecraftForge.info')
|
||||
zip_add('install/MinecraftForge-Credits.txt')
|
||||
zip_add('install/MinecraftForge-License.txt')
|
||||
zip_add('fml/CREDITS-fml.txt')
|
||||
zip_add('fml/LICENSE-fml.txt')
|
||||
zip_add('fml/README-fml.txt')
|
||||
zip_add('fml/src/minecraft_server/fmlversion.properties')
|
||||
zip_end()
|
||||
|
||||
inject_version(os.path.join(forge_dir, 'forge_common', 'net', 'minecraft', 'src', 'forge', 'ForgeHooks.java'), build_num)
|
||||
zip_start('minecraftforge-src-%s.zip' % version_str, 'forge')
|
||||
zip_add('forge_client/src', 'src/minecraft')
|
||||
zip_add('forge_server/src', 'src/minecraft_server')
|
||||
zip_add('forge_common', 'src/minecraft')
|
||||
zip_add('forge_common', 'src/minecraft_server')
|
||||
zip_add('patches', 'patches')
|
||||
zip_add('fml', 'fml')
|
||||
zip_add('conf', 'conf')
|
||||
zip_add('install/install.cmd')
|
||||
zip_add('install/install.sh')
|
||||
zip_add('install/README-MinecraftForge.txt')
|
||||
zip_add('install/install.py')
|
||||
zip_add('forge.py')
|
||||
zip_add('install/MinecraftForge-Credits.txt')
|
||||
zip_add('install/MinecraftForge-License.txt')
|
||||
zip_add('install/Paulscode IBXM Library License.txt')
|
||||
zip_add('install/Paulscode SoundSystem CodecIBXM License.txt')
|
||||
zip_end()
|
||||
inject_version(os.path.join(forge_dir, 'forge_common', 'net', 'minecraft', 'src', 'forge', 'ForgeHooks.java'), 0)
|
||||
|
||||
shutil.move(os.path.join(forge_dir, 'file.backup'), os.path.join(forge_dir, 'forge_common/mod_MinecraftForge.info'.replace('/', os.sep)))
|
||||
|
||||
print '=================================== Release Finished %d =================================' % error_level
|
||||
sys.exit(error_level)
|
||||
|
||||
|
||||
def zip_add(file, key=None):
|
||||
if key == None:
|
||||
key = os.path.basename(file)
|
||||
else:
|
||||
key = key.replace('/', os.sep)
|
||||
if not zip_base is None:
|
||||
key = os.path.join(zip_base, key)
|
||||
file = os.path.join(forge_dir, file.replace('/', os.sep))
|
||||
if os.path.isdir(file):
|
||||
zip_folder(file, key, zip)
|
||||
else:
|
||||
if os.path.isfile(file):
|
||||
print key
|
||||
zip.write(file, key)
|
||||
|
||||
def zip_add_perm(file, perm, key=None):
|
||||
if key == None:
|
||||
key = os.path.basename(file)
|
||||
else:
|
||||
key = key.replace('/', os.sep)
|
||||
if not zip_base is None:
|
||||
key = os.path.join(zip_base, key)
|
||||
file = os.path.join(forge_dir, file.replace('/', os.sep))
|
||||
if os.path.isfile(file):
|
||||
print key
|
||||
#zip.write(file, key)
|
||||
|
||||
with open(file, 'r') as fh: data = fh.read()
|
||||
info = zipfile.ZipInfo(key)
|
||||
info.external_attr = 0777 << 16L
|
||||
zip.writestr(info, data)
|
||||
|
||||
def zip_start(name, base=None):
|
||||
global zip, zip_name, zip_base
|
||||
zip_name = name
|
||||
|
||||
print '=================================== %s Start =================================' % zip_name
|
||||
zip_file = os.path.join(forge_dir, 'forge-%s' % version_str, name)
|
||||
zip = zipfile.ZipFile(zip_file, 'w', zipfile.ZIP_DEFLATED)
|
||||
zip_base = base
|
||||
|
||||
def zip_end():
|
||||
global zip, zip_name, zip_base
|
||||
zip.close()
|
||||
print '=================================== %s Finished =================================' % zip_name
|
||||
zip_name = None
|
||||
zip_base = None
|
||||
|
||||
def update_info(input, version):
|
||||
input = os.path.join(forge_dir, input.replace('/', os.sep))
|
||||
temp = os.path.join(forge_dir, 'file.backup')
|
||||
|
||||
shutil.move(input, temp)
|
||||
|
||||
with open(temp, 'r') as fh:
|
||||
buf = fh.read()
|
||||
|
||||
buf = re.sub(r'{version}', version, buf)
|
||||
|
||||
with open(input, 'w') as fh:
|
||||
fh.write(buf)
|
||||
|
||||
def extract_fml_obfed():
|
||||
fml_file = os.path.join(forge_dir, 'fml', 'difflist.txt')
|
||||
if not os.path.isfile(fml_file):
|
||||
print 'Could not find Forge ModLoader\'s DiffList, looking for it at: %s' % fml_file
|
||||
sys.exit(1)
|
||||
|
||||
with open(fml_file, 'r') as fh:
|
||||
lines = fh.readlines()
|
||||
|
||||
client = zipfile.ZipFile(os.path.join(mcp_dir, 'temp', 'client_reobf.jar'))
|
||||
server = zipfile.ZipFile(os.path.join(mcp_dir, 'temp', 'server_reobf.jar'))
|
||||
|
||||
print 'Extracting Reobfed Forge ModLoader classes'
|
||||
lines.append("minecraft/net/minecraft/client/MinecraftApplet.class") #Needed because users dont install Forge properly -.-
|
||||
|
||||
for line in lines:
|
||||
line = line.replace('\n', '').replace('\r', '').replace('/', os.sep)
|
||||
print line
|
||||
if not os.path.isfile(os.path.join(reobf_dir, line)):
|
||||
side = line.split(os.sep)[0]
|
||||
if side == 'minecraft':
|
||||
client.extract(line[10:].replace(os.sep, '/'), client_dir)
|
||||
else:
|
||||
server.extract(line[17:].replace(os.sep, '/'), server_dir)
|
||||
|
||||
client.close()
|
||||
server.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
@echo off
|
||||
..\runtime\bin\python\python_mcp setup.py %*
|
||||
if NOT "%1"=="-skipdecompile" (
|
||||
pause
|
||||
@echo off
|
||||
..\runtime\bin\python\python_mcp setup.py %*
|
||||
if NOT "%1"=="-skipdecompile" (
|
||||
pause
|
||||
)
|
202
forge/setup.py
202
forge/setup.py
|
@ -1,102 +1,102 @@
|
|||
import os, os.path, sys
|
||||
import urllib, zipfile
|
||||
import shutil, glob, fnmatch
|
||||
import subprocess, logging
|
||||
|
||||
forge_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
mcp_dir = os.path.abspath('..')
|
||||
src_dir = os.path.join(mcp_dir, 'src')
|
||||
|
||||
sys.path.append(mcp_dir)
|
||||
from runtime.decompile import decompile
|
||||
from runtime.updatenames import updatenames
|
||||
from runtime.updatemd5 import updatemd5
|
||||
|
||||
from forge import apply_patches, copytree, reset_logger, download_ff, cleanup_source, pre_decompile, post_decompile
|
||||
|
||||
|
||||
def main():
|
||||
print '=================================== Setup Start ================================='
|
||||
|
||||
skipDecompile = len(sys.argv) > 1 and sys.argv[1] == '-skipdecompile'
|
||||
if not skipDecompile:
|
||||
if not download_ff(mcp_dir):
|
||||
sys.exit(1)
|
||||
|
||||
if os.path.isdir(src_dir):
|
||||
shutil.rmtree(src_dir)
|
||||
|
||||
try:
|
||||
|
||||
pre_decompile()
|
||||
|
||||
os.chdir(mcp_dir)
|
||||
# Conf JAD CSV -r -d -a -n -p -o -l -g
|
||||
decompile(None, False, False, True, True, False, True, False, False, False, False)
|
||||
reset_logger()
|
||||
os.chdir(forge_dir)
|
||||
|
||||
post_decompile()
|
||||
|
||||
except SystemExit, e:
|
||||
print 'Decompile Exception: %d ' % e.code
|
||||
raise e
|
||||
|
||||
if not os.path.isdir(src_dir):
|
||||
print 'Something went wrong, src folder not found at: %s' % src_dir
|
||||
sys.exit(1)
|
||||
|
||||
cleanup_source(src_dir)
|
||||
|
||||
setup_fml()
|
||||
|
||||
os.chdir(mcp_dir)
|
||||
updatenames(None, True)
|
||||
reset_logger()
|
||||
updatemd5(None, True)
|
||||
reset_logger()
|
||||
os.chdir(forge_dir)
|
||||
|
||||
base_dir = os.path.join(mcp_dir, 'src_base')
|
||||
work_dir = os.path.join(mcp_dir, 'src_work')
|
||||
|
||||
if os.path.isdir(base_dir):
|
||||
shutil.rmtree(base_dir)
|
||||
if os.path.isdir(work_dir):
|
||||
shutil.rmtree(work_dir)
|
||||
|
||||
print 'Setting up source directories'
|
||||
shutil.copytree(src_dir, base_dir)
|
||||
shutil.copytree(src_dir, work_dir)
|
||||
|
||||
print 'Applying forge patches'
|
||||
apply_patches(os.path.join(forge_dir, 'patches'), work_dir)
|
||||
|
||||
print '=================================== Setup Finished ================================='
|
||||
|
||||
def setup_fml():
|
||||
print 'Setting up Forge ModLoader'
|
||||
fml = glob.glob(os.path.join(forge_dir, 'fml-src-*.zip'))
|
||||
if not len(fml) == 1:
|
||||
if len(fml) == 0:
|
||||
print 'Missing FML source zip, should be named fml-src-*.zip inside your forge folder, obtain it from the repo'
|
||||
else:
|
||||
print 'To many FML source zips found, we should only have one. Check the Forge Git for the latest FML version supported'
|
||||
sys.exit(1)
|
||||
|
||||
fml_dir = os.path.join(forge_dir, 'fml')
|
||||
if os.path.isdir(fml_dir):
|
||||
shutil.rmtree(fml_dir)
|
||||
|
||||
print 'Extracting: %s' % os.path.basename(fml[0])
|
||||
|
||||
zf = zipfile.ZipFile(fml[0])
|
||||
zf.extractall(forge_dir)
|
||||
zf.close()
|
||||
|
||||
print 'Applying Forge ModLoader patches'
|
||||
apply_patches(os.path.join(fml_dir, 'patches'), src_dir)
|
||||
copytree(os.path.join(fml_dir, 'src'), src_dir)
|
||||
|
||||
if __name__ == '__main__':
|
||||
import os, os.path, sys
|
||||
import urllib, zipfile
|
||||
import shutil, glob, fnmatch
|
||||
import subprocess, logging
|
||||
|
||||
forge_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
mcp_dir = os.path.abspath('..')
|
||||
src_dir = os.path.join(mcp_dir, 'src')
|
||||
|
||||
sys.path.append(mcp_dir)
|
||||
from runtime.decompile import decompile
|
||||
from runtime.updatenames import updatenames
|
||||
from runtime.updatemd5 import updatemd5
|
||||
|
||||
from forge import apply_patches, copytree, reset_logger, download_ff, cleanup_source, pre_decompile, post_decompile
|
||||
|
||||
|
||||
def main():
|
||||
print '=================================== Setup Start ================================='
|
||||
|
||||
skipDecompile = len(sys.argv) > 1 and sys.argv[1] == '-skipdecompile'
|
||||
if not skipDecompile:
|
||||
if not download_ff(mcp_dir):
|
||||
sys.exit(1)
|
||||
|
||||
if os.path.isdir(src_dir):
|
||||
shutil.rmtree(src_dir)
|
||||
|
||||
try:
|
||||
|
||||
pre_decompile()
|
||||
|
||||
os.chdir(mcp_dir)
|
||||
# Conf JAD CSV -r -d -a -n -p -o -l -g
|
||||
decompile(None, False, False, True, True, False, True, False, False, False, False)
|
||||
reset_logger()
|
||||
os.chdir(forge_dir)
|
||||
|
||||
post_decompile()
|
||||
|
||||
except SystemExit, e:
|
||||
print 'Decompile Exception: %d ' % e.code
|
||||
raise e
|
||||
|
||||
if not os.path.isdir(src_dir):
|
||||
print 'Something went wrong, src folder not found at: %s' % src_dir
|
||||
sys.exit(1)
|
||||
|
||||
cleanup_source(src_dir)
|
||||
|
||||
setup_fml()
|
||||
|
||||
os.chdir(mcp_dir)
|
||||
updatenames(None, True)
|
||||
reset_logger()
|
||||
updatemd5(None, True)
|
||||
reset_logger()
|
||||
os.chdir(forge_dir)
|
||||
|
||||
base_dir = os.path.join(mcp_dir, 'src_base')
|
||||
work_dir = os.path.join(mcp_dir, 'src_work')
|
||||
|
||||
if os.path.isdir(base_dir):
|
||||
shutil.rmtree(base_dir)
|
||||
if os.path.isdir(work_dir):
|
||||
shutil.rmtree(work_dir)
|
||||
|
||||
print 'Setting up source directories'
|
||||
shutil.copytree(src_dir, base_dir)
|
||||
shutil.copytree(src_dir, work_dir)
|
||||
|
||||
print 'Applying forge patches'
|
||||
apply_patches(os.path.join(forge_dir, 'patches'), work_dir)
|
||||
|
||||
print '=================================== Setup Finished ================================='
|
||||
|
||||
def setup_fml():
|
||||
print 'Setting up Forge ModLoader'
|
||||
fml = glob.glob(os.path.join(forge_dir, 'fml-src-*.zip'))
|
||||
if not len(fml) == 1:
|
||||
if len(fml) == 0:
|
||||
print 'Missing FML source zip, should be named fml-src-*.zip inside your forge folder, obtain it from the repo'
|
||||
else:
|
||||
print 'To many FML source zips found, we should only have one. Check the Forge Git for the latest FML version supported'
|
||||
sys.exit(1)
|
||||
|
||||
fml_dir = os.path.join(forge_dir, 'fml')
|
||||
if os.path.isdir(fml_dir):
|
||||
shutil.rmtree(fml_dir)
|
||||
|
||||
print 'Extracting: %s' % os.path.basename(fml[0])
|
||||
|
||||
zf = zipfile.ZipFile(fml[0])
|
||||
zf.extractall(forge_dir)
|
||||
zf.close()
|
||||
|
||||
print 'Applying Forge ModLoader patches'
|
||||
apply_patches(os.path.join(fml_dir, 'patches'), src_dir)
|
||||
copytree(os.path.join(fml_dir, 'src'), src_dir)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -1,3 +1,3 @@
|
|||
@echo off
|
||||
set PATH=.\bin;%PATH%
|
||||
..\runtime\bin\python\python_mcp update_patches.py
|
||||
@echo off
|
||||
set PATH=.\bin;%PATH%
|
||||
..\runtime\bin\python\python_mcp update_patches.py
|
||||
|
|
Loading…
Reference in a new issue