Compare commits

..
2 Commits
Author SHA1 Message Date
Space Toad eac172d806 merged with trunk 2012-01-15 23:44:46 +00:00
Space Toad dbd6af437c tagged 1.3.0 2012-01-15 19:29:54 +00:00
565 changed files with 32137 additions and 34611 deletions

No files matched your search

-7
View File
@@ -1,7 +0,0 @@
* text eol=lf
*.bat text eol=crlf
*.patch text
*.png binary
*.exe binary
*.dll binary
*.zip binary
-7
View File
@@ -1,7 +0,0 @@
*.DS_Store
/logs/
/*.pyc
/forge-*/
/patches-old/
/mcp/
/eclipse/
-3
View File
@@ -1,3 +0,0 @@
[submodule "fml"]
path = fml
url = https://github.com/MinecraftForge/FML.git
-6
View File
@@ -1,6 +0,0 @@
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.8.2
Created-By: 1.7.0_09-b30 (Oracle Corporation)
Main-Class: net.minecraft.server.MinecraftServer
Class-Path: minecraft_server.jar
-34
View File
@@ -1,34 +0,0 @@
import os, os.path, sys
from optparse import OptionParser
forge_dir = os.path.dirname(os.path.abspath(__file__))
mcp_dir = os.path.abspath('..')
from forge import build_forge_dev
def main():
parser = OptionParser()
parser.add_option('-m', '--mcp-dir', action='store', dest='mcp_dir', help='MCP Path', default=None)
parser.add_option('-b', '--build', action='store', dest='build', help='Build number', default=None)
options, _ = parser.parse_args()
build_num = 0
if not options.build is None:
try:
build_num = int(options.build)
except:
pass
fml_dir = os.path.join(forge_dir, 'fml')
mcp_dir = os.path.join(forge_dir, 'mcp')
if not options.mcp_dir is None:
mcp_dir = os.path.abspath(options.mcp_dir)
elif os.path.isfile(os.path.join('..', 'runtime', 'commands.py')):
mcp_dir = os.path.abspath('..')
sys.exit(build_forge_dev(mcp_dir, forge_dir, fml_dir, build_num))
if __name__ == '__main__':
main()
-89
View File
@@ -1,89 +0,0 @@
import os, os.path, sys, re
import json, urllib2
from pprint import pprint
from urlparse import urlparse
import base64
import optparse, ast
class PreemptiveBasicAuthHandler(urllib2.BaseHandler):
def __init__(self, password_mgr=None):
if password_mgr is None:
password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
self.passwd = password_mgr
self.add_password = self.passwd.add_password
def http_request(self,req):
uri = req.get_full_url()
user, pw = self.passwd.find_user_password(None,uri)
if pw is None: return req
raw = "%s:%s" % (user, pw)
auth = 'Basic %s' % base64.b64encode(raw).strip()
req.add_unredirected_header('Authorization', auth)
return req
def https_request(self,req):
return self.http_request(req)
def getBuildInfo(url, current_version=None):
handler = PreemptiveBasicAuthHandler()
handler.add_password(None, 'jenkins.minecraftforge.net:81', 'console_script', 'fd584bffa72fcac12181f37f80001200')
file = urllib2.build_opener(handler).open(url)
data = file.read()
file.close()
data = ast.literal_eval(data)['allBuilds']
data = sorted(data, key=lambda key: key['number'], reverse=False)
items = []
output = []
for build in data:
build['actions'] = filter(lambda act: act is not None, build['actions'])
build['actions'] = filter(lambda act: 'text' in act, build['actions'])
build['actions'] = filter(lambda act: not ' ' in act['text'], build['actions'])
if len(build['actions']) == 0:
build['version'] = current_version
current_version = None
else:
build['version'] = build['actions'][0]['text']
build['items'] = build['changeSet']['items']
for item in build['items']:
item['author'] = item['author']['fullName']
if build['result'] != 'SUCCESS':
items += build['items']
else:
build['items'] = items + build['items']
items = []
output += [build]
build.pop('changeSet')
build.pop('actions')
return sorted(output, key=lambda key: key['number'], reverse=True)
def make_changelog(job_path, target_build, change_file, current_version=None):
builds = getBuildInfo('%s/api/python?tree=allBuilds[result,number,actions[text],changeSet[items[author[fullName],comment]]]&pretty=true' % job_path, current_version)
log = [ "Changelog:" ]
for build in builds:
if int(build['number']) > target_build: continue
if len(build['items']) == 0: continue
log.append('')
if build['version'] is None:
log.append('Build %s' % build['number'])
else:
log.append('Build %s' % build['version'])
for change in build['items']:
comments = filter(lambda cmt: len(cmt) > 0, change['comment'].split('\n'))
if len(comments) > 1:
log.append('\t' + change['author'])
for comment in comments:
log.append('\t\t' + comment)
elif len(comments) == 1:
log.append('\t%s: %s' % (change['author'], comments[0]))
file = open(change_file, 'wb')
for line in log:
file.write('%s\n' % line)
file.close()
if __name__ == '__main__':
make_changelog("http://jenkins.minecraftforge.net:81/job/minecraftforge/", 70000, 'changelog.txt', 'pinecone')
Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

-946
View File
@@ -1,946 +0,0 @@
package ibxm;
public class Channel {
public int pattern_loop_row;
private Module module;
private Instrument instrument;
private Sample sample;
private int[] global_volume, current_note;
private boolean linear_periods, fast_volume_slides, key_on, silent;
private int sample_idx, sample_frac, step, left_gain, right_gain;
private int volume, panning, fine_tune, period, porta_period, key_add;
private int tremolo_speed, tremolo_depth, tremolo_tick, tremolo_wave, tremolo_add;
private int vibrato_speed, vibrato_depth, vibrato_tick, vibrato_wave, vibrato_add;
private int volume_slide_param, portamento_param, retrig_param;
private int volume_envelope_tick, panning_envelope_tick;
private int effect_tick, trigger_tick, fade_out_volume, random_seed;
private int log_2_sampling_rate;
private static final int LOG_2_29024 = LogTable.log_2( 29024 );
private static final int LOG_2_8287 = LogTable.log_2( 8287 );
private static final int LOG_2_8363 = LogTable.log_2( 8363 );
private static final int LOG_2_1712 = LogTable.log_2( 1712 );
private static final int[] sine_table = new int[] {
0, 24 , 49, 74, 97, 120, 141, 161, 180, 197, 212, 224, 235, 244, 250, 253,
255, 253, 250, 244, 235, 224, 212, 197, 180, 161, 141, 120, 97, 74, 49, 24
};
public Channel( Module mod, int sampling_rate, int[] global_vol ) {
module = mod;
global_volume = global_vol;
linear_periods = module.linear_periods;
fast_volume_slides = module.fast_volume_slides;
current_note = new int[ 5 ];
log_2_sampling_rate = LogTable.log_2( sampling_rate );
}
public void reset() {
tremolo_speed = 0;
tremolo_depth = 0;
tremolo_wave = 0;
vibrato_speed = 0;
vibrato_depth = 0;
vibrato_wave = 0;
volume_slide_param = 0;
portamento_param = 0;
retrig_param = 0;
random_seed = 0xABC123;
instrument = module.get_instrument( 0 );
row( 48, 256, 0, 0, 0 );
}
public void resample( int[] mixing_buffer, int frame_offset, int frames, int quality ) {
if( !silent ) {
switch( quality ) {
default:
sample.resample_nearest( sample_idx, sample_frac, step, left_gain, right_gain, mixing_buffer, frame_offset, frames );
break;
case 1:
sample.resample_linear( sample_idx, sample_frac, step, left_gain, right_gain, mixing_buffer, frame_offset, frames );
break;
case 2:
sample.resample_sinc( sample_idx, sample_frac, step, left_gain, right_gain, mixing_buffer, frame_offset, frames );
break;
}
}
}
public void update_sample_idx( int samples ) {
sample_frac += step * samples;
sample_idx += sample_frac >> IBXM.FP_SHIFT;
sample_frac &= IBXM.FP_MASK;
}
public void set_volume( int vol ) {
if( vol < 0 ) {
vol = 0;
}
if( vol > 64 ) {
vol = 64;
}
volume = vol;
}
public void set_panning( int pan ) {
if( pan < 0 ) {
pan = 0;
}
if( pan > 255 ) {
pan = 255;
}
panning = pan;
}
public void row( int key, int inst_idx, int volume_column, int effect, int effect_param ) {
effect = effect & 0xFF;
if( effect >= 0x30 ) {
/* Effects above 0x30 are internal.*/
effect = 0;
}
if( effect == 0x00 && effect_param != 0 ) {
/* Arpeggio.*/
effect = 0x40;
}
if( effect == 0x0E ) {
/* Renumber 0x0Ex effect command.*/
effect = 0x30 + ( ( effect_param & 0xF0 ) >> 4 );
effect_param = effect_param & 0x0F;
}
if( effect == 0x21 ) {
/* Renumber 0x21x effect command.*/
effect = 0x40 + ( ( effect_param & 0xF0 ) >> 4 );
effect_param = effect_param & 0x0F;
}
current_note[ 0 ] = key;
current_note[ 1 ] = inst_idx;
current_note[ 2 ] = volume_column;
current_note[ 3 ] = effect;
current_note[ 4 ] = effect_param;
effect_tick = 0;
trigger_tick += 1;
update_envelopes();
key_add = 0;
vibrato_add = 0;
tremolo_add = 0;
if( ! ( effect == 0x3D && effect_param > 0 ) ) {
/* Not note delay.*/
trigger( key, inst_idx, volume_column, effect );
/* Handle volume column.*/
switch( volume_column & 0xF0 ) {
case 0x00:
/* Do nothing.*/
break;
case 0x60:
/* Volume slide down.*/
break;
case 0x70:
/* Volume slide up.*/
break;
case 0x80:
/* Fine volume slide down.*/
set_volume( volume - ( volume_column & 0x0F ) );
break;
case 0x90:
/* Fine volume slide up.*/
set_volume( volume + ( volume_column & 0x0F ) );
break;
case 0xA0:
/* Set vibrato speed.*/
set_vibrato_speed( volume_column & 0x0F );
break;
case 0xB0:
/* Vibrato.*/
set_vibrato_depth( volume_column & 0x0F );
vibrato();
break;
case 0xC0:
/* Set panning.*/
set_panning( ( volume_column & 0x0F ) << 4 );
break;
case 0xD0:
/* Panning slide left.*/
break;
case 0xE0:
/* Panning slide right.*/
break;
case 0xF0:
/* Tone portamento.*/
set_portamento_param( volume_column & 0x0F );
break;
default:
/* Set volume.*/
set_volume( volume_column - 0x10 );
break;
}
}
if( instrument.vibrato_depth > 0 ) {
auto_vibrato();
}
switch( effect ) {
case 0x01:
/* Portmento Up.*/
set_portamento_param( effect_param );
portamento_up();
break;
case 0x02:
/* Portamento Down.*/
set_portamento_param( effect_param );
portamento_down();
break;
case 0x03:
/* Tone Portamento.*/
set_portamento_param( effect_param );
break;
case 0x04:
/* Vibrato.*/
set_vibrato_speed( ( effect_param & 0xF0 ) >> 4 );
set_vibrato_depth( effect_param & 0x0F );
vibrato();
break;
case 0x05:
/* Tone Portamento + Volume Slide.*/
set_volume_slide_param( effect_param );
volume_slide();
break;
case 0x06:
/* Vibrato + Volume Slide.*/
set_volume_slide_param( effect_param );
vibrato();
volume_slide();
break;
case 0x07:
/* Tremolo.*/
set_tremolo_speed( ( effect_param & 0xF0 ) >> 4 );
set_tremolo_depth( effect_param & 0x0F );
tremolo();
break;
case 0x08:
/* Set Panning.*/
set_panning( effect_param );
break;
case 0x09:
/* Set Sample Index.*/
set_sample_index( effect_param << 8 );
break;
case 0x0A:
/* Volume Slide.*/
set_volume_slide_param( effect_param );
volume_slide();
break;
case 0x0B:
/* Pattern Jump.*/
break;
case 0x0C:
/* Set volume.*/
set_volume( effect_param );
break;
case 0x0D:
/* Pattern Break.*/
break;
case 0x0E:
/* Extended Commands (See 0x30-0x3F).*/
break;
case 0x0F:
/* Set Speed/Tempo.*/
break;
case 0x10:
/* Set Global Volume.*/
set_global_volume( effect_param );
break;
case 0x11:
/* global Volume Slide.*/
set_volume_slide_param( effect_param );
break;
case 0x14:
/* Key Off*/
if( effect_param == 0 ) {
key_on = false;
}
break;
case 0x15:
/* Set Envelope Tick.*/
set_envelope_tick( effect_param );
break;
case 0x19:
/* Panning Slide.*/
set_volume_slide_param( effect_param );
break;
case 0x1B:
/* Retrig + Volume Slide.*/
set_retrig_param( effect_param );
retrig_volume_slide();
break;
case 0x1D:
/* Tremor.*/
set_retrig_param( effect_param );
tremor();
break;
case 0x24:
/* S3M Fine Vibrato.*/
set_vibrato_speed( ( effect_param & 0xF0 ) >> 4 );
set_vibrato_depth( effect_param & 0x0F );
fine_vibrato();
break;
case 0x25:
/* S3M Set Speed.*/
break;
case 0x30:
/* Amiga Set Filter.*/
break;
case 0x31:
/* Fine Portamento Up.*/
set_portamento_param( 0xF0 | effect_param );
portamento_up();
break;
case 0x32:
/* Fine Portamento Down.*/
set_portamento_param( 0xF0 | effect_param );
portamento_down();
break;
case 0x33:
/* Set Glissando Mode.*/
break;
case 0x34:
/* Set Vibrato Waveform.*/
set_vibrato_wave( effect_param );
break;
case 0x35:
/* Set Fine Tune.*/
break;
case 0x36:
/* Pattern Loop.*/
break;
case 0x37:
/* Set Tremolo Waveform.*/
set_tremolo_wave( effect_param );
break;
case 0x38:
/* Set Panning(Obsolete).*/
break;
case 0x39:
/* Retrig.*/
set_retrig_param( effect_param );
break;
case 0x3A:
/* Fine Volume Slide Up.*/
set_volume_slide_param( ( effect_param << 4 ) | 0x0F );
volume_slide();
break;
case 0x3B:
/* Fine Volume Slide Down.*/
set_volume_slide_param( 0xF0 | effect_param );
volume_slide();
break;
case 0x3C:
/* Note Cut.*/
if( effect_param == 0 ) {
set_volume( 0 );
}
break;
case 0x3D:
/* Note Delay.*/
break;
case 0x3E:
/* Pattern Delay.*/
break;
case 0x3F:
/* Invert Loop.*/
break;
case 0x40:
/* Arpeggio.*/
break;
case 0x41:
/* Extra Fine Porta Up.*/
set_portamento_param( 0xE0 | effect_param );
portamento_up();
break;
case 0x42:
/* Extra Fine Porta Down.*/
set_portamento_param( 0xE0 | effect_param );
portamento_down();
break;
}
calculate_amplitude();
calculate_frequency();
}
public void tick() {
int volume_column, effect, effect_param;
volume_column = current_note[ 2 ];
effect = current_note[ 3 ];
effect_param = current_note[ 4 ];
effect_tick += 1;
if( effect == 0x3D && effect_param == effect_tick ) {
/* Note delay.*/
row( current_note[ 0 ], current_note[ 1 ], volume_column, 0, 0 );
} else {
trigger_tick += 1;
vibrato_tick += 1;
tremolo_tick += 1;
update_envelopes();
key_add = 0;
vibrato_add = 0;
tremolo_add = 0;
if( instrument.vibrato_depth > 0 ) {
auto_vibrato();
}
switch( volume_column & 0xF0 ) {
case 0x60:
/* Volume Slide Down.*/
set_volume( volume - ( volume_column & 0x0F ) );
break;
case 0x70:
/* Volume Slide Up.*/
set_volume( volume + ( volume_column & 0x0F ) );
break;
case 0xB0:
/* Vibrato.*/
vibrato();
break;
case 0xD0:
/* Panning Slide Left.*/
set_panning( panning - ( volume_column & 0x0F ) );
break;
case 0xE0:
/* Panning Slide Right.*/
set_panning( panning + ( volume_column & 0x0F ) );
break;
case 0xF0:
/* Tone Portamento.*/
tone_portamento();
break;
}
switch( effect ) {
case 0x01:
/* Portamento Up.*/
portamento_up();
break;
case 0x02:
/* Portamento Down.*/
portamento_down();
break;
case 0x03:
/* Tone Portamento.*/
tone_portamento();
break;
case 0x04:
/* Vibrato.*/
vibrato();
break;
case 0x05:
/* Tone Portamento + Volume Slide.*/
tone_portamento();
volume_slide();
break;
case 0x06:
/* Vibrato + Volume Slide */
vibrato();
volume_slide();
break;
case 0x07:
/* Tremolo.*/
tremolo();
break;
case 0x0A:
/* Volume Slide.*/
volume_slide();
break;
case 0x11:
/* Global Volume Slide.*/
global_volume_slide();
break;
case 0x14:
/* Key off.*/
if( effect_tick == effect_param ) {
key_on = false;
}
break;
case 0x19:
/* Panning Slide.*/
panning_slide();
break;
case 0x1B:
/* Retrig + Volume Slide.*/
retrig_volume_slide();
break;
case 0x1D:
/* Tremor.*/
tremor();
break;
case 0x24:
/* S3M Fine Vibrato.*/
fine_vibrato();
break;
case 0x39:
/* Retrig.*/
retrig_volume_slide();
break;
case 0x3C:
/* Note Cut.*/
if( effect_tick == effect_param ) {
set_volume( 0 );
}
break;
case 0x40:
/* Arpeggio.*/
switch( effect_tick % 3 ) {
case 1:
key_add = ( effect_param & 0xF0 ) >> 4;
break;
case 2:
key_add = effect_param & 0x0F;
break;
}
break;
}
}
calculate_amplitude();
calculate_frequency();
}
private void set_vibrato_speed( int speed ) {
if( speed > 0 ) {
vibrato_speed = speed;
}
}
private void set_vibrato_depth( int depth ) {
if( depth > 0 ) {
vibrato_depth = depth;
}
}
private void set_vibrato_wave( int wave ) {
if( wave < 0 || wave > 7 ) {
wave = 0;
}
vibrato_wave = wave;
}
private void set_tremolo_speed( int speed ) {
if( speed > 0 ) {
tremolo_speed = speed;
}
}
private void set_tremolo_depth( int depth ) {
if( depth > 0 ) {
tremolo_depth = depth;
}
}
private void set_tremolo_wave( int wave ) {
if( wave < 0 || wave > 7 ) {
wave = 0;
}
tremolo_wave = wave;
}
private void vibrato() {
int vibrato_phase;
vibrato_phase = vibrato_tick * vibrato_speed;
vibrato_add += waveform( vibrato_phase, vibrato_wave ) * vibrato_depth >> 5;
}
private void fine_vibrato() {
int vibrato_phase;
vibrato_phase = vibrato_tick * vibrato_speed;
vibrato_add += waveform( vibrato_phase, vibrato_wave ) * vibrato_depth >> 7;
}
private void tremolo() {
int tremolo_phase;
tremolo_phase = tremolo_tick * tremolo_speed;
tremolo_add += waveform( tremolo_phase, tremolo_wave ) * tremolo_depth >> 6;
}
private void set_portamento_param( int param ) {
if( param != 0 ) {
portamento_param = param;
}
}
private void tone_portamento() {
int new_period;
if( porta_period < period ) {
new_period = period - ( portamento_param << 2 );
if( new_period < porta_period ) {
new_period = porta_period;
}
set_period( new_period );
}
if( porta_period > period ) {
new_period = period + ( portamento_param << 2 );
if( new_period > porta_period ) {
new_period = porta_period;
}
set_period( new_period );
}
}
private void portamento_up() {
if( ( portamento_param & 0xF0 ) == 0xE0 ) {
/* Extra-fine porta.*/
if( effect_tick == 0 ) {
set_period( period - ( portamento_param & 0x0F ) );
}
} else if( ( portamento_param & 0xF0 ) == 0xF0 ) {
/* Fine porta.*/
if( effect_tick == 0 ) {
set_period( period - ( ( portamento_param & 0x0F ) << 2 ) );
}
} else {
/* Normal porta.*/
if( effect_tick > 0 ) {
set_period( period - ( portamento_param << 2 ) );
}
}
}
private void portamento_down() {
if( ( portamento_param & 0xF0 ) == 0xE0 ) {
/* Extra-fine porta.*/
if( effect_tick == 0 ) {
set_period( period + ( portamento_param & 0x0F ) );
}
} else if( ( portamento_param & 0xF0 ) == 0xF0 ) {
/* Fine porta.*/
if( effect_tick == 0 ) {
set_period( period + ( ( portamento_param & 0x0F ) << 2 ) );
}
} else {
/* Normal porta.*/
if( effect_tick > 0 ) {
set_period( period + ( portamento_param << 2 ) );
}
}
}
private void set_period( int p ) {
if( p < 32 ) {
p = 32;
}
if( p > 32768 ) {
p = 32768;
}
period = p;
}
private void set_global_volume( int vol ) {
if( vol < 0 ) {
vol = 0;
}
if( vol > 64 ) {
vol = 64;
}
global_volume[ 0 ] = vol;
}
private void set_volume_slide_param( int param ) {
if( param != 0 ) {
volume_slide_param = param;
}
}
private void global_volume_slide() {
int up, down;
up = ( volume_slide_param & 0xF0 ) >> 4;
down = volume_slide_param & 0x0F;
set_global_volume( global_volume[ 0 ] + up - down );
}
private void volume_slide() {
int up, down;
up = ( volume_slide_param & 0xF0 ) >> 4;
down = volume_slide_param & 0x0F;
if( down == 0x0F && up > 0 ) {
/* Fine slide up.*/
if( effect_tick == 0 ) {
set_volume( volume + up );
}
} else if( up == 0x0F && down > 0 ) {
/* Fine slide down.*/
if( effect_tick == 0 ) {
set_volume( volume - down );
}
} else {
/* Normal slide.*/
if( effect_tick > 0 || fast_volume_slides ) {
set_volume( volume + up - down );
}
}
}
private void panning_slide() {
int left, right;
left = ( volume_slide_param & 0xF0 ) >> 4;
right = volume_slide_param & 0x0F;
set_panning( panning - left + right );
}
private void set_retrig_param( int param ) {
if( param != 0 ) {
retrig_param = param;
}
}
private void tremor() {
int on_ticks, cycle_length, cycle_index;
on_ticks = ( ( retrig_param & 0xF0 ) >> 4 ) + 1;
cycle_length = on_ticks + ( retrig_param & 0x0F ) + 1;
cycle_index = trigger_tick % cycle_length;
if( cycle_index >= on_ticks ) {
tremolo_add = -64;
}
}
private void retrig_volume_slide() {
int retrig_volume, retrig_tick;
retrig_volume = ( retrig_param & 0xF0 ) >> 4;
retrig_tick = retrig_param & 0x0F;
if( retrig_tick > 0 && ( trigger_tick % retrig_tick ) == 0 ) {
set_sample_index( 0 );
switch( retrig_volume ) {
case 0x01:
set_volume( volume - 1 );
break;
case 0x02:
set_volume( volume - 2 );
break;
case 0x03:
set_volume( volume - 4 );
break;
case 0x04:
set_volume( volume - 8 );
break;
case 0x05:
set_volume( volume - 16 );
break;
case 0x06:
set_volume( volume - volume / 3 );
break;
case 0x07:
set_volume( volume / 2 );
break;
case 0x09:
set_volume( volume + 1 );
break;
case 0x0A:
set_volume( volume + 2 );
break;
case 0x0B:
set_volume( volume + 4 );
break;
case 0x0C:
set_volume( volume + 8 );
break;
case 0x0D:
set_volume( volume + 16 );
break;
case 0x0E:
set_volume( volume + volume / 2 );
break;
case 0x0F:
set_volume( volume * 2 );
break;
}
}
}
private void set_sample_index( int index ) {
if( index < 0 ) {
index = 0;
}
sample_idx = index;
sample_frac = 0;
}
private void set_envelope_tick( int tick ) {
volume_envelope_tick = tick;
panning_envelope_tick = tick;
}
private void trigger( int key, int instrument_idx, int volume_column, int effect ) {
if( instrument_idx > 0 ) {
instrument = module.get_instrument( instrument_idx );
sample = instrument.get_sample_from_key( key );
set_volume( sample.volume );
if( sample.set_panning ) {
set_panning( sample.panning );
}
set_envelope_tick( 0 );
fade_out_volume = 32768;
key_on = true;
}
if( key > 0 ) {
if( key < 97 ) {
porta_period = key_to_period( key );
if( effect != 0x03 && effect != 0x05 ) {
if( ( volume_column & 0xF0 ) != 0xF0 ) {
/* Not portamento.*/
trigger_tick = 0;
if( vibrato_wave < 4 ) {
vibrato_tick = 0;
}
if( tremolo_wave < 4 ) {
tremolo_tick = 0;
}
set_period( porta_period );
set_sample_index( 0 );
}
}
} else {
/* Key off.*/
key_on = false;
}
}
}
private void update_envelopes() {
Envelope envelope;
if( instrument.volume_envelope_active ) {
if( !key_on ) {
fade_out_volume -= instrument.volume_fade_out & 0xFFFF;
if( fade_out_volume < 0 ) {
fade_out_volume = 0;
}
}
envelope = instrument.get_volume_envelope();
volume_envelope_tick = envelope.next_tick( volume_envelope_tick, key_on );
}
if( instrument.panning_envelope_active ) {
envelope = instrument.get_panning_envelope();
panning_envelope_tick = envelope.next_tick( panning_envelope_tick, key_on );
}
}
private void auto_vibrato() {
int sweep, depth, rate;
sweep = instrument.vibrato_sweep & 0xFF;
depth = instrument.vibrato_depth & 0x0F;
rate = instrument.vibrato_rate & 0x3F;
if( trigger_tick < sweep ) {
depth = depth * trigger_tick / sweep;
}
vibrato_add += waveform( trigger_tick * rate, 0 ) * depth >> 9;
}
private int waveform( int phase, int wform ) {
int amplitude;
amplitude = 0;
switch( wform & 0x3 ) {
case 0:
/* Sine. */
if( ( phase & 0x20 ) == 0 ) {
amplitude = sine_table[ phase & 0x1F ];
} else {
amplitude = -sine_table[ phase & 0x1F ];
}
break;
case 1:
/* Saw. */
if( ( phase & 0x20 ) == 0 ) {
amplitude = ( phase & 0x1F ) << 3;
} else {
amplitude = ( ( phase & 0x1F ) << 3 ) - 255;
}
break;
case 2:
/* Square. */
if( ( phase & 0x20 ) == 0 ) {
amplitude = 255;
} else {
amplitude = -255;
}
break;
case 3:
/* Random. */
amplitude = ( random_seed >> 15 ) - 255;
random_seed = ( random_seed * 65 + 17 ) & 0xFFFFFF;
break;
}
return amplitude;
}
private int key_to_period( int key ) {
int octave, log_2_period, period_out;
octave = ( key << IBXM.FP_SHIFT ) / 12 + sample.transpose;
if( linear_periods ) {
period_out = 7744 - ( octave * 768 >> IBXM.FP_SHIFT );
} else {
log_2_period = LOG_2_29024 - octave;
period_out = LogTable.raise_2( log_2_period );
period_out = period_out >> ( IBXM.FP_SHIFT - 1 );
period_out = ( period_out >> 1 ) + ( period_out & 1 );
}
return period_out;
}
private void calculate_amplitude() {
int envelope_volume, tremolo_volume, amplitude;
int envelope_panning, mixer_panning, panning_range;
Envelope envelope;
envelope_volume = 0;
if( instrument.volume_envelope_active ) {
envelope = instrument.get_volume_envelope();
envelope_volume = envelope.calculate_ampl( volume_envelope_tick );
} else {
if( key_on ) {
envelope_volume = 64;
}
}
tremolo_volume = volume + tremolo_add;
if( tremolo_volume < 0 ) {
tremolo_volume = 0;
}
if( tremolo_volume > 64 ) {
tremolo_volume = 64;
}
amplitude = tremolo_volume << IBXM.FP_SHIFT - 6;
amplitude = amplitude * envelope_volume >> 6;
amplitude = amplitude * fade_out_volume >> 15;
amplitude = amplitude * global_volume[ 0 ] >> 6;
amplitude = amplitude * module.channel_gain >> IBXM.FP_SHIFT;
silent = sample.has_finished( sample_idx );
if( amplitude <= 0 ) {
silent = true;
} else {
envelope_panning = 32;
if( instrument.panning_envelope_active ) {
envelope = instrument.get_panning_envelope();
envelope_panning = envelope.calculate_ampl( panning_envelope_tick );
}
mixer_panning = ( panning & 0xFF ) << IBXM.FP_SHIFT - 8;
panning_range = IBXM.FP_ONE - mixer_panning;
if( panning_range > mixer_panning ) {
panning_range = mixer_panning;
}
mixer_panning = mixer_panning + ( panning_range * ( envelope_panning - 32 ) >> 5 );
left_gain = amplitude * ( IBXM.FP_ONE - mixer_panning ) >> IBXM.FP_SHIFT;
right_gain = amplitude * mixer_panning >> IBXM.FP_SHIFT;
}
}
private void calculate_frequency() {
int vibrato_period, log_2_freq;
vibrato_period = period + vibrato_add;
if( vibrato_period < 32 ) {
vibrato_period = 32;
}
if( vibrato_period > 32768 ) {
vibrato_period = 32768;
}
if( linear_periods ) {
log_2_freq = LOG_2_8363 + ( 4608 - vibrato_period << IBXM.FP_SHIFT ) / 768;
} else {
log_2_freq = module.pal ? LOG_2_8287 : LOG_2_8363;
log_2_freq = log_2_freq + LOG_2_1712 - LogTable.log_2( vibrato_period );
}
log_2_freq += ( key_add << IBXM.FP_SHIFT ) / 12;
step = LogTable.raise_2( log_2_freq - log_2_sampling_rate );
}
}
-111
View File
@@ -1,111 +0,0 @@
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 ) + ", " );
}
}
}
-256
View File
@@ -1,256 +0,0 @@
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;
}
}
-343
View File
@@ -1,343 +0,0 @@
package ibxm;
public class IBXM {
public static final String VERSION = "ibxm alpha 51 (c)2008 [email protected]";
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;
}
}
}
-90
View File
@@ -1,90 +0,0 @@
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();
}
}
}
-91
View File
@@ -1,91 +0,0 @@
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;
}
}
-138
View File
@@ -1,138 +0,0 @@
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;
}
}
}
-61
View File
@@ -1,61 +0,0 @@
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;
}
}
-132
View File
@@ -1,132 +0,0 @@
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();
}
}
}
}
-234
View File
@@ -1,234 +0,0 @@
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;
}
}
-239
View File
@@ -1,239 +0,0 @@
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;
}
}
-489
View File
@@ -1,489 +0,0 @@
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,44 +0,0 @@
package net.minecraftforge.client;
import net.minecraft.world.EnumGameType;
import net.minecraft.util.EnumOS;
import net.minecraft.client.settings.EnumOptions;
import net.minecraft.item.EnumRarity;
import net.minecraftforge.common.EnumHelper;
public class EnumHelperClient extends EnumHelper
{
private static Class[][] clentTypes =
{
{EnumGameType.class, int.class, String.class},
{EnumOptions.class, String.class, boolean.class, boolean.class},
{EnumOS.class},
{EnumRarity.class, int.class, String.class}
};
public static EnumGameType addGameType(String name, int id, String displayName)
{
return addEnum(EnumGameType.class, name, id, displayName);
}
public static EnumOptions addOptions(String name, String langName, boolean isSlider, boolean isToggle)
{
return addEnum(EnumOptions.class, name, langName, isSlider, isToggle);
}
public static EnumOS addOS2(String name)
{
return addEnum(EnumOS.class, name);
}
public static EnumRarity addRarity(String name, int color, String displayName)
{
return addEnum(EnumRarity.class, name, color, displayName);
}
public static <T extends Enum<? >> T addEnum(Class<T> enumType, String enumName, Object... paramValues)
{
return addEnum(clentTypes, enumType, enumName, paramValues);
}
}
@@ -1,286 +0,0 @@
package net.minecraftforge.client;
import java.util.HashMap;
import java.util.Random;
import java.util.TreeSet;
import javax.imageio.ImageIO;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import org.lwjgl.opengl.PixelFormat;
import cpw.mods.fml.client.FMLClientHandler;
import net.minecraft.client.Minecraft;
import net.minecraft.block.Block;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.util.MathHelper;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.client.model.ModelBiped;
import net.minecraft.client.renderer.RenderBlocks;
import net.minecraft.client.renderer.RenderGlobal;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.entity.RenderItem;
import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraftforge.client.IItemRenderer.ItemRenderType;
import net.minecraftforge.client.event.DrawBlockHighlightEvent;
import net.minecraftforge.client.event.RenderWorldLastEvent;
import net.minecraftforge.client.event.TextureStitchEvent;
import net.minecraftforge.common.MinecraftForge;
import static net.minecraftforge.client.IItemRenderer.ItemRenderType.*;
import static net.minecraftforge.client.IItemRenderer.ItemRendererHelper.*;
public class ForgeHooksClient
{
static TextureManager engine()
{
return FMLClientHandler.instance().getClient().renderEngine;
}
public static String getArmorTexture(Entity entity, ItemStack armor, String _default, int slot, int layer, String type)
{
String result = armor.getItem().getArmorTexture(armor, entity, slot, layer);
return result != null ? result : _default;
}
public static boolean renderEntityItem(EntityItem entity, ItemStack item, float bobing, float rotation, Random random, TextureManager engine, RenderBlocks renderBlocks)
{
IItemRenderer customRenderer = MinecraftForgeClient.getItemRenderer(item, ENTITY);
if (customRenderer == null)
{
return false;
}
if (customRenderer.shouldUseRenderHelper(ENTITY, item, ENTITY_ROTATION))
{
GL11.glRotatef(rotation, 0.0F, 1.0F, 0.0F);
}
if (!customRenderer.shouldUseRenderHelper(ENTITY, item, ENTITY_BOBBING))
{
GL11.glTranslatef(0.0F, -bobing, 0.0F);
}
boolean is3D = customRenderer.shouldUseRenderHelper(ENTITY, item, BLOCK_3D);
engine.func_110577_a(item.getItemSpriteNumber() == 0 ? TextureMap.field_110575_b : TextureMap.field_110576_c);
Block block = (item.itemID < Block.blocksList.length ? Block.blocksList[item.itemID] : null);
if (is3D || (block != null && RenderBlocks.renderItemIn3d(block.getRenderType())))
{
int renderType = (block != null ? block.getRenderType() : 1);
float scale = (renderType == 1 || renderType == 19 || renderType == 12 || renderType == 2 ? 0.5F : 0.25F);
if (RenderItem.renderInFrame)
{
GL11.glScalef(1.25F, 1.25F, 1.25F);
GL11.glTranslatef(0.0F, 0.05F, 0.0F);
GL11.glRotatef(-90.0F, 0.0F, 1.0F, 0.0F);
}
GL11.glScalef(scale, scale, scale);
int size = item.stackSize;
int count = (size > 40 ? 5 : (size > 20 ? 4 : (size > 5 ? 3 : (size > 1 ? 2 : 1))));
for(int j = 0; j < count; j++)
{
GL11.glPushMatrix();
if (j > 0)
{
GL11.glTranslatef(
((random.nextFloat() * 2.0F - 1.0F) * 0.2F) / scale,
((random.nextFloat() * 2.0F - 1.0F) * 0.2F) / scale,
((random.nextFloat() * 2.0F - 1.0F) * 0.2F) / scale);
}
customRenderer.renderItem(ENTITY, item, renderBlocks, entity);
GL11.glPopMatrix();
}
}
else
{
GL11.glScalef(0.5F, 0.5F, 0.5F);
customRenderer.renderItem(ENTITY, item, renderBlocks, entity);
}
return true;
}
public static boolean renderInventoryItem(RenderBlocks renderBlocks, TextureManager engine, ItemStack item, boolean inColor, float zLevel, float x, float y)
{
IItemRenderer customRenderer = MinecraftForgeClient.getItemRenderer(item, INVENTORY);
if (customRenderer == null)
{
return false;
}
engine.func_110577_a(item.getItemSpriteNumber() == 0 ? TextureMap.field_110575_b : TextureMap.field_110576_c);
if (customRenderer.shouldUseRenderHelper(INVENTORY, item, INVENTORY_BLOCK))
{
GL11.glPushMatrix();
GL11.glTranslatef(x - 2, y + 3, -3.0F + zLevel);
GL11.glScalef(10F, 10F, 10F);
GL11.glTranslatef(1.0F, 0.5F, 1.0F);
GL11.glScalef(1.0F, 1.0F, -1F);
GL11.glRotatef(210F, 1.0F, 0.0F, 0.0F);
GL11.glRotatef(45F, 0.0F, 1.0F, 0.0F);
if(inColor)
{
int color = Item.itemsList[item.itemID].getColorFromItemStack(item, 0);
float r = (float)(color >> 16 & 0xff) / 255F;
float g = (float)(color >> 8 & 0xff) / 255F;
float b = (float)(color & 0xff) / 255F;
GL11.glColor4f(r, g, b, 1.0F);
}
GL11.glRotatef(-90F, 0.0F, 1.0F, 0.0F);
renderBlocks.useInventoryTint = inColor;
customRenderer.renderItem(INVENTORY, item, renderBlocks);
renderBlocks.useInventoryTint = true;
GL11.glPopMatrix();
}
else
{
GL11.glDisable(GL11.GL_LIGHTING);
GL11.glPushMatrix();
GL11.glTranslatef(x, y, -3.0F + zLevel);
if (inColor)
{
int color = Item.itemsList[item.itemID].getColorFromItemStack(item, 0);
float r = (float)(color >> 16 & 255) / 255.0F;
float g = (float)(color >> 8 & 255) / 255.0F;
float b = (float)(color & 255) / 255.0F;
GL11.glColor4f(r, g, b, 1.0F);
}
customRenderer.renderItem(INVENTORY, item, renderBlocks);
GL11.glPopMatrix();
GL11.glEnable(GL11.GL_LIGHTING);
}
return true;
}
public static void renderEquippedItem(ItemRenderType type, IItemRenderer customRenderer, RenderBlocks renderBlocks, EntityLivingBase entity, ItemStack item)
{
if (customRenderer.shouldUseRenderHelper(type, item, EQUIPPED_BLOCK))
{
GL11.glPushMatrix();
GL11.glTranslatef(-0.5F, -0.5F, -0.5F);
customRenderer.renderItem(type, item, renderBlocks, entity);
GL11.glPopMatrix();
}
else
{
GL11.glPushMatrix();
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
GL11.glTranslatef(0.0F, -0.3F, 0.0F);
GL11.glScalef(1.5F, 1.5F, 1.5F);
GL11.glRotatef(50.0F, 0.0F, 1.0F, 0.0F);
GL11.glRotatef(335.0F, 0.0F, 0.0F, 1.0F);
GL11.glTranslatef(-0.9375F, -0.0625F, 0.0F);
customRenderer.renderItem(type, item, renderBlocks, entity);
GL11.glDisable(GL12.GL_RESCALE_NORMAL);
GL11.glPopMatrix();
}
}
//Optifine Helper Functions u.u, these are here specifically for Optifine
//Note: When using Optfine, these methods are invoked using reflection, which
//incurs a major performance penalty.
public static void orientBedCamera(Minecraft mc, EntityLivingBase entity)
{
int x = MathHelper.floor_double(entity.posX);
int y = MathHelper.floor_double(entity.posY);
int z = MathHelper.floor_double(entity.posZ);
Block block = Block.blocksList[mc.theWorld.getBlockId(x, y, z)];
if (block != null && block.isBed(mc.theWorld, x, y, z, entity))
{
int var12 = block.getBedDirection(mc.theWorld, x, y, z);
GL11.glRotatef((float)(var12 * 90), 0.0F, 1.0F, 0.0F);
}
}
public static boolean onDrawBlockHighlight(RenderGlobal context, EntityPlayer player, MovingObjectPosition target, int subID, ItemStack currentItem, float partialTicks)
{
return MinecraftForge.EVENT_BUS.post(new DrawBlockHighlightEvent(context, player, target, subID, currentItem, partialTicks));
}
public static void dispatchRenderLast(RenderGlobal context, float partialTicks)
{
MinecraftForge.EVENT_BUS.post(new RenderWorldLastEvent(context, partialTicks));
}
public static void onTextureStitchedPre(TextureMap map)
{
MinecraftForge.EVENT_BUS.post(new TextureStitchEvent.Pre(map));
}
public static void onTextureStitchedPost(TextureMap map)
{
MinecraftForge.EVENT_BUS.post(new TextureStitchEvent.Post(map));
}
/**
* This is added for Optifine's convenience. And to explode if a ModMaker is developing.
* @param texture
*/
public static void onTextureLoadPre(String texture)
{
if (Tessellator.renderingWorldRenderer)
{
String msg = String.format("Warning: Texture %s not preloaded, will cause render glitches!", texture);
System.out.println(msg);
if (Tessellator.class.getPackage() != null)
{
if (Tessellator.class.getPackage().getName().startsWith("net.minecraft."))
{
Minecraft mc = FMLClientHandler.instance().getClient();
if (mc.ingameGUI != null)
{
mc.ingameGUI.getChatGUI().printChatMessage(msg);
}
}
}
}
}
static int renderPass = -1;
public static void setRenderPass(int pass)
{
renderPass = pass;
}
public static ModelBiped getArmorModel(EntityLivingBase entityLiving, ItemStack itemStack, int slotID, ModelBiped _default)
{
ModelBiped modelbiped = itemStack.getItem().getArmorModel(entityLiving, itemStack, slotID);
return modelbiped == null ? _default : modelbiped;
}
static int stencilBits = 0;
public static void createDisplay() throws LWJGLException
{
ImageIO.setUseCache(false); //Disable on-disc stream cache should speed up texture pack reloading.
PixelFormat format = new PixelFormat().withDepthBits(24);
try
{
//TODO: Figure out how to determine the max bits.
Display.create(format.withStencilBits(8));
stencilBits = 8;
}
catch(LWJGLException e)
{
Display.create(format);
stencilBits = 0;
}
}
}
@@ -1,127 +0,0 @@
package net.minecraftforge.client;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.GL11;
import net.minecraft.client.Minecraft;
import net.minecraft.client.settings.GameSettings;
import net.minecraft.client.gui.GuiControls;
import net.minecraft.client.gui.GuiSlot;
import net.minecraft.client.settings.KeyBinding;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.util.EnumChatFormatting;
public class GuiControlsScrollPanel extends GuiSlot
{
private GuiControls controls;
private GameSettings options;
private Minecraft mc;
private String[] message;
private int _mouseX;
private int _mouseY;
private int selected = -1;
public GuiControlsScrollPanel(GuiControls controls, GameSettings options, Minecraft mc)
{
super(mc, controls.width, controls.height, 16, (controls.height - 32) + 4, 25);
this.controls = controls;
this.options = options;
this.mc = mc;
}
@Override
protected int getSize()
{
return options.keyBindings.length;
}
@Override
protected void elementClicked(int i, boolean flag)
{
if (!flag)
{
if (selected == -1)
{
selected = i;
}
else
{
options.setKeyBinding(selected, -100);
selected = -1;
KeyBinding.resetKeyBindingArrayAndHash();
}
}
}
@Override
protected boolean isSelected(int i)
{
return false;
}
@Override
protected void func_130003_c() {}
@Override
public void drawScreen(int mX, int mY, float f)
{
_mouseX = mX;
_mouseY = mY;
if (selected != -1 && !Mouse.isButtonDown(0) && Mouse.getDWheel() == 0)
{
if (Mouse.next() && Mouse.getEventButtonState())
{
System.out.println(Mouse.getEventButton());
options.setKeyBinding(selected, -100 + Mouse.getEventButton());
selected = -1;
KeyBinding.resetKeyBindingArrayAndHash();
}
}
super.drawScreen(mX, mY, f);
}
@Override
protected void drawSlot(int index, int xPosition, int yPosition, int l, Tessellator tessellator)
{
int width = 70;
int height = 20;
xPosition -= 20;
boolean flag = _mouseX >= xPosition && _mouseY >= yPosition && _mouseX < xPosition + width && _mouseY < yPosition + height;
int k = (flag ? 2 : 1);
mc.renderEngine.func_110577_a(TextureMap.field_110576_c);
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
controls.drawTexturedModalRect(xPosition, yPosition, 0, 46 + k * 20, width / 2, height);
controls.drawTexturedModalRect(xPosition + width / 2, yPosition, 200 - width / 2, 46 + k * 20, width / 2, height);
controls.drawString(mc.fontRenderer, options.getKeyBindingDescription(index), xPosition + width + 4, yPosition + 6, 0xFFFFFFFF);
boolean conflict = false;
for (int x = 0; x < options.keyBindings.length; x++)
{
if (x != index && options.keyBindings[x].keyCode == options.keyBindings[index].keyCode)
{
conflict = true;
break;
}
}
String str = (conflict ? EnumChatFormatting.RED : "") + options.getOptionDisplayString(index);
str = (index == selected ? EnumChatFormatting.WHITE + "> " + EnumChatFormatting.YELLOW + "??? " + EnumChatFormatting.WHITE + "<" : str);
controls.drawCenteredString(mc.fontRenderer, str, xPosition + (width / 2), yPosition + (height - 8) / 2, 0xFFFFFFFF);
}
public boolean keyTyped(char c, int i)
{
if (selected != -1)
{
options.setKeyBinding(selected, i);
selected = -1;
KeyBinding.resetKeyBindingArrayAndHash();
return false;
}
return true;
}
}
@@ -1,871 +0,0 @@
package net.minecraftforge.client;
import static net.minecraftforge.client.event.RenderGameOverlayEvent.ElementType.*;
import java.awt.Color;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.gui.GuiIngame;
import net.minecraft.client.gui.GuiPlayerInfo;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.client.multiplayer.NetClientHandler;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.resources.ResourceLocation;
import net.minecraft.crash.CallableMinecraftVersion;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.ai.attributes.AttributeInstance;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.potion.Potion;
import net.minecraft.scoreboard.Score;
import net.minecraft.scoreboard.ScoreObjective;
import net.minecraft.scoreboard.ScorePlayerTeam;
import net.minecraft.util.Direction;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.FoodStats;
import net.minecraft.util.MathHelper;
import net.minecraft.util.StatCollector;
import net.minecraft.util.StringUtils;
import net.minecraft.world.EnumSkyBlock;
import net.minecraft.world.chunk.Chunk;
import net.minecraftforge.client.event.RenderGameOverlayEvent;
import net.minecraftforge.client.event.RenderGameOverlayEvent.ElementType;
import net.minecraftforge.common.ForgeHooks;
import net.minecraftforge.common.MinecraftForge;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import cpw.mods.fml.common.FMLCommonHandler;
public class GuiIngameForge extends GuiIngame
{
private static final ResourceLocation VIGNETTE = new ResourceLocation("textures/misc/vignette.png");
private static final ResourceLocation WIDGITS = new ResourceLocation("textures/gui/widgets.png");
private static final ResourceLocation PUMPKIN_BLUR = new ResourceLocation("textures/misc/pumpkinblur.png");
private static final int WHITE = 0xFFFFFF;
//Flags to toggle the rendering of certain aspects of the HUD, valid conditions
//must be met for them to render normally. If those conditions are met, but this flag
//is false, they will not be rendered.
public static boolean renderHelmet = true;
public static boolean renderPortal = true;
public static boolean renderHotbar = true;
public static boolean renderCrosshairs = true;
public static boolean renderBossHealth = true;
public static boolean renderHealth = true;
public static boolean renderArmor = true;
public static boolean renderFood = true;
public static boolean renderHealthMount = true;
public static boolean renderAir = true;
public static boolean renderExperiance = true;
public static boolean renderJumpBar = true;
public static boolean renderObjective = true;
public static int left_height = 39;
public static int right_height = 39;
private ScaledResolution res = null;
private FontRenderer fontrenderer = null;
private RenderGameOverlayEvent eventParent;
private static final String MC_VERSION = (new CallableMinecraftVersion(null)).minecraftVersion();
public GuiIngameForge(Minecraft mc)
{
super(mc);
}
@Override
public void renderGameOverlay(float partialTicks, boolean hasScreen, int mouseX, int mouseY)
{
res = new ScaledResolution(mc.gameSettings, mc.displayWidth, mc.displayHeight);
eventParent = new RenderGameOverlayEvent(partialTicks, res, mouseX, mouseY);
int width = res.getScaledWidth();
int height = res.getScaledHeight();
renderHealthMount = mc.thePlayer.ridingEntity instanceof EntityLivingBase;
renderFood = mc.thePlayer.ridingEntity == null;
renderJumpBar = mc.thePlayer.func_110317_t();
right_height = 39;
left_height = 39;
if (pre(ALL)) return;
fontrenderer = mc.fontRenderer;
mc.entityRenderer.setupOverlayRendering();
GL11.glEnable(GL11.GL_BLEND);
if (Minecraft.isFancyGraphicsEnabled())
{
renderVignette(mc.thePlayer.getBrightness(partialTicks), width, height);
}
else
{
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
}
if (renderHelmet) renderHelmet(res, partialTicks, hasScreen, mouseX, mouseY);
if (renderPortal && !mc.thePlayer.isPotionActive(Potion.confusion))
{
renderPortal(width, height, partialTicks);
}
if (!mc.playerController.enableEverythingIsScrewedUpMode())
{
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
zLevel = -90.0F;
rand.setSeed((long)(updateCounter * 312871));
if (renderCrosshairs) renderCrosshairs(width, height);
if (renderBossHealth) renderBossHealth();
if (this.mc.playerController.shouldDrawHUD())
{
if (renderHealth) renderHealth(width, height);
if (renderArmor) renderArmor(width, height);
if (renderFood) renderFood(width, height);
if (renderHealthMount) renderHealthMount(width, height);
if (renderAir) renderAir(width, height);
}
if (renderHotbar) renderHotbar(width, height, partialTicks);
}
if (renderJumpBar)
{
renderJumpBar(width, height);
}
else if (renderExperiance)
{
renderExperience(width, height);
}
renderSleepFade(width, height);
renderToolHightlight(width, height);
renderHUDText(width, height);
renderRecordOverlay(width, height, partialTicks);
ScoreObjective objective = mc.theWorld.getScoreboard().func_96539_a(1);
if (renderObjective && objective != null)
{
this.func_96136_a(objective, height, width, fontrenderer);
}
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glDisable(GL11.GL_ALPHA_TEST);
renderChat(width, height);
renderPlayerList(width, height);
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
GL11.glDisable(GL11.GL_LIGHTING);
GL11.glEnable(GL11.GL_ALPHA_TEST);
post(ALL);
}
public ScaledResolution getResolution()
{
return res;
}
protected void renderHotbar(int width, int height, float partialTicks)
{
if (pre(HOTBAR)) return;
mc.mcProfiler.startSection("actionBar");
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
mc.renderEngine.func_110577_a(WIDGITS);
InventoryPlayer inv = mc.thePlayer.inventory;
drawTexturedModalRect(width / 2 - 91, height - 22, 0, 0, 182, 22);
drawTexturedModalRect(width / 2 - 91 - 1 + inv.currentItem * 20, height - 22 - 1, 0, 22, 24, 22);
GL11.glDisable(GL11.GL_BLEND);
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
RenderHelper.enableGUIStandardItemLighting();
for (int i = 0; i < 9; ++i)
{
int x = width / 2 - 90 + i * 20 + 2;
int z = height - 16 - 3;
renderInventorySlot(i, x, z, partialTicks);
}
RenderHelper.disableStandardItemLighting();
GL11.glDisable(GL12.GL_RESCALE_NORMAL);
mc.mcProfiler.endSection();
post(HOTBAR);
}
protected void renderCrosshairs(int width, int height)
{
if (pre(CROSSHAIRS)) return;
bind(Gui.field_110324_m);
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_ONE_MINUS_DST_COLOR, GL11.GL_ONE_MINUS_SRC_COLOR);
drawTexturedModalRect(width / 2 - 7, height / 2 - 7, 0, 0, 16, 16);
GL11.glDisable(GL11.GL_BLEND);
post(CROSSHAIRS);
}
@Override
protected void renderBossHealth()
{
if (pre(BOSSHEALTH)) return;
mc.mcProfiler.startSection("bossHealth");
super.renderBossHealth();
mc.mcProfiler.endSection();
post(BOSSHEALTH);
}
private void renderHelmet(ScaledResolution res, float partialTicks, boolean hasScreen, int mouseX, int mouseY)
{
if (pre(HELMET)) return;
ItemStack itemstack = this.mc.thePlayer.inventory.armorItemInSlot(3);
if (this.mc.gameSettings.thirdPersonView == 0 && itemstack != null && itemstack.getItem() != null)
{
if (itemstack.itemID == Block.pumpkin.blockID)
{
renderPumpkinBlur(res.getScaledWidth(), res.getScaledHeight());
}
else
{
itemstack.getItem().renderHelmetOverlay(itemstack, mc.thePlayer, res, partialTicks, hasScreen, mouseX, mouseY);
}
}
post(HELMET);
}
protected void renderArmor(int width, int height)
{
if (pre(ARMOR)) return;
mc.mcProfiler.startSection("armor");
int left = width / 2 - 91;
int top = height - left_height;
int level = ForgeHooks.getTotalArmorValue(mc.thePlayer);
for (int i = 1; level > 0 && i < 20; i += 2)
{
if (i < level)
{
drawTexturedModalRect(left, top, 34, 9, 9, 9);
}
else if (i == level)
{
drawTexturedModalRect(left, top, 25, 9, 9, 9);
}
else if (i > level)
{
drawTexturedModalRect(left, top, 16, 9, 9, 9);
}
left += 8;
}
left_height += 10;
mc.mcProfiler.endSection();
post(ARMOR);
}
protected void renderPortal(int width, int height, float partialTicks)
{
if (pre(PORTAL)) return;
float f1 = mc.thePlayer.prevTimeInPortal + (mc.thePlayer.timeInPortal - mc.thePlayer.prevTimeInPortal) * partialTicks;
if (f1 > 0.0F)
{
func_130015_b(f1, width, height);
}
post(PORTAL);
}
protected void renderAir(int width, int height)
{
if (pre(AIR)) return;
mc.mcProfiler.startSection("air");
int left = width / 2 + 91;
int top = height - right_height;
if (mc.thePlayer.isInsideOfMaterial(Material.water))
{
int air = mc.thePlayer.getAir();
int full = MathHelper.ceiling_double_int((double)(air - 2) * 10.0D / 300.0D);
int partial = MathHelper.ceiling_double_int((double)air * 10.0D / 300.0D) - full;
for (int i = 0; i < full + partial; ++i)
{
drawTexturedModalRect(left - i * 8 - 9, top, (i < full ? 16 : 25), 18, 9, 9);
}
right_height += 10;
}
mc.mcProfiler.endSection();
post(AIR);
}
public void renderHealth(int width, int height)
{
bind(field_110324_m);
if (pre(HEALTH)) return;
mc.mcProfiler.startSection("health");
boolean highlight = mc.thePlayer.hurtResistantTime / 3 % 2 == 1;
if (mc.thePlayer.hurtResistantTime < 10)
{
highlight = false;
}
AttributeInstance attrMaxHealth = this.mc.thePlayer.func_110148_a(SharedMonsterAttributes.field_111267_a);
int health = MathHelper.ceiling_float_int(mc.thePlayer.func_110143_aJ());
int healthLast = MathHelper.ceiling_float_int(mc.thePlayer.prevHealth);
float healthMax = (float)attrMaxHealth.func_111126_e();
float absorb = this.mc.thePlayer.func_110139_bj();
int healthRows = MathHelper.ceiling_float_int((healthMax + absorb) / 2.0F / 10.0F);
int rowHeight = Math.max(10 - (healthRows - 2), 3);
this.rand.setSeed((long)(updateCounter * 312871));
int left = width / 2 - 91;
int top = height - left_height;
left_height += (healthRows * rowHeight);
if (rowHeight != 10) left_height += 10 - rowHeight;
int regen = -1;
if (mc.thePlayer.isPotionActive(Potion.regeneration))
{
regen = updateCounter % 25;
}
final int TOP = 9 * (mc.theWorld.getWorldInfo().isHardcoreModeEnabled() ? 5 : 0);
final int BACKGROUND = (highlight ? 25 : 16);
int MARGIN = 16;
if (mc.thePlayer.isPotionActive(Potion.poison)) MARGIN += 36;
else if (mc.thePlayer.isPotionActive(Potion.wither)) MARGIN += 72;
float absorbRemaining = absorb;
for (int i = MathHelper.ceiling_float_int((healthMax + absorb) / 2.0F) - 1; i >= 0; --i)
{
int b0 = (highlight ? 1 : 0);
int row = MathHelper.ceiling_float_int((float)(i + 1) / 10.0F) - 1;
int x = left + i % 10 * 8;
int y = top - row * rowHeight;
if (health <= 4) y += rand.nextInt(2);
if (i == regen) y -= 2;
drawTexturedModalRect(x, y, BACKGROUND, TOP, 9, 9);
if (highlight)
{
if (i * 2 + 1 < healthLast)
drawTexturedModalRect(x, y, MARGIN + 54, TOP, 9, 9); //6
else if (i * 2 + 1 == healthLast)
drawTexturedModalRect(x, y, MARGIN + 63, TOP, 9, 9); //7
}
if (absorbRemaining > 0.0F)
{
if (absorbRemaining == absorb && absorb % 2.0F == 1.0F)
drawTexturedModalRect(x, y, MARGIN + 153, TOP, 9, 9); //17
else
drawTexturedModalRect(x, y, MARGIN + 144, TOP, 9, 9); //16
absorbRemaining -= 2.0F;
}
else
{
if (i * 2 + 1 < health)
drawTexturedModalRect(x, y, MARGIN + 36, TOP, 9, 9); //4
else if (i * 2 + 1 == health)
drawTexturedModalRect(x, y, MARGIN + 45, TOP, 9, 9); //5
}
}
mc.mcProfiler.endSection();
post(HEALTH);
}
public void renderFood(int width, int height)
{
if (pre(FOOD)) return;
mc.mcProfiler.startSection("food");
int left = width / 2 + 91;
int top = height - right_height;
right_height += 10;
boolean unused = false;// Unused flag in vanilla, seems to be part of a 'fade out' mechanic
FoodStats stats = mc.thePlayer.getFoodStats();
int level = stats.getFoodLevel();
int levelLast = stats.getPrevFoodLevel();
for (int i = 0; i < 10; ++i)
{
int idx = i * 2 + 1;
int x = left - i * 8 - 9;
int y = top;
int icon = 16;
byte backgound = 0;
if (mc.thePlayer.isPotionActive(Potion.hunger))
{
icon += 36;
backgound = 13;
}
if (unused) backgound = 1; //Probably should be a += 1 but vanilla never uses this
if (mc.thePlayer.getFoodStats().getSaturationLevel() <= 0.0F && updateCounter % (level * 3 + 1) == 0)
{
y = top + (rand.nextInt(3) - 1);
}
drawTexturedModalRect(x, y, 16 + backgound * 9, 27, 9, 9);
if (unused)
{
if (idx < levelLast)
drawTexturedModalRect(x, y, icon + 54, 27, 9, 9);
else if (idx == levelLast)
drawTexturedModalRect(x, y, icon + 63, 27, 9, 9);
}
if (idx < level)
drawTexturedModalRect(x, y, icon + 36, 27, 9, 9);
else if (idx == level)
drawTexturedModalRect(x, y, icon + 45, 27, 9, 9);
}
mc.mcProfiler.endSection();
post(FOOD);
}
protected void renderSleepFade(int width, int height)
{
if (mc.thePlayer.getSleepTimer() > 0)
{
mc.mcProfiler.startSection("sleep");
GL11.glDisable(GL11.GL_DEPTH_TEST);
GL11.glDisable(GL11.GL_ALPHA_TEST);
int sleepTime = mc.thePlayer.getSleepTimer();
float opacity = (float)sleepTime / 100.0F;
if (opacity > 1.0F)
{
opacity = 1.0F - (float)(sleepTime - 100) / 10.0F;
}
int color = (int)(220.0F * opacity) << 24 | 1052704;
drawRect(0, 0, width, height, color);
GL11.glEnable(GL11.GL_ALPHA_TEST);
GL11.glEnable(GL11.GL_DEPTH_TEST);
mc.mcProfiler.endSection();
}
}
protected void renderExperience(int width, int height)
{
bind(field_110324_m);
if (pre(EXPERIENCE)) return;
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
if (mc.playerController.func_78763_f())
{
mc.mcProfiler.startSection("expBar");
int cap = this.mc.thePlayer.xpBarCap();
int left = width / 2 - 91;
if (cap > 0)
{
short barWidth = 182;
int filled = (int)(mc.thePlayer.experience * (float)(barWidth + 1));
int top = height - 32 + 3;
drawTexturedModalRect(left, top, 0, 64, barWidth, 5);
if (filled > 0)
{
drawTexturedModalRect(left, top, 0, 69, filled, 5);
}
}
this.mc.mcProfiler.endSection();
if (mc.playerController.func_78763_f() && mc.thePlayer.experienceLevel > 0)
{
mc.mcProfiler.startSection("expLevel");
boolean flag1 = false;
int color = flag1 ? 16777215 : 8453920;
String text = "" + mc.thePlayer.experienceLevel;
int x = (width - fontrenderer.getStringWidth(text)) / 2;
int y = height - 31 - 4;
fontrenderer.drawString(text, x + 1, y, 0);
fontrenderer.drawString(text, x - 1, y, 0);
fontrenderer.drawString(text, x, y + 1, 0);
fontrenderer.drawString(text, x, y - 1, 0);
fontrenderer.drawString(text, x, y, color);
mc.mcProfiler.endSection();
}
}
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
post(EXPERIENCE);
}
protected void renderJumpBar(int width, int height)
{
bind(field_110324_m);
if (pre(JUMPBAR)) return;
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
mc.mcProfiler.startSection("jumpBar");
float charge = mc.thePlayer.func_110319_bJ();
final int barWidth = 182;
int x = (width / 2) - (barWidth / 2);
int filled = (int)(charge * (float)(barWidth + 1));
int top = height - 32 + 3;
drawTexturedModalRect(x, top, 0, 84, barWidth, 5);
if (filled > 0)
{
this.drawTexturedModalRect(x, top, 0, 89, filled, 5);
}
mc.mcProfiler.endSection();
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
post(JUMPBAR);
}
protected void renderToolHightlight(int width, int height)
{
if (this.mc.gameSettings.heldItemTooltips)
{
mc.mcProfiler.startSection("toolHighlight");
if (this.remainingHighlightTicks > 0 && this.highlightingItemStack != null)
{
String name = this.highlightingItemStack.getDisplayName();
int opacity = (int)((float)this.remainingHighlightTicks * 256.0F / 10.0F);
if (opacity > 255) opacity = 255;
if (opacity > 0)
{
int y = height - 59;
if (!mc.playerController.shouldDrawHUD()) y += 14;
GL11.glPushMatrix();
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
FontRenderer font = highlightingItemStack.getItem().getFontRenderer(highlightingItemStack);
if (font != null)
{
int x = (width - font.getStringWidth(name)) / 2;
font.drawStringWithShadow(name, x, y, WHITE | (opacity << 24));
}
else
{
int x = (width - fontrenderer.getStringWidth(name)) / 2;
fontrenderer.drawStringWithShadow(name, x, y, WHITE | (opacity << 24));
}
GL11.glDisable(GL11.GL_BLEND);
GL11.glPopMatrix();
}
}
mc.mcProfiler.endSection();
}
}
protected void renderHUDText(int width, int height)
{
mc.mcProfiler.startSection("forgeHudText");
ArrayList<String> left = new ArrayList<String>();
ArrayList<String> right = new ArrayList<String>();
if (mc.isDemo())
{
long time = mc.theWorld.getTotalWorldTime();
if (time >= 120500L)
{
right.add(StatCollector.translateToLocal("demo.demoExpired"));
}
else
{
right.add(String.format(StatCollector.translateToLocal("demo.remainingTime"), StringUtils.ticksToElapsedTime((int)(120500L - time))));
}
}
if (this.mc.gameSettings.showDebugInfo)
{
mc.mcProfiler.startSection("debug");
GL11.glPushMatrix();
left.add("Minecraft " + MC_VERSION + " (" + this.mc.debug + ")");
left.add(mc.debugInfoRenders());
left.add(mc.getEntityDebug());
left.add(mc.debugInfoEntities());
left.add(mc.getWorldProviderName());
left.add(null); //Spacer
long max = Runtime.getRuntime().maxMemory();
long total = Runtime.getRuntime().totalMemory();
long free = Runtime.getRuntime().freeMemory();
long used = total - free;
right.add("Used memory: " + used * 100L / max + "% (" + used / 1024L / 1024L + "MB) of " + max / 1024L / 1024L + "MB");
right.add("Allocated memory: " + total * 100L / max + "% (" + total / 1024L / 1024L + "MB)");
int x = MathHelper.floor_double(mc.thePlayer.posX);
int y = MathHelper.floor_double(mc.thePlayer.posY);
int z = MathHelper.floor_double(mc.thePlayer.posZ);
float yaw = mc.thePlayer.rotationYaw;
int heading = MathHelper.floor_double((double)(mc.thePlayer.rotationYaw * 4.0F / 360.0F) + 0.5D) & 3;
left.add(String.format("x: %.5f (%d) // c: %d (%d)", mc.thePlayer.posX, x, x >> 4, x & 15));
left.add(String.format("y: %.3f (feet pos, %.3f eyes pos)", mc.thePlayer.boundingBox.minY, mc.thePlayer.posY));
left.add(String.format("z: %.5f (%d) // c: %d (%d)", mc.thePlayer.posZ, z, z >> 4, z & 15));
left.add(String.format("f: %d (%s) / %f", heading, Direction.directions[heading], MathHelper.wrapAngleTo180_float(yaw)));
if (mc.theWorld != null && mc.theWorld.blockExists(x, y, z))
{
Chunk chunk = this.mc.theWorld.getChunkFromBlockCoords(x, z);
left.add(String.format("lc: %d b: %s bl: %d sl: %d rl: %d",
chunk.getTopFilledSegment() + 15,
chunk.getBiomeGenForWorldCoords(x & 15, z & 15, mc.theWorld.getWorldChunkManager()).biomeName,
chunk.getSavedLightValue(EnumSkyBlock.Block, x & 15, y, z & 15),
chunk.getSavedLightValue(EnumSkyBlock.Sky, x & 15, y, z & 15),
chunk.getBlockLightValue(x & 15, y, z & 15, 0)));
}
else
{
left.add(null);
}
left.add(String.format("ws: %.3f, fs: %.3f, g: %b, fl: %d", mc.thePlayer.capabilities.getWalkSpeed(), mc.thePlayer.capabilities.getFlySpeed(), mc.thePlayer.onGround, mc.theWorld.getHeightValue(x, z)));
right.add(null);
for (String s : FMLCommonHandler.instance().getBrandings().subList(1, FMLCommonHandler.instance().getBrandings().size()))
{
right.add(s);
}
GL11.glPopMatrix();
mc.mcProfiler.endSection();
}
RenderGameOverlayEvent.Text event = new RenderGameOverlayEvent.Text(eventParent, left, right);
if (!MinecraftForge.EVENT_BUS.post(event))
{
for (int x = 0; x < left.size(); x++)
{
String msg = left.get(x);
if (msg == null) continue;
fontrenderer.drawStringWithShadow(msg, 2, 2 + x * 10, WHITE);
}
for (int x = 0; x < right.size(); x++)
{
String msg = right.get(x);
if (msg == null) continue;
int w = fontrenderer.getStringWidth(msg);
fontrenderer.drawStringWithShadow(msg, width - w - 10, 2 + x * 10, WHITE);
}
}
mc.mcProfiler.endSection();
post(TEXT);
}
protected void renderRecordOverlay(int width, int height, float partialTicks)
{
if (recordPlayingUpFor > 0)
{
mc.mcProfiler.startSection("overlayMessage");
float hue = (float)recordPlayingUpFor - partialTicks;
int opacity = (int)(hue * 256.0F / 20.0F);
if (opacity > 255) opacity = 255;
if (opacity > 0)
{
GL11.glPushMatrix();
GL11.glTranslatef((float)(width / 2), (float)(height - 48), 0.0F);
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
int color = (recordIsPlaying ? Color.HSBtoRGB(hue / 50.0F, 0.7F, 0.6F) & WHITE : WHITE);
fontrenderer.drawString(recordPlaying, -fontrenderer.getStringWidth(recordPlaying) / 2, -4, color | (opacity << 24));
GL11.glDisable(GL11.GL_BLEND);
GL11.glPopMatrix();
}
mc.mcProfiler.endSection();
}
}
protected void renderChat(int width, int height)
{
GL11.glPushMatrix();
GL11.glTranslatef(0.0F, (float)(height - 48), 0.0F);
mc.mcProfiler.startSection("chat");
persistantChatGUI.drawChat(updateCounter);
mc.mcProfiler.endSection();
GL11.glPopMatrix();
}
protected void renderPlayerList(int width, int height)
{
ScoreObjective scoreobjective = this.mc.theWorld.getScoreboard().func_96539_a(0);
NetClientHandler handler = mc.thePlayer.sendQueue;
if (mc.gameSettings.keyBindPlayerList.pressed && (!mc.isIntegratedServerRunning() || handler.playerInfoList.size() > 1 || scoreobjective != null))
{
this.mc.mcProfiler.startSection("playerList");
List players = handler.playerInfoList;
int maxPlayers = handler.currentServerMaxPlayers;
int rows = maxPlayers;
int columns = 1;
for (columns = 1; rows > 20; rows = (maxPlayers + columns - 1) / columns)
{
columns++;
}
int columnWidth = 300 / columns;
if (columnWidth > 150)
{
columnWidth = 150;
}
int left = (width - columns * columnWidth) / 2;
byte border = 10;
drawRect(left - 1, border - 1, left + columnWidth * columns, border + 9 * rows, Integer.MIN_VALUE);
for (int i = 0; i < maxPlayers; i++)
{
int xPos = left + i % columns * columnWidth;
int yPos = border + i / columns * 9;
drawRect(xPos, yPos, xPos + columnWidth - 1, yPos + 8, 553648127);
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
GL11.glEnable(GL11.GL_ALPHA_TEST);
if (i < players.size())
{
GuiPlayerInfo player = (GuiPlayerInfo)players.get(i);
ScorePlayerTeam team = mc.theWorld.getScoreboard().getPlayersTeam(player.name);
String displayName = ScorePlayerTeam.func_96667_a(team, player.name);
fontrenderer.drawStringWithShadow(displayName, xPos, yPos, 16777215);
if (scoreobjective != null)
{
int endX = xPos + fontrenderer.getStringWidth(displayName) + 5;
int maxX = xPos + columnWidth - 12 - 5;
if (maxX - endX > 5)
{
Score score = scoreobjective.getScoreboard().func_96529_a(player.name, scoreobjective);
String scoreDisplay = EnumChatFormatting.YELLOW + "" + score.func_96652_c();
fontrenderer.drawStringWithShadow(scoreDisplay, maxX - fontrenderer.getStringWidth(scoreDisplay), yPos, 16777215);
}
}
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
mc.func_110434_K().func_110577_a(Gui.field_110324_m);
int pingIndex = 4;
int ping = player.responseTime;
if (ping < 0) pingIndex = 5;
else if (ping < 150) pingIndex = 0;
else if (ping < 300) pingIndex = 1;
else if (ping < 600) pingIndex = 2;
else if (ping < 1000) pingIndex = 3;
zLevel += 100.0F;
drawTexturedModalRect(xPos + columnWidth - 12, yPos, 0, 176 + pingIndex * 8, 10, 8);
zLevel -= 100.0F;
}
}
}
}
protected void renderHealthMount(int width, int height)
{
Entity tmp = mc.thePlayer.ridingEntity;
if (!(tmp instanceof EntityLivingBase)) return;
bind(field_110324_m);
if (pre(HEALTHMOUNT)) return;
boolean unused = false;
int left_align = width / 2 + 91;
mc.mcProfiler.endStartSection("mountHealth");
EntityLivingBase mount = (EntityLivingBase)tmp;
int health = (int)Math.ceil((double)mount.func_110143_aJ());
float healthMax = mount.func_110138_aP();
int hearts = (int)(healthMax + 0.5F) / 2;
if (hearts > 30) hearts = 30;
final int MARGIN = 52;
final int BACKGROUND = MARGIN + (unused ? 1 : 0);
final int HALF = MARGIN + 45;
final int FULL = MARGIN + 36;
for (int heart = 0; hearts > 0; heart += 20)
{
int top = height - right_height;
int rowCount = Math.min(hearts, 10);
hearts -= rowCount;
for (int i = 0; i < rowCount; ++i)
{
int x = left_align - i * 8 - 9;
drawTexturedModalRect(x, top, BACKGROUND, 9, 9, 9);
if (i * 2 + 1 + heart < health)
drawTexturedModalRect(x, top, FULL, 9, 9, 9);
else if (i * 2 + 1 + heart == health)
drawTexturedModalRect(x, top, HALF, 9, 9, 9);
}
right_height += 10;
}
post(HEALTHMOUNT);
}
//Helper macros
private boolean pre(ElementType type)
{
return MinecraftForge.EVENT_BUS.post(new RenderGameOverlayEvent.Pre(eventParent, type));
}
private void post(ElementType type)
{
MinecraftForge.EVENT_BUS.post(new RenderGameOverlayEvent.Post(eventParent, type));
}
private void bind(ResourceLocation res)
{
mc.func_110434_K().func_110577_a(res);
}
}
@@ -1,137 +0,0 @@
package net.minecraftforge.client;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.EntityLiving;
import net.minecraft.item.ItemStack;
import net.minecraft.client.renderer.RenderBlocks;
public interface IItemRenderer
{
public enum ItemRenderType
{
/**
* Called to render an in-world item, e.g. one that has been thrown or
* dropped. The appropriate OpenGL transformations and scaling have already
* been applied, so Tessellator location (0,0,0) is the center of the
* EntityItem.
*
* Data parameters:
* RenderBlocks render - The RenderBlocks instance
* EntityItem entity - The in-world item to be rendered
*/
ENTITY,
/**
* Called to render an item currently held in-hand by a living entity. If
* rendering as a 3D block, the item will be rotated to a 45-degree angle.
* To render a 2D texture with some thickness (like default items), see
* net.minecraft.src.ItemRenderer. In either case, rendering should be done
* in local coordinates from (0,0,0)-(1,1,1).
*
* Data parameters:
* RenderBlocks render - The RenderBlocks instance
* EntityLiving entity - The entity holding this item
*/
EQUIPPED,
/**
* Called to render an item currently held in-hand by a living entity in
* first person. If rendering as a 3D block, the item will be rotated to a
* 45-degree angle. To render a 2D texture with some thickness, see
* net.minecraft.src.ItemRenderer. In either case, rendering should be done
* in local coordinates from (0,0,0)-(1,1,1).
*
* Data parameters:
* RenderBlocks render - The RenderBlocks instance
* EntityLiving entity - The entity holding this item
*/
EQUIPPED_FIRST_PERSON,
/**
* Called to render an item in a GUI inventory slot. If rendering as a 3D
* block, the appropriate OpenGL translations and scaling have already been
* applied, and the rendering should be done in local coordinates from
* (0,0,0)-(1,1,1). If rendering as a 2D texture, the rendering should be in
* GUI pixel coordinates from (0, 0, 0)-(16, 16, 0).
*
* Data parameters:
* RenderBlocks render - The RenderBlocks instance
*/
INVENTORY,
/**
* The render type used for when a ItemMap is rendered in first person,
* All appropriate rotations have been applied, and the player's hands,
* and the map BG are already rendered.
*
* Data Parameters:
* EntityPlayer player - The player holding the map
* RenderEngine engine - The RenderEngine instance
* MapData mapData - The map data
*/
FIRST_PERSON_MAP
}
public enum ItemRendererHelper
{
/**
* Determines if a rotation effect should be used when rendering an
* EntityItem, like most default blocks do.
*/
ENTITY_ROTATION,
/**
* Determines if an up-and-down bobbing effect should be used when
* rendering an EntityItem, like most default items do.
*/
ENTITY_BOBBING,
/**
* Determines if the currently equipped item should be rendered as a 3D
* block or as a 2D texture.
*/
EQUIPPED_BLOCK,
/**
* Determines if the item should equate to a block that has
* RenderBlocks.renderItemIn3d return true
*/
BLOCK_3D,
/**
* Determines if the item should be rendered in GUI inventory slots as a 3D
* block or as a 2D texture.
*/
INVENTORY_BLOCK
}
/**
* Checks if this renderer should handle a specific item's render type
* @param item The item we are trying to render
* @param type A render type to check if this renderer handles
* @return true if this renderer should handle the given render type,
* otherwise false
*/
public boolean handleRenderType(ItemStack item, ItemRenderType type);
/**
* Checks if certain helper functionality should be executed for this renderer.
* See ItemRendererHelper for more info
*
* @param type The render type
* @param item The ItemStack being rendered
* @param helper The type of helper functionality to be ran
* @return True to run the helper functionality, false to not.
*/
public boolean shouldUseRenderHelper(ItemRenderType type, ItemStack item, ItemRendererHelper helper);
/**
* Called to do the actual rendering, see ItemRenderType for details on when specific
* types are run, and what extra data is passed into the data parameter.
*
* @param type The render type
* @param item The ItemStack being rendered
* @param data Extra Type specific data
*/
public void renderItem(ItemRenderType type, ItemStack item, Object... data);
}
@@ -1,17 +0,0 @@
/*
* This software is provided under the terms of the Minecraft Forge Public
* License v1.0.
*/
package net.minecraftforge.client;
public interface IRenderContextHandler
{
/** Run before the specified rendering context.
*/
public void beforeRenderContext();
/** Run after the specified rendering context.
*/
public void afterRenderContext();
}
@@ -1,12 +0,0 @@
package net.minecraftforge.client;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.WorldClient;
public abstract class IRenderHandler
{
@SideOnly(Side.CLIENT)
public abstract void render(float partialTicks, WorldClient world, Minecraft mc);
}
@@ -1,92 +0,0 @@
/**
* This software is provided under the terms of the Minecraft Forge Public
* License v1.0.
*/
package net.minecraftforge.client;
import java.util.BitSet;
import org.lwjgl.opengl.Display;
import net.minecraft.block.Block;
import net.minecraft.entity.Entity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.client.renderer.RenderBlocks;
import net.minecraft.world.World;
import net.minecraftforge.client.IItemRenderer.ItemRenderType;
import net.minecraftforge.common.MinecraftForge;
public class MinecraftForgeClient
{
private static IItemRenderer[] customItemRenderers = new IItemRenderer[Item.itemsList.length];
/**
* Register a custom renderer for a specific item. This can be used to
* render the item in-world as an EntityItem, when the item is equipped, or
* when the item is in an inventory slot.
* @param itemID The item ID (shifted index) to handle rendering.
* @param renderer The IItemRenderer interface that handles rendering for
* this item.
*/
public static void registerItemRenderer(int itemID, IItemRenderer renderer)
{
customItemRenderers[itemID] = renderer;
}
public static IItemRenderer getItemRenderer(ItemStack item, ItemRenderType type)
{
IItemRenderer renderer = customItemRenderers[item.itemID];
if (renderer != null && renderer.handleRenderType(item, type))
{
return customItemRenderers[item.itemID];
}
return null;
}
public static int getRenderPass()
{
return ForgeHooksClient.renderPass;
}
public static int getStencilBits()
{
return ForgeHooksClient.stencilBits;
}
private static BitSet stencilBits = new BitSet(getStencilBits());
static
{
stencilBits.set(0,getStencilBits());
}
/**
* Reserve a stencil bit for use in rendering
*
* @return A bit or -1 if no further stencil bits are available
*/
public static int reserveStencilBit()
{
int bit = stencilBits.nextSetBit(0);
if (bit >= 0)
{
stencilBits.clear(bit);
}
return bit;
}
/**
* Release the stencil bit for other use
*
* @param bit The bit from {@link #reserveStencilBit()}
*/
public static void releaseStencilBit(int bit)
{
if (bit >= 0 && bit < getStencilBits())
{
stencilBits.set(bit);
}
}
}
@@ -1,14 +0,0 @@
package net.minecraftforge.client.event;
import net.minecraftforge.event.Cancelable;
import net.minecraftforge.event.Event;
@Cancelable
public class ClientChatReceivedEvent extends Event
{
public String message;
public ClientChatReceivedEvent(String message)
{
this.message = message;
}
}
@@ -1,30 +0,0 @@
package net.minecraftforge.client.event;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.client.renderer.RenderGlobal;
import net.minecraftforge.event.Cancelable;
import net.minecraftforge.event.Event;
@Cancelable
public class DrawBlockHighlightEvent extends Event
{
public final RenderGlobal context;
public final EntityPlayer player;
public final MovingObjectPosition target;
public final int subID;
public final ItemStack currentItem;
public final float partialTicks;
public DrawBlockHighlightEvent(RenderGlobal context, EntityPlayer player, MovingObjectPosition target, int subID, ItemStack currentItem, float partialTicks)
{
this.context = context;
this.player = player;
this.target = target;
this.subID = subID;
this.currentItem = currentItem;
this.partialTicks= partialTicks;
}
}
@@ -1,82 +0,0 @@
package net.minecraftforge.client.event;
import java.util.ArrayList;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraftforge.event.Cancelable;
import net.minecraftforge.event.Event;
@Cancelable
public class RenderGameOverlayEvent extends Event
{
public static enum ElementType
{
ALL,
HELMET,
PORTAL,
CROSSHAIRS,
BOSSHEALTH,
ARMOR,
HEALTH,
FOOD,
AIR,
HOTBAR,
EXPERIENCE,
TEXT,
HEALTHMOUNT,
JUMPBAR
}
public final float partialTicks;
public final ScaledResolution resolution;
public final int mouseX;
public final int mouseY;
public final ElementType type;
public RenderGameOverlayEvent(float partialTicks, ScaledResolution resolution, int mouseX, int mouseY)
{
this.partialTicks = partialTicks;
this.resolution = resolution;
this.mouseX = mouseX;
this.mouseY = mouseY;
this.type = null;
}
private RenderGameOverlayEvent(RenderGameOverlayEvent parent, ElementType type)
{
this.partialTicks = parent.partialTicks;
this.resolution = parent.resolution;
this.mouseX = parent.mouseX;
this.mouseY = parent.mouseY;
this.type = type;
}
public static class Pre extends RenderGameOverlayEvent
{
public Pre(RenderGameOverlayEvent parent, ElementType type)
{
super(parent, type);
}
}
public static class Post extends RenderGameOverlayEvent
{
public Post(RenderGameOverlayEvent parent, ElementType type)
{
super(parent, type);
}
@Override public boolean isCancelable(){ return false; }
}
public static class Text extends Pre
{
public final ArrayList<String> left;
public final ArrayList<String> right;
public Text(RenderGameOverlayEvent parent, ArrayList<String> left, ArrayList<String> right)
{
super(parent, ElementType.TEXT);
this.left = left;
this.right = right;
}
}
}
@@ -1,33 +0,0 @@
package net.minecraftforge.client.event;
import net.minecraft.client.renderer.entity.RendererLivingEntity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraftforge.event.Cancelable;
import net.minecraftforge.event.Event;
public abstract class RenderLivingEvent extends Event
{
public final EntityLivingBase entity;
public final RendererLivingEntity renderer;
public RenderLivingEvent(EntityLivingBase entity, RendererLivingEntity renderer)
{
this.entity = entity;
this.renderer = renderer;
}
public abstract static class Specials extends RenderLivingEvent
{
public Specials(EntityLivingBase entity, RendererLivingEntity renderer){ super(entity, renderer); }
@Cancelable
public static class Pre extends Specials
{
public Pre(EntityLivingBase entity, RendererLivingEntity renderer){ super(entity, renderer); }
}
public static class Post extends Specials
{
public Post(EntityLivingBase entity, RendererLivingEntity renderer){ super(entity, renderer); }
}
}
}
@@ -1,72 +0,0 @@
package net.minecraftforge.client.event;
import net.minecraft.client.renderer.entity.RenderPlayer;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraftforge.event.Cancelable;
import net.minecraftforge.event.entity.player.PlayerEvent;
public abstract class RenderPlayerEvent extends PlayerEvent
{
public final RenderPlayer renderer;
public RenderPlayerEvent(EntityPlayer player, RenderPlayer renderer)
{
super(player);
this.renderer = renderer;
}
@Cancelable
public static class Pre extends RenderPlayerEvent
{
public Pre(EntityPlayer player, RenderPlayer renderer){ super(player, renderer); }
}
public static class Post extends RenderPlayerEvent
{
public Post(EntityPlayer player, RenderPlayer renderer){ super(player, renderer); }
}
public abstract static class Specials extends RenderPlayerEvent
{
public final float partialTicks;
public Specials(EntityPlayer player, RenderPlayer renderer, float partialTicks)
{
super(player, renderer);
this.partialTicks = partialTicks;
}
@Cancelable
public static class Pre extends Specials
{
public boolean renderHelmet = true;
public boolean renderCape = true;
public boolean renderItem = true;
public Pre(EntityPlayer player, RenderPlayer renderer, float partialTicks){ super(player, renderer, partialTicks); }
}
public static class Post extends Specials
{
public Post(EntityPlayer player, RenderPlayer renderer, float partialTicks){ super(player, renderer, partialTicks); }
}
}
public static class SetArmorModel extends RenderPlayerEvent
{
/**
* Setting this to any value besides -1 will result in the function being
* Immediately exited with the return value specified.
*/
public int result = -1;
public final int slot;
public final float partialTick;
public final ItemStack stack;
public SetArmorModel(EntityPlayer player, RenderPlayer renderer, int slot, float partialTick, ItemStack stack)
{
super(player, renderer);
this.slot = slot;
this.partialTick = partialTick;
this.stack = stack;
}
}
}
@@ -1,15 +0,0 @@
package net.minecraftforge.client.event;
import net.minecraft.client.renderer.RenderGlobal;
import net.minecraftforge.event.Event;
public class RenderWorldLastEvent extends Event
{
public final RenderGlobal context;
public final float partialTicks;
public RenderWorldLastEvent(RenderGlobal context, float partialTicks)
{
this.context = context;
this.partialTicks = partialTicks;
}
}
@@ -1,35 +0,0 @@
package net.minecraftforge.client.event;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraftforge.event.Event;
public class TextureStitchEvent extends Event
{
public final TextureMap map;
public TextureStitchEvent(TextureMap map)
{
this.map = map;
}
/**
* Fired when the TextureMap is told to refresh it's stitched texture.
* Called after the Stitched list is cleared, but before any blocks or items
* add themselves to the list.
*/
public static class Pre extends TextureStitchEvent
{
public Pre(TextureMap map){ super(map); }
}
/**
* This event is fired once the texture map has loaded all textures and
* stitched them together. All Icons should have there locations defined
* by the time this is fired.
*/
public static class Post extends TextureStitchEvent
{
public Post(TextureMap map){ super(map); }
}
}
@@ -1,15 +0,0 @@
package net.minecraftforge.client.event.sound;
import net.minecraft.client.audio.SoundManager;
import net.minecraft.client.audio.SoundPoolEntry;
/**
* 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.
*/
public class PlayBackgroundMusicEvent extends SoundResultEvent
{
public PlayBackgroundMusicEvent(SoundManager manager, SoundPoolEntry entry)
{ super(manager, entry, null, 0.0f, 0.0f); }
}
@@ -1,10 +0,0 @@
package net.minecraftforge.client.event.sound;
import net.minecraft.client.audio.SoundManager;
import net.minecraft.client.audio.SoundPoolEntry;
public class PlaySoundEffectEvent extends SoundResultEvent
{
public PlaySoundEffectEvent(SoundManager manager, SoundPoolEntry source, String name, float volume, float pitch)
{ super(manager, source, name, volume, pitch); }
}
@@ -1,14 +0,0 @@
package net.minecraftforge.client.event.sound;
import net.minecraft.client.audio.SoundManager;
public class PlaySoundEffectSourceEvent extends SoundEvent
{
public final SoundManager manager;
public final String name;
public PlaySoundEffectSourceEvent(SoundManager manager, String name)
{
this.manager = manager;
this.name = name;
}
}
@@ -1,25 +0,0 @@
package net.minecraftforge.client.event.sound;
import net.minecraft.client.audio.SoundManager;
import net.minecraft.client.audio.SoundPoolEntry;
/***
* 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.
*/
public class PlaySoundEvent extends SoundResultEvent
{
public final float x;
public final float y;
public final float z;
public PlaySoundEvent(SoundManager manager, SoundPoolEntry source, String name, float x, float y, float z, float volume, float pitch)
{
super(manager, source, name, volume, pitch);
this.x = x;
this.y = y;
this.z = z;
}
}
@@ -1,20 +0,0 @@
package net.minecraftforge.client.event.sound;
import net.minecraft.client.audio.SoundManager;
public class PlaySoundSourceEvent extends SoundEvent
{
public final SoundManager manager;
public final String name;
public final float x;
public final float y;
public final float z;
public PlaySoundSourceEvent(SoundManager manager, String name, float x, float y, float z)
{
this.manager = manager;
this.name = name;
this.x = x;
this.y = y;
this.z = z;
}
}
@@ -1,26 +0,0 @@
package net.minecraftforge.client.event.sound;
import net.minecraft.client.audio.SoundManager;
import net.minecraft.client.audio.SoundPoolEntry;
/**
* 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.
*
*/
public class PlayStreamingEvent extends SoundResultEvent
{
public final float x;
public final float y;
public final float z;
public PlayStreamingEvent(SoundManager manager, SoundPoolEntry source, String name, float x, float y, float z)
{
super(manager, source, name, 0.0f, 0.0f);
this.x = x;
this.y = y;
this.z = z;
}
}
@@ -1,20 +0,0 @@
package net.minecraftforge.client.event.sound;
import net.minecraft.client.audio.SoundManager;
public class PlayStreamingSourceEvent extends SoundEvent
{
public final SoundManager manager;
public final String name;
public final float x;
public final float y;
public final float z;
public PlayStreamingSourceEvent(SoundManager manager, String name, float x, float y, float z)
{
this.manager = manager;
this.name = name;
this.x = x;
this.y = y;
this.z = z;
}
}
@@ -1,19 +0,0 @@
package net.minecraftforge.client.event.sound;
import net.minecraft.entity.Entity;
import net.minecraft.client.audio.SoundManager;
import net.minecraft.client.audio.SoundPoolEntry;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.Cancelable;
import net.minecraftforge.event.Event;
public class SoundEvent extends Event
{
public SoundEvent(){}
public static SoundPoolEntry getResult(SoundResultEvent event)
{
MinecraftForge.EVENT_BUS.post(event);
return event.result;
}
}
@@ -1,16 +0,0 @@
package net.minecraftforge.client.event.sound;
import net.minecraft.client.audio.SoundManager;
/**
* Raised by the SoundManager.loadSoundSettings, this would be a good place for
* adding your custom sounds to the SoundPool.
*/
public class SoundLoadEvent extends SoundEvent
{
public final SoundManager manager;
public SoundLoadEvent(SoundManager manager)
{
this.manager = manager;
}
}
@@ -1,24 +0,0 @@
package net.minecraftforge.client.event.sound;
import net.minecraft.client.audio.SoundManager;
import net.minecraft.client.audio.SoundPoolEntry;
public abstract class SoundResultEvent extends SoundEvent
{
public final SoundManager manager;
public final SoundPoolEntry source;
public final String name;
public final float volume;
public final float pitch;
public SoundPoolEntry result;
public SoundResultEvent(SoundManager manager, SoundPoolEntry source, String name, float volume, float pitch)
{
this.manager = manager;
this.source = source;
this.name = name;
this.volume = volume;
this.pitch = pitch;
this.result = source;
}
}
@@ -1,16 +0,0 @@
package net.minecraftforge.client.event.sound;
import net.minecraft.client.audio.SoundManager;
/**
* 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.
*/
public class SoundSetupEvent extends SoundEvent
{
public final SoundManager manager;
public SoundSetupEvent(SoundManager manager)
{
this.manager = manager;
}
}
@@ -1,82 +0,0 @@
package net.minecraftforge.client.model;
import java.io.InputStream;
import java.net.URL;
import java.util.Collection;
import java.util.Map;
import net.minecraftforge.client.model.obj.ObjModelLoader;
import com.google.common.collect.Maps;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
/**
* Common interface for advanced model loading from files, based on file suffix
* Model support can be queried through the {@link #getSupportedSuffixes()} method.
* Instances can be created by calling {@link #loadModel(String)} with a class-loadable-path
*
* @author cpw
*
*/
@SideOnly(Side.CLIENT)
public class AdvancedModelLoader {
private static Map<String, IModelCustomLoader> instances = Maps.newHashMap();
/**
* Register a new model handler
* @param modelHandler The model handler to register
*/
public static void registerModelHandler(IModelCustomLoader modelHandler)
{
for (String suffix : modelHandler.getSuffixes())
{
instances.put(suffix, modelHandler);
}
}
/**
* Load the model from the supplied classpath resolvable resource name
* @param resourceName The resource name
* @return A model
* @throws IllegalArgumentException if the resource name cannot be understood
* @throws ModelFormatException if the underlying model handler cannot parse the model format
*/
public static IModelCustom loadModel(String resourceName) throws IllegalArgumentException, ModelFormatException
{
int i = resourceName.lastIndexOf('.');
if (i == -1)
{
FMLLog.severe("The resource name %s is not valid", resourceName);
throw new IllegalArgumentException("The resource name is not valid");
}
String suffix = resourceName.substring(i+1);
IModelCustomLoader loader = instances.get(suffix);
if (loader == null)
{
FMLLog.severe("The resource name %s is not supported", resourceName);
throw new IllegalArgumentException("The resource name is not supported");
}
URL resource = AdvancedModelLoader.class.getResource(resourceName);
if (resource == null)
{
FMLLog.severe("The resource name %s could not be found", resourceName);
throw new IllegalArgumentException("The resource name could not be found");
}
return loader.loadInstance(resourceName, resource);
}
public static Collection<String> getSupportedSuffixes()
{
return instances.keySet();
}
static
{
registerModelHandler(new ObjModelLoader());
}
}
@@ -1,9 +0,0 @@
package net.minecraftforge.client.model;
public interface IModelCustom {
String getType();
void renderAll();
void renderPart(String partName);
}
@@ -1,31 +0,0 @@
package net.minecraftforge.client.model;
import java.io.InputStream;
import java.net.URL;
/**
* Instances of this class act as factories for their model type
*
* @author cpw
*
*/
public interface IModelCustomLoader {
/**
* Get the main type name for this loader
* @return the type name
*/
String getType();
/**
* Get resource suffixes this model loader recognizes
* @return a list of suffixes
*/
String[] getSuffixes();
/**
* Load a model instance from the supplied path
* @param resourceName The resource name to load
* @param resource The URL associated with the classloader resource
* @return A model instance
* @throws ModelFormatException if the model format is not correct
*/
IModelCustom loadInstance(String resourceName, URL resource) throws ModelFormatException;
}
@@ -1,31 +0,0 @@
package net.minecraftforge.client.model;
/**
* Thrown if there is a problem parsing the model
*
* @author cpw
*
*/
public class ModelFormatException extends RuntimeException {
public ModelFormatException()
{
super();
}
public ModelFormatException(String message, Throwable cause)
{
super(message, cause);
}
public ModelFormatException(String message)
{
super(message);
}
public ModelFormatException(Throwable cause)
{
super(cause);
}
}
@@ -1,84 +0,0 @@
package net.minecraftforge.client.model.obj;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.util.Vec3;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class Face
{
public Vertex[] vertices;
public Vertex[] vertexNormals;
public Vertex faceNormal;
public TextureCoordinate[] textureCoordinates;
public void addFaceForRender(Tessellator tessellator)
{
addFaceForRender(tessellator, 0.0005F);
}
public void addFaceForRender(Tessellator tessellator, float textureOffset)
{
if (faceNormal == null)
{
faceNormal = this.calculateFaceNormal();
}
tessellator.setNormal(faceNormal.x, faceNormal.y, faceNormal.z);
float averageU = 0F;
float averageV = 0F;
if ((textureCoordinates != null) && (textureCoordinates.length > 0))
{
for (int i = 0; i < textureCoordinates.length; ++i)
{
averageU += textureCoordinates[i].u;
averageV += textureCoordinates[i].v;
}
averageU = averageU / textureCoordinates.length;
averageV = averageV / textureCoordinates.length;
}
float offsetU, offsetV;
for (int i = 0; i < vertices.length; ++i)
{
if ((textureCoordinates != null) && (textureCoordinates.length > 0))
{
offsetU = textureOffset;
offsetV = textureOffset;
if (textureCoordinates[i].u > averageU)
{
offsetU = -offsetU;
}
if (textureCoordinates[i].v > averageV)
{
offsetV = -offsetV;
}
tessellator.addVertexWithUV(vertices[i].x, vertices[i].y, vertices[i].z, textureCoordinates[i].u + offsetU, textureCoordinates[i].v + offsetV);
}
else
{
tessellator.addVertex(vertices[i].x, vertices[i].y, vertices[i].z);
}
}
}
public Vertex calculateFaceNormal()
{
Vec3 v1 = Vec3.createVectorHelper(vertices[1].x - vertices[0].x, vertices[1].y - vertices[0].y, vertices[1].z - vertices[0].z);
Vec3 v2 = Vec3.createVectorHelper(vertices[2].x - vertices[0].x, vertices[2].y - vertices[0].y, vertices[2].z - vertices[0].z);
Vec3 normalVector = null;
normalVector = v1.crossProduct(v2).normalize();
return new Vertex((float) normalVector.xCoord, (float) normalVector.yCoord, (float) normalVector.zCoord);
}
}
@@ -1,54 +0,0 @@
package net.minecraftforge.client.model.obj;
import java.util.ArrayList;
import net.minecraft.client.renderer.Tessellator;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class GroupObject
{
public String name;
public ArrayList<Face> faces = new ArrayList<Face>();
public int glDrawingMode;
public GroupObject()
{
this("");
}
public GroupObject(String name)
{
this(name, -1);
}
public GroupObject(String name, int glDrawingMode)
{
this.name = name;
this.glDrawingMode = glDrawingMode;
}
public void render()
{
if (faces.size() > 0)
{
Tessellator tessellator = Tessellator.instance;
tessellator.startDrawing(glDrawingMode);
render(tessellator);
tessellator.draw();
}
}
public void render(Tessellator tessellator)
{
if (faces.size() > 0)
{
for (Face face : faces)
{
face.addFaceForRender(tessellator);
}
}
}
}
@@ -1,31 +0,0 @@
package net.minecraftforge.client.model.obj;
import java.io.InputStream;
import java.net.URL;
import net.minecraftforge.client.model.IModelCustom;
import net.minecraftforge.client.model.IModelCustomLoader;
import net.minecraftforge.client.model.ModelFormatException;
public class ObjModelLoader implements IModelCustomLoader {
@Override
public String getType()
{
return "OBJ model";
}
private static final String[] types = { "obj" };
@Override
public String[] getSuffixes()
{
return types;
}
@Override
public IModelCustom loadInstance(String resourceName, URL resource) throws ModelFormatException
{
return new WavefrontObject(resourceName, resource);
}
}
@@ -1,23 +0,0 @@
package net.minecraftforge.client.model.obj;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class TextureCoordinate
{
public float u, v, w;
public TextureCoordinate(float u, float v)
{
this(u, v, 0F);
}
public TextureCoordinate(float u, float v, float w)
{
this.u = u;
this.v = v;
this.w = w;
}
}
@@ -1,23 +0,0 @@
package net.minecraftforge.client.model.obj;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class Vertex
{
public float x, y, z;
public Vertex(float x, float y)
{
this(x, y, 0F);
}
public Vertex(float x, float y, float z)
{
this.x = x;
this.y = y;
this.z = z;
}
}
@@ -1,583 +0,0 @@
package net.minecraftforge.client.model.obj;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.minecraft.client.renderer.Tessellator;
import net.minecraftforge.client.model.IModelCustom;
import net.minecraftforge.client.model.ModelFormatException;
import org.lwjgl.opengl.GL11;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
/**
* Wavefront Object importer
* Based heavily off of the specifications found at http://en.wikipedia.org/wiki/Wavefront_.obj_file
*/
@SideOnly(Side.CLIENT)
public class WavefrontObject implements IModelCustom
{
private static Pattern vertexPattern = Pattern.compile("(v( (\\-){0,1}\\d+\\.\\d+){3,4} *\\n)|(v( (\\-){0,1}\\d+\\.\\d+){3,4} *$)");
private static Pattern vertexNormalPattern = Pattern.compile("(vn( (\\-){0,1}\\d+\\.\\d+){3,4} *\\n)|(vn( (\\-){0,1}\\d+\\.\\d+){3,4} *$)");
private static Pattern textureCoordinatePattern = Pattern.compile("(vt( (\\-){0,1}\\d+\\.\\d+){2,3} *\\n)|(vt( (\\-){0,1}\\d+\\.\\d+){2,3} *$)");
private static Pattern face_V_VT_VN_Pattern = Pattern.compile("(f( \\d+/\\d+/\\d+){3,4} *\\n)|(f( \\d+/\\d+/\\d+){3,4} *$)");
private static Pattern face_V_VT_Pattern = Pattern.compile("(f( \\d+/\\d+){3,4} *\\n)|(f( \\d+/\\d+){3,4} *$)");
private static Pattern face_V_VN_Pattern = Pattern.compile("(f( \\d+//\\d+){3,4} *\\n)|(f( \\d+//\\d+){3,4} *$)");
private static Pattern face_V_Pattern = Pattern.compile("(f( \\d+){3,4} *\\n)|(f( \\d+){3,4} *$)");
private static Pattern groupObjectPattern = Pattern.compile("([go]( [\\w\\d]+) *\\n)|([go]( [\\w\\d]+) *$)");
private static Matcher vertexMatcher, vertexNormalMatcher, textureCoordinateMatcher;
private static Matcher face_V_VT_VN_Matcher, face_V_VT_Matcher, face_V_VN_Matcher, face_V_Matcher;
private static Matcher groupObjectMatcher;
public ArrayList<Vertex> vertices = new ArrayList<Vertex>();
public ArrayList<Vertex> vertexNormals = new ArrayList<Vertex>();
public ArrayList<TextureCoordinate> textureCoordinates = new ArrayList<TextureCoordinate>();
public ArrayList<GroupObject> groupObjects = new ArrayList<GroupObject>();
private GroupObject currentGroupObject;
private String fileName;
public WavefrontObject(String fileName, URL resource) throws ModelFormatException
{
this.fileName = fileName;
loadObjModel(resource);
}
private void loadObjModel(URL fileURL) throws ModelFormatException
{
BufferedReader reader = null;
InputStream inputStream = null;
String currentLine = null;
int lineCount = 0;
try
{
inputStream = fileURL.openStream();
reader = new BufferedReader(new InputStreamReader(inputStream));
while ((currentLine = reader.readLine()) != null)
{
lineCount++;
currentLine = currentLine.replaceAll("\\s+", " ").trim();
if (currentLine.startsWith("#") || currentLine.length() == 0)
{
continue;
}
else if (currentLine.startsWith("v "))
{
Vertex vertex = parseVertex(currentLine, lineCount);
if (vertex != null)
{
vertices.add(vertex);
}
}
else if (currentLine.startsWith("vn "))
{
Vertex vertex = parseVertexNormal(currentLine, lineCount);
if (vertex != null)
{
vertexNormals.add(vertex);
}
}
else if (currentLine.startsWith("vt "))
{
TextureCoordinate textureCoordinate = parseTextureCoordinate(currentLine, lineCount);
if (textureCoordinate != null)
{
textureCoordinates.add(textureCoordinate);
}
}
else if (currentLine.startsWith("f "))
{
if (currentGroupObject == null)
{
currentGroupObject = new GroupObject("Default");
}
Face face = parseFace(currentLine, lineCount);
if (face != null)
{
currentGroupObject.faces.add(face);
}
}
else if (currentLine.startsWith("g ") | currentLine.startsWith("o "))
{
GroupObject group = parseGroupObject(currentLine, lineCount);
if (group != null)
{
if (currentGroupObject != null)
{
groupObjects.add(currentGroupObject);
}
}
currentGroupObject = group;
}
}
groupObjects.add(currentGroupObject);
}
catch (IOException e)
{
throw new ModelFormatException("IO Exception reading model format", e);
}
finally
{
try
{
reader.close();
}
catch (IOException e)
{
// hush
}
try
{
inputStream.close();
}
catch (IOException e)
{
// hush
}
}
}
public void renderAll()
{
Tessellator tessellator = Tessellator.instance;
if (currentGroupObject != null)
{
tessellator.startDrawing(currentGroupObject.glDrawingMode);
}
else
{
tessellator.startDrawing(GL11.GL_TRIANGLES);
}
for (GroupObject groupObject : groupObjects)
{
groupObject.render(tessellator);
}
tessellator.draw();
}
public void renderOnly(String... groupNames)
{
for (GroupObject groupObject : groupObjects)
{
for (String groupName : groupNames)
{
if (groupName.equalsIgnoreCase(groupObject.name))
{
groupObject.render();
}
}
}
}
public void renderPart(String partName)
{
for (GroupObject groupObject : groupObjects)
{
if (partName.equalsIgnoreCase(groupObject.name))
{
groupObject.render();
}
}
}
public void renderAllExcept(String... excludedGroupNames)
{
for (GroupObject groupObject : groupObjects)
{
for (String excludedGroupName : excludedGroupNames)
{
if (!excludedGroupName.equalsIgnoreCase(groupObject.name))
{
groupObject.render();
}
}
}
}
private Vertex parseVertex(String line, int lineCount) throws ModelFormatException
{
Vertex vertex = null;
if (isValidVertexLine(line))
{
line = line.substring(line.indexOf(" ") + 1);
String[] tokens = line.split(" ");
try
{
if (tokens.length == 2)
{
return new Vertex(Float.parseFloat(tokens[0]), Float.parseFloat(tokens[1]));
}
else if (tokens.length == 3)
{
return new Vertex(Float.parseFloat(tokens[0]), Float.parseFloat(tokens[1]), Float.parseFloat(tokens[2]));
}
}
catch (NumberFormatException e)
{
throw new ModelFormatException(String.format("Number formatting error at line %d",lineCount), e);
}
}
else
{
throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Incorrect format");
}
return vertex;
}
private Vertex parseVertexNormal(String line, int lineCount) throws ModelFormatException
{
Vertex vertexNormal = null;
if (isValidVertexNormalLine(line))
{
line = line.substring(line.indexOf(" ") + 1);
String[] tokens = line.split(" ");
try
{
if (tokens.length == 3)
return new Vertex(Float.parseFloat(tokens[0]), Float.parseFloat(tokens[1]), Float.parseFloat(tokens[2]));
}
catch (NumberFormatException e)
{
throw new ModelFormatException(String.format("Number formatting error at line %d",lineCount), e);
}
}
else
{
throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Incorrect format");
}
return vertexNormal;
}
private TextureCoordinate parseTextureCoordinate(String line, int lineCount) throws ModelFormatException
{
TextureCoordinate textureCoordinate = null;
if (isValidTextureCoordinateLine(line))
{
line = line.substring(line.indexOf(" ") + 1);
String[] tokens = line.split(" ");
try
{
if (tokens.length == 2)
return new TextureCoordinate(Float.parseFloat(tokens[0]), 1 - Float.parseFloat(tokens[1]));
else if (tokens.length == 3)
return new TextureCoordinate(Float.parseFloat(tokens[0]), 1 - Float.parseFloat(tokens[1]), Float.parseFloat(tokens[2]));
}
catch (NumberFormatException e)
{
throw new ModelFormatException(String.format("Number formatting error at line %d",lineCount), e);
}
}
else
{
throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Incorrect format");
}
return textureCoordinate;
}
private Face parseFace(String line, int lineCount) throws ModelFormatException
{
Face face = null;
if (isValidFaceLine(line))
{
face = new Face();
String trimmedLine = line.substring(line.indexOf(" ") + 1);
String[] tokens = trimmedLine.split(" ");
String[] subTokens = null;
if (tokens.length == 3)
{
if (currentGroupObject.glDrawingMode == -1)
{
currentGroupObject.glDrawingMode = GL11.GL_TRIANGLES;
}
else if (currentGroupObject.glDrawingMode != GL11.GL_TRIANGLES)
{
throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Invalid number of points for face (expected 4, found " + tokens.length + ")");
}
}
else if (tokens.length == 4)
{
if (currentGroupObject.glDrawingMode == -1)
{
currentGroupObject.glDrawingMode = GL11.GL_QUADS;
}
else if (currentGroupObject.glDrawingMode != GL11.GL_QUADS)
{
throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Invalid number of points for face (expected 3, found " + tokens.length + ")");
}
}
// f v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3 ...
if (isValidFace_V_VT_VN_Line(line))
{
face.vertices = new Vertex[tokens.length];
face.textureCoordinates = new TextureCoordinate[tokens.length];
face.vertexNormals = new Vertex[tokens.length];
for (int i = 0; i < tokens.length; ++i)
{
subTokens = tokens[i].split("/");
face.vertices[i] = vertices.get(Integer.parseInt(subTokens[0]) - 1);
face.textureCoordinates[i] = textureCoordinates.get(Integer.parseInt(subTokens[1]) - 1);
face.vertexNormals[i] = vertexNormals.get(Integer.parseInt(subTokens[2]) - 1);
}
face.faceNormal = face.calculateFaceNormal();
}
// f v1/vt1 v2/vt2 v3/vt3 ...
else if (isValidFace_V_VT_Line(line))
{
face.vertices = new Vertex[tokens.length];
face.textureCoordinates = new TextureCoordinate[tokens.length];
for (int i = 0; i < tokens.length; ++i)
{
subTokens = tokens[i].split("/");
face.vertices[i] = vertices.get(Integer.parseInt(subTokens[0]) - 1);
face.textureCoordinates[i] = textureCoordinates.get(Integer.parseInt(subTokens[1]) - 1);
}
face.faceNormal = face.calculateFaceNormal();
}
// f v1//vn1 v2//vn2 v3//vn3 ...
else if (isValidFace_V_VN_Line(line))
{
face.vertices = new Vertex[tokens.length];
face.vertexNormals = new Vertex[tokens.length];
for (int i = 0; i < tokens.length; ++i)
{
subTokens = tokens[i].split("//");
face.vertices[i] = vertices.get(Integer.parseInt(subTokens[0]) - 1);
face.vertexNormals[i] = vertexNormals.get(Integer.parseInt(subTokens[1]) - 1);
}
face.faceNormal = face.calculateFaceNormal();
}
// f v1 v2 v3 ...
else if (isValidFace_V_Line(line))
{
face.vertices = new Vertex[tokens.length];
for (int i = 0; i < tokens.length; ++i)
{
face.vertices[i] = vertices.get(Integer.parseInt(tokens[i]) - 1);
}
face.faceNormal = face.calculateFaceNormal();
}
else
{
throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Incorrect format");
}
}
else
{
throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Incorrect format");
}
return face;
}
private GroupObject parseGroupObject(String line, int lineCount) throws ModelFormatException
{
GroupObject group = null;
if (isValidGroupObjectLine(line))
{
String trimmedLine = line.substring(line.indexOf(" ") + 1);
if (trimmedLine.length() > 0)
{
group = new GroupObject(trimmedLine);
}
}
else
{
throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Incorrect format");
}
return group;
}
/***
* Verifies that the given line from the model file is a valid vertex
* @param line the line being validated
* @return true if the line is a valid vertex, false otherwise
*/
private static boolean isValidVertexLine(String line)
{
if (vertexMatcher != null)
{
vertexMatcher.reset();
}
vertexMatcher = vertexPattern.matcher(line);
return vertexMatcher.matches();
}
/***
* Verifies that the given line from the model file is a valid vertex normal
* @param line the line being validated
* @return true if the line is a valid vertex normal, false otherwise
*/
private static boolean isValidVertexNormalLine(String line)
{
if (vertexNormalMatcher != null)
{
vertexNormalMatcher.reset();
}
vertexNormalMatcher = vertexNormalPattern.matcher(line);
return vertexNormalMatcher.matches();
}
/***
* Verifies that the given line from the model file is a valid texture coordinate
* @param line the line being validated
* @return true if the line is a valid texture coordinate, false otherwise
*/
private static boolean isValidTextureCoordinateLine(String line)
{
if (textureCoordinateMatcher != null)
{
textureCoordinateMatcher.reset();
}
textureCoordinateMatcher = textureCoordinatePattern.matcher(line);
return textureCoordinateMatcher.matches();
}
/***
* Verifies that the given line from the model file is a valid face that is described by vertices, texture coordinates, and vertex normals
* @param line the line being validated
* @return true if the line is a valid face that matches the format "f v1/vt1/vn1 ..." (with a minimum of 3 points in the face, and a maximum of 4), false otherwise
*/
private static boolean isValidFace_V_VT_VN_Line(String line)
{
if (face_V_VT_VN_Matcher != null)
{
face_V_VT_VN_Matcher.reset();
}
face_V_VT_VN_Matcher = face_V_VT_VN_Pattern.matcher(line);
return face_V_VT_VN_Matcher.matches();
}
/***
* Verifies that the given line from the model file is a valid face that is described by vertices and texture coordinates
* @param line the line being validated
* @return true if the line is a valid face that matches the format "f v1/vt1 ..." (with a minimum of 3 points in the face, and a maximum of 4), false otherwise
*/
private static boolean isValidFace_V_VT_Line(String line)
{
if (face_V_VT_Matcher != null)
{
face_V_VT_Matcher.reset();
}
face_V_VT_Matcher = face_V_VT_Pattern.matcher(line);
return face_V_VT_Matcher.matches();
}
/***
* Verifies that the given line from the model file is a valid face that is described by vertices and vertex normals
* @param line the line being validated
* @return true if the line is a valid face that matches the format "f v1//vn1 ..." (with a minimum of 3 points in the face, and a maximum of 4), false otherwise
*/
private static boolean isValidFace_V_VN_Line(String line)
{
if (face_V_VN_Matcher != null)
{
face_V_VN_Matcher.reset();
}
face_V_VN_Matcher = face_V_VN_Pattern.matcher(line);
return face_V_VN_Matcher.matches();
}
/***
* Verifies that the given line from the model file is a valid face that is described by only vertices
* @param line the line being validated
* @return true if the line is a valid face that matches the format "f v1 ..." (with a minimum of 3 points in the face, and a maximum of 4), false otherwise
*/
private static boolean isValidFace_V_Line(String line)
{
if (face_V_Matcher != null)
{
face_V_Matcher.reset();
}
face_V_Matcher = face_V_Pattern.matcher(line);
return face_V_Matcher.matches();
}
/***
* Verifies that the given line from the model file is a valid face of any of the possible face formats
* @param line the line being validated
* @return true if the line is a valid face that matches any of the valid face formats, false otherwise
*/
private static boolean isValidFaceLine(String line)
{
return isValidFace_V_VT_VN_Line(line) || isValidFace_V_VT_Line(line) || isValidFace_V_VN_Line(line) || isValidFace_V_Line(line);
}
/***
* Verifies that the given line from the model file is a valid group (or object)
* @param line the line being validated
* @return true if the line is a valid group (or object), false otherwise
*/
private static boolean isValidGroupObjectLine(String line)
{
if (groupObjectMatcher != null)
{
groupObjectMatcher.reset();
}
groupObjectMatcher = groupObjectPattern.matcher(line);
return groupObjectMatcher.matches();
}
@Override
public String getType()
{
return "obj";
}
}
@@ -1,642 +0,0 @@
package paulscode.sound.codecs;
import java.io.DataInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.ShortBuffer;
import javax.sound.sampled.AudioFormat;
import paulscode.sound.ICodec;
import paulscode.sound.SoundBuffer;
import paulscode.sound.SoundSystemConfig;
import paulscode.sound.SoundSystemLogger;
import ibxm.FastTracker2;
import ibxm.IBXM;
import ibxm.Module;
import ibxm.ProTracker;
import ibxm.ScreamTracker3;
/**
* The CodecIBXM class provides an ICodec interface for reading from MOD/S3M/XM
* files via the IBXM library.
*<b><i> SoundSystem CodecIBXM Class License:</b></i><br><b><br>
* 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:
*<br>
* 1) You may not falsely claim to be the author of this class or any
* unmodified portion of it.
*<br>
* 2) You may not copyright this class or a modified version of it and then
* sue me for copyright infringement.
*<br>
* 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.
*<br>
* 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
*<br>
* 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.
*<br>
* 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.
* <br><br>
* Author: Paul Lamb
* <br>
* http://www.paulscode.com
*</b><br><br>
*<b>
* This software is based on or using the IBXM library available from
* http://www.geocities.com/sunet2000/
*</b><br><br>
*<br><b>
* IBXM is copyright (c) 2007, Martin Cameron, and is licensed under the BSD
* License.
*<br><br>
* All rights reserved.
*<br><br>
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*<br><br>
* 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.
* <br><br>
* 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.
* <br><br><br></b>
*/
public class CodecIBXM implements ICodec
{
/**
* Used to return a current value from one of the synchronized
* boolean-interface methods.
*/
private static final boolean GET = false;
/**
* Used to set the value in one of the synchronized boolean-interface methods.
*/
private static final boolean SET = true;
/**
* Used when a parameter for one of the synchronized boolean-interface methods
* is not aplicable.
*/
private static final boolean XXX = false;
/**
* True if there is no more data to read in.
*/
private boolean endOfStream = false;
/**
* True if the stream has finished initializing.
*/
private boolean initialized = false;
/**
* Format the converted audio will be in.
*/
private AudioFormat myAudioFormat = null;
/**
* True if the using library requires data read by this codec to be
* reverse-ordered before returning it from methods read() and readAll().
*/
private boolean reverseBytes = false;
/**
* IBXM decoder.
*/
private IBXM ibxm;
/**
* Module instance to be played.
*/
private Module module;
/**
* Duration of the audio (in frames).
*/
private int songDuration;
/**
* Audio read position (in frames).
*/
private int playPosition;
/**
* Processes status messages, warnings, and error messages.
*/
private SoundSystemLogger logger;
/**
* Constructor: Grabs a handle to the logger.
*/
public CodecIBXM()
{
logger = SoundSystemConfig.getLogger();
}
/**
* Tells this codec when it will need to reverse the byte order of
* the data before returning it in the read() and readAll() methods. The
* IBXM library produces audio data in a format that some external audio
* libraries require to be reversed. Derivatives of the Library and Source
* classes for audio libraries which require this type of data to be reversed
* will call the reverseByteOrder() method.
* @param b True if the calling audio library requires byte-reversal.
*/
public void reverseByteOrder( boolean b )
{
reverseBytes = b;
}
/**
* Prepares an audio stream to read from. If another stream is already opened,
* it will be closed and a new audio stream opened in its place.
* @param url URL to an audio file to stream from.
* @return False if an error occurred or if end of stream was reached.
*/
public boolean initialize( URL url )
{
initialized( SET, false );
cleanup();
if( url == null )
{
errorMessage( "url null in method 'initialize'" );
cleanup();
return false;
}
InputStream is = null;
try
{
is = url.openStream();
}
catch( IOException ioe )
{
errorMessage( "Unable to open stream in method 'initialize'" );
printStackTrace( ioe );
return false;
}
if( ibxm == null )
ibxm = new IBXM( 48000 );
if( myAudioFormat == null )
myAudioFormat = new AudioFormat( 48000, 16, 2, true, true );
try
{
setModule( loadModule( is ) );
}
catch( IllegalArgumentException iae )
{
errorMessage( "Illegal argument in method 'initialize'" );
printStackTrace( iae );
if( is != null )
{
try
{
is.close();
}
catch( IOException ioe )
{}
}
return false;
}
catch( IOException ioe )
{
errorMessage( "Error loading module in method 'initialize'" );
printStackTrace( ioe );
if( is != null )
{
try
{
is.close();
}
catch( IOException ioe2 )
{}
}
return false;
}
if( is != null )
{
try
{
is.close();
}
catch( IOException ioe )
{}
}
endOfStream( SET, false );
initialized( SET, true );
return true;
}
/**
* Returns false if the stream is busy initializing.
* @return True if steam is initialized.
*/
public boolean initialized()
{
return initialized( GET, XXX );
}
/**
* Reads in one stream buffer worth of audio data. See
* {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for more
* information about accessing and changing default settings.
* @return The audio data wrapped into a SoundBuffer context.
*/
public SoundBuffer read()
{
if( endOfStream( GET, XXX ) )
return null;
if( module == null )
{
errorMessage( "Module null in method 'read'" );
return null;
}
// Check to make sure there is an audio format:
if( myAudioFormat == null )
{
errorMessage( "Audio Format null in method 'read'" );
return null;
}
int bufferFrameSize = (int) SoundSystemConfig.getStreamingBufferSize()
/ 4;
int frames = songDuration - playPosition;
if( frames > bufferFrameSize )
frames = bufferFrameSize;
if( frames <= 0 )
{
endOfStream( SET, true );
return null;
}
byte[] outputBuffer = new byte[ frames * 4 ];
ibxm.get_audio( outputBuffer, frames );
playPosition += frames;
if( playPosition >= songDuration )
{
endOfStream( SET, true );
}
// Reverse the byte order if necessary:
if( reverseBytes )
reverseBytes( outputBuffer, 0, frames * 4 );
// Wrap the data into a SoundBuffer:
SoundBuffer buffer = new SoundBuffer( outputBuffer, myAudioFormat );
return buffer;
}
/**
* Reads in all the audio data from the stream (up to the default
* "maximum file size". See
* {@link paulscode.sound.SoundSystemConfig SoundSystemConfig} for more
* information about accessing and changing default settings.
* @return the audio data wrapped into a SoundBuffer context.
*/
public SoundBuffer readAll()
{
if( module == null )
{
errorMessage( "Module null in method 'readAll'" );
return null;
}
// Check to make sure there is an audio format:
if( myAudioFormat == null )
{
errorMessage( "Audio Format null in method 'readAll'" );
return null;
}
int bufferFrameSize = (int) SoundSystemConfig.getFileChunkSize()
/ 4;
byte[] outputBuffer = new byte[ bufferFrameSize * 4 ];
// Buffer to contain the audio data:
byte[] fullBuffer = null;
// frames of audio data:
int frames;
// bytes of audio data:
int totalBytes = 0;
while( (!endOfStream(GET, XXX)) &&
(totalBytes < SoundSystemConfig.getMaxFileSize()) )
{
frames = songDuration - playPosition;
if( frames > bufferFrameSize )
frames = bufferFrameSize;
ibxm.get_audio( outputBuffer, frames );
totalBytes += (frames * 4);
fullBuffer = appendByteArrays( fullBuffer, outputBuffer,
frames * 4 );
playPosition += frames;
if( playPosition >= songDuration )
{
endOfStream( SET, true );
}
}
// Reverse the byte order if necessary:
if( reverseBytes )
reverseBytes( fullBuffer, 0, totalBytes );
// Wrap the data into a SoundBuffer:
SoundBuffer buffer = new SoundBuffer( fullBuffer, myAudioFormat );
return buffer;
}
/**
* Returns false if there is still more data available to be read in.
* @return True if end of stream was reached.
*/
public boolean endOfStream()
{
return endOfStream( GET, XXX );
}
/**
* Closes the audio stream and remove references to all instantiated objects.
*/
public void cleanup()
{
// if( ibxm != null )
// ibxm.seek( 0 );
playPosition = 0;
}
/**
* Returns the audio format of the data being returned by the read() and
* readAll() methods.
* @return Information wrapped into an AudioFormat context.
*/
public AudioFormat getAudioFormat()
{
return myAudioFormat;
}
/**
* Decodes the data in the specified InputStream into an instance of
* ibxm.Module.
* @param input an InputStream containing the module file to be decoded.
* @throws IllegalArgumentException if the data is not recognised as a module file.
*/
private static Module loadModule( 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 );
}
/**
* Sets the Module instance to be played.
*/
private void setModule( Module m )
{
if( m != null )
module = m;
ibxm.set_module( module );
songDuration = ibxm.calculate_song_duration();
}
/**
* Internal method for synchronizing access to the boolean 'initialized'.
* @param action GET or SET.
* @param value New value if action == SET, or XXX if action == GET.
* @return True if steam is initialized.
*/
private synchronized boolean initialized( boolean action, boolean value )
{
if( action == SET )
initialized = value;
return initialized;
}
/**
* Internal method for synchronizing access to the boolean 'endOfStream'.
* @param action GET or SET.
* @param value New value if action == SET, or XXX if action == GET.
* @return True if end of stream was reached.
*/
private synchronized boolean endOfStream( boolean action, boolean value )
{
if( action == SET )
endOfStream = value;
return endOfStream;
}
/**
* Trims down the size of the array if it is larger than the specified
* maximum length.
* @param array Array containing audio data.
* @param maxLength Maximum size this array may be.
* @return New array.
*/
private static byte[] trimArray( byte[] array, int maxLength )
{
byte[] trimmedArray = null;
if( array != null && array.length > maxLength )
{
trimmedArray = new byte[maxLength];
System.arraycopy( array, 0, trimmedArray, 0, maxLength );
}
return trimmedArray;
}
/**
* Reverse-orders all bytes contained in the specified array.
* @param buffer Array containing audio data.
*/
public static void reverseBytes( byte[] buffer )
{
reverseBytes( buffer, 0, buffer.length );
}
/**
* Reverse-orders the specified range of bytes contained in the specified array.
* @param buffer Array containing audio data.
* @param offset Array index to begin.
* @param size number of bytes to reverse-order.
*/
public static void reverseBytes( byte[] buffer, int offset, int size )
{
byte b;
for( int i = offset; i < ( offset + size ); i += 2 )
{
b = buffer[i];
buffer[i] = buffer[i + 1];
buffer[i + 1] = b;
}
}
/**
* Converts sound bytes to little-endian format.
* @param audio_bytes The original wave data
* @param two_bytes_data For stereo sounds.
* @return byte array containing the converted data.
*/
private static byte[] convertAudioBytes( byte[] audio_bytes,
boolean two_bytes_data )
{
ByteBuffer dest = ByteBuffer.allocateDirect( audio_bytes.length );
dest.order( ByteOrder.nativeOrder() );
ByteBuffer src = ByteBuffer.wrap( audio_bytes );
src.order( ByteOrder.LITTLE_ENDIAN );
if( two_bytes_data )
{
ShortBuffer dest_short = dest.asShortBuffer();
ShortBuffer src_short = src.asShortBuffer();
while( src_short.hasRemaining() )
{
dest_short.put(src_short.get());
}
}
else
{
while( src.hasRemaining() )
{
dest.put( src.get() );
}
}
dest.rewind();
if( !dest.hasArray() )
{
byte[] arrayBackedBuffer = new byte[dest.capacity()];
dest.get( arrayBackedBuffer );
dest.clear();
return arrayBackedBuffer;
}
return dest.array();
}
/**
* Creates a new array with the second array appended to the end of the first
* array.
* @param arrayOne The first array.
* @param arrayTwo The second array.
* @param length How many bytes to append from the second array.
* @return Byte array containing information from both arrays.
*/
private static byte[] appendByteArrays( byte[] arrayOne, byte[] arrayTwo,
int length )
{
byte[] newArray;
if( arrayOne == null && arrayTwo == null )
{
// no data, just return
return null;
}
else if( arrayOne == null )
{
// create the new array, same length as arrayTwo:
newArray = new byte[ length ];
// fill the new array with the contents of arrayTwo:
System.arraycopy( arrayTwo, 0, newArray, 0, length );
arrayTwo = null;
}
else if( arrayTwo == null )
{
// create the new array, same length as arrayOne:
newArray = new byte[ arrayOne.length ];
// fill the new array with the contents of arrayOne:
System.arraycopy( arrayOne, 0, newArray, 0, arrayOne.length );
arrayOne = null;
}
else
{
// create the new array large enough to hold both arrays:
newArray = new byte[ arrayOne.length + length ];
System.arraycopy( arrayOne, 0, newArray, 0, arrayOne.length );
// fill the new array with the contents of both arrays:
System.arraycopy( arrayTwo, 0, newArray, arrayOne.length,
length );
arrayOne = null;
arrayTwo = null;
}
return newArray;
}
/**
* Prints an error message.
* @param message Message to print.
*/
private void errorMessage( String message )
{
logger.errorMessage( "CodecWav", message, 0 );
}
/**
* Prints an exception's error message followed by the stack trace.
* @param e Exception containing the information to print.
*/
private void printStackTrace( Exception e )
{
logger.printStackTrace( e, 1 );
}
}
-162
View File
@@ -1,162 +0,0 @@
#Main Forge Access Transformer configuration file
# Tessellator
public-f bff.a #FD:Tessellator/field_78398_a #instance
public bff.u #FD:Tessellator/field_78409_u #drawMode
public bff.v #FD:Tessellator/field_78408_v #xOffset
public bff.w #FD:Tessellator/field_78407_w #yOffset
public bff.x #FD:Tessellator/field_78417_x #zOffset
public bff.z #FD:Tessellator/field_78415_z #isDrawing
# ItemPickaxe
public yi.<init>(ILxy;)V #MD:ItemPickaxe/<init>(ILnet/minecraft/src/EnumToolMaterial;) #constructor
public+f yi.c #FD:ItemPickaxe/field_77867_c #blocksEffectiveAgainst
# ItemAxe
public xv.<init>(ILxy;)V #MD:ItemAxe/<init>(ILnet/minecraft/src/EnumToolMaterial;) #constructor
public+f xv.c #FD:ItemAxe/field_77868_c #blocksEffectiveAgainst
# ItemSpade
public yt.<init>(ILxy;)V #MD:ItemSpade/<init>(ILnet/minecraft/src/EnumToolMaterial;) #constructor
public+f yt.c #FD:ItemSpade/field_77866_c #blocksEffectiveAgainst
# ItemTool
public xe.a #FD:ItemTool/field_77864_a #efficiencyOnProperMaterial
public xe.d #FD:ItemTool/field_77865_bY #damageVsEntity
# EntityEnderman
public td.br #FD:EntityEnderman/field_70827_d #carriableBlocks
# RenderEngine
# -- MISSING MAPPING public bge.f(Ljava/lang/String;)I #MD:RenderEngine/func_78341_b #getTexture
# -- MISSING MAPPING public bge.i #FD:RenderEngine/field_94154_l #terrainTextureMap
# -- MISSING MAPPING public bge.j #FD:RenderEngine/field_94155_m #itemTextureMap
# RenderGlobal
public bfa.k #FD:RenderGlobal/field_72769_h #theWorld
public bfa.l #FD:RenderGlobal/field_72770_i #renderEngine
public bfa.t #FD:RenderGlobal/field_72777_q #mc
public bfa.u #FD:RenderGlobal/field_72776_r #globalRenderBlocks
public bfa.H #FD:RenderGlobal/field_72738_E #damagedBlocks
# SoundManager
public blc.b #FD:SoundManager/field_77381_a #sndSystem
public blc.d #FD:SoundManager/field_77379_b #soundPoolSounds
public blc.e #FD:SoundManager/field_77380_c #soundPoolStreaming
public blc.f #FD:SoundManager/field_77377_d #soundPoolMusic
# EntityMinecart
protected sq.* #FD:EntityMinecart/* # All private -> protected
# -- MISSING MAPPING public py.h()Z #MD:EntityMinecart/func_70490_h #isMinecartPowered
# Block
public aqs.<init>(ILajv;)V #MD:Block/<init>(ILnet/minecraft/src/Material;) #Constructor
public aqs.<init>(IILajv;)V #MD:Block/<init>(IILnet/minecraft/src/Material;) #Constructor
public aqs.cH #FD:Block/field_72029_cc #blockResistance
public aqs.cG #FD:Block/field_71989_cb #blockHardness
# -- MISSING MAPPING public amq.r()Lamq; #MD:Block/func_71912_p #setRequiresSelfNotify
public aqs.a(Laqw;)Laqs; #MD:Block/func_71884_a #setStepSound
public aqs.b(F)Laqs; #MD:Block/func_71894_b #setResistance
public aqs.c(F)Laqs; #MD:Block/func_71848_c #setHardness
public aqs.k(I)Laqs; #MD:Block/func_71868_h #setLightOpacity
public aqs.a(F)Laqs; #MD:Block/func_71900_a #setLightValue
public aqs.r()Laqs; #MD:Block/func_71875_q #setBlockUnbreakable
public aqs.b(Z)Laqs; #MD:Block/func_71907_b #setTickRandomly
public aqs.a(FFFFFF)V #MD:Block/func_71905_a #setBlockBounds
# NetServerHandler
public jx.f #FD:NetServerHandler/field_72572_g #playerInAirTime
# TileEntity
public asi.k #FD:TileEntity/field_70331_k #worldObj
# BlockLeavesBase
public ara.d #FD:BlockLeavesBase/field_72131_c #graphicsLevel
# Item
public xx.<init>(I)V #MD:Item/<init>(I) #Constructor
public xx.e(I)Lxx; #MD:Item/func_77656_e #setMaxDamage
public-f xx.h(Lxz;)Lmp; #MD:Item/func_77650_f #getIconIndex
public xx.c(Ljava/lang/String;)Lxx; #MD:Item/func_77631_c #setPotionEffect
# RailLogic
public ams #CL:BlockBaseRailLogic
public ams.a()I #MD:BlockBaseRailLogic/func_94505_a #getNAdjacentTiles
# EntityPlayer
public ua.a(Lsp;)V #MD:EntityPlayer/func_71012_a #joinEntityItemWithWorld
public ua.i()V #MD:EntityPlayer/func_71053_j #closeScreen
public ua.b #FD:EntityPlayer/field_71076_b #sleepTimer
# EntityPlayerMP
public bcx.a(Lsp;)V #MD:EntityClientPlayerMP/func_71012_a #joinEntityItemWithWorld
# World Gen Chests Related
public mh.* #FD:WeightedRandomChestContent/* #all
public jp.T #FD:WorldServer/field_73069_S #bonusChestContent
public agc.a #FD:StructureMineshaftPieces/field_78818_a #mineshaftChestContents
public ahg.i #FD:ComponentScatteredFeatureDesertPyramid/field_74941_i #itemsToGenerateInTemple
public ahh.l #FD:ComponentScatteredFeatureJunglePyramid/field_74943_l #junglePyramidsChestContents
public ahh.m #FD:ComponentScatteredFeatureJunglePyramid/field_74944_m #junglePyramidsDispenserContents
public ahr.a #FD:ComponentStrongholdChestCorridor/field_75003_a #strongholdChestContents
public ahv.b #FD:ComponentStrongholdLibrary/field_75007_b #strongholdLibraryChestContents
public aia.c #FD:ComponentStrongholdRoomCrossing/field_75014_c #strongholdCorridorChestContents
public ajb.a #FD:ComponentVillageHouse2/field_74918_a #villageBlacksmithChestContents
# AnvilChunkLoader.chunkSaveLocation
public adz.d #FD:AnvilChunkLoader/field_75825_d
# ChunkProviderServer.currentChunkLoader
public jo.e #FD:ChunkProviderServer/field_73247_e
# PlayerManager
public jm.a(IIZ)Ljn; #MD:PlayerManager/func_72690_a #getOrCreateChunkWatcher
# PlayerInstance
public jn #CL:PlayerInstance
# World
public-f abr.A #FD:World/field_72982_D #villageCollectionObj
public abr.G #FD:World/field_72993_I #activeChunkSet
# EntityLiving
public od.b #FD:EntityLiving/field_70728_aV #experienceValue
# -- MISSING MAPPING public ng.bt #FD:EntityLiving/field_94063_bt #combatTracker
public od.d #FD:EntityLiving/field_70715_bh #targetTasks
# GuiFlatPresets
public avq.a(Ljava/lang/String;ILacl;Ljava/util/List;[Lafy;)V #MD:GuiFlatPresets/func_82294_a
public avq.a(Ljava/lang/String;ILacl;[Lafy;)V #MD:GuiFlatPresets/func_82297_a
# BiomeGenBase
public acl.*() #MD:BiomeGenBase/* #Everything protected->public
# MapGenVillage
public-f aip.e #FD:MapGenVillage/field_75055_e #villageSpawnBiomes
# ShapedRecipes
public+f aad.d #FD:ShapedRecipes/field_77574_d #recipeItems
public+f aad.b #FD:ShapedRecipes/field_77576_b #recipeWidth
public+f aad.c #FD:ShapedRecipes/field_77577_c #recipeHeight
# ShapelessRecipes
public aae.b #FD:ShapelessRecipes/field_77579_b #recipeItems
# GuiContainer
protected awp.a(Lvz;)V #MD:GuiContainer/func_74192_a #drawSlotInventory
# ContainerPlayer
protected vq.h #FD:ContainerPlayer/field_82862_h #player
# BlockButton
protected amy.n(Labr;III)V #MD:BlockButton/func_82535_o #checkActivation
protected-f amy.a #FD:BlockButton/field_82537_a #sensible
# BiomeDecorator
public acp.* #FD:BiomeDecorator/* # All private -> protected
# CreativeTabs
public-f wr.a #FD:CreativeTabs/field_78032_a # creativeTabArray non-final
# Packet
public ex.a(IZZLjava/lang/Class;)V #MD:Packet/func_73285_a #addIdClassMapping
# SaveHandler
public alj.b()Ljava/io/File; #MD:SaveHandler/func_75765_b
# World stuff
public abr.b(Lnk;)V #MD:World/func_72847_b #releaseEntitySkin
public abr.m #FD:World/field_73003_n #prevRainingStrength
public abr.n #FD:World/field_73004_o #rainingStrength
public abr.p #FD:World/field_73017_q #thunderingStrength
public abr.o #FD:World/field_73018_p #prevThunderingStrength
#WorldClient
public bcu.b(Lnk;)V #MD:WorldClient/func_72847_b #releaseEntitySkin
#WorldServer
public jp.b(Lnk;)V #MD:WorldServer/func_72847_b #releaseEntitySkin
public jp.N #FD:WorldServer/field_73068_P #allPlayersSleeping
#TextureMap
public bhz.g #FD:TextureMap/field_94255_a
# -- MISSING MAPPING public bir.b #FD:TextureMap/field_94253_b
public bhz.h #FD:TextureMap/field_94254_c
# -- MISSING MAPPING public bir.d #FD:TextureMap/field_94251_d
#Potion
public nf.b(II)Lnf; #MD:Potion/func_76399_b #setIconIndex
#PotionHelper
public zk.m #FD:PotionHelper/field_77927_l #potionRequirements
public zk.n #FD:PotionHelper/field_77928_m #potionAmplifiers
#PotionEffect
public ng.b #FD:PotionEffect/field_76460_b #duration
#BlockFluid
protected aov.a #FD:BlockFluid/field_94425_a #theIcon
#GuiIngame
protected ava.* #FD:GuiIngame/* # All private -> protected
protected ava.*() #MD:GuiIngame/* # All private -> protected
#ItemStack
default xz.f #FD:ItemStack/field_77991_e # make default access for itemDamage
#GuiSlot
protected avx.b(IIII)V #MD:GuiSlot/func_77206_b #overlayBackground
#EntityPlayer
public ua.bu #FD:EntityPlayer/field_71092_bJ #username
@@ -1,43 +0,0 @@
package net.minecraftforge.classloading;
import java.util.Map;
import cpw.mods.fml.relauncher.IFMLLoadingPlugin;
public class FMLForgePlugin implements IFMLLoadingPlugin
{
public static boolean RUNTIME_DEOBF = false;
@Override
public String[] getLibraryRequestClass()
{
return null;
}
@Override
public String[] getASMTransformerClass()
{
return new String[]{
"net.minecraftforge.transformers.ForgeAccessTransformer",
"net.minecraftforge.transformers.EventTransformer"
};
}
@Override
public String getModContainerClass()
{
return "net.minecraftforge.common.ForgeDummyContainer";
}
@Override
public String getSetupClass()
{
return null;
}
@Override
public void injectData(Map<String, Object> data)
{
RUNTIME_DEOBF = (Boolean)data.get("runtimeDeobfuscationEnabled");
}
}
@@ -1,108 +0,0 @@
/**
* This software is provided under the terms of the Minecraft Forge Public
* License v1.0.
*/
package net.minecraftforge.common;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import net.minecraft.stats.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;
}
private static LinkedList<AchievementPage> achievementPages = new LinkedList<AchievementPage>();
/**
* Registers an achievement page.
* @param page The page.
*/
public static void registerAchievementPage(AchievementPage page)
{
if (getAchievementPage(page.getName()) != null)
{
throw new RuntimeException("Duplicate achievement page name \"" + page.getName() + "\"!");
}
achievementPages.add(page);
}
/**
* Will return an achievement page by its index on the list.
* @param index The page's index.
* @return the achievement page corresponding to the index or null if invalid index
*/
public static AchievementPage getAchievementPage(int index)
{
return achievementPages.get(index);
}
/**
* Will return an achievement page by its name.
* @param name The page's name.
* @return the achievement page with the given name or null if no such page
*/
public static AchievementPage getAchievementPage(String name)
{
for (AchievementPage page : achievementPages)
{
if (page.getName().equals(name))
{
return page;
}
}
return null;
}
/**
* Will return the list of achievement pages.
* @return the list's size
*/
public static Set<AchievementPage> getAchievementPages()
{
return new HashSet<AchievementPage>(achievementPages);
}
/**
* Will return whether an achievement is in any page or not.
* @param achievement The achievement.
*/
public static boolean isAchievementInPages(Achievement achievement)
{
for (AchievementPage page : achievementPages)
{
if (page.getAchievements().contains(achievement))
{
return true;
}
}
return false;
}
public static String getTitle(int index)
{
return index == -1 ? "Minecraft" : getAchievementPage(index).getName();
}
}
@@ -1,301 +0,0 @@
package net.minecraftforge.common;
import java.util.*;
import net.minecraft.world.biome.*;
import static net.minecraft.world.biome.BiomeGenBase.*;
import static net.minecraftforge.common.BiomeDictionary.Type.*;
public class BiomeDictionary
{
public enum Type
{
FOREST,
PLAINS,
MOUNTAIN,
HILLS,
SWAMP,
WATER,
DESERT,
FROZEN,
JUNGLE,
WASTELAND,
BEACH,
NETHER,
END,
MUSHROOM,
MAGICAL;
}
private static final int BIOME_LIST_SIZE = 256;
private static BiomeInfo[] biomeList = new BiomeInfo[BIOME_LIST_SIZE];
private static ArrayList<BiomeGenBase>[] typeInfoList = new ArrayList[Type.values().length];
private static class BiomeInfo
{
public EnumSet<Type> typeList;
public BiomeInfo(Type[] types)
{
typeList = EnumSet.noneOf(Type.class);
for(Type t : types)
{
typeList.add(t);
}
}
}
static
{
registerVanillaBiomes();
}
/**
* Registers a biome with a specific biome type
*
* @param biome the biome to be registered
* @param type the type to register the biome as
* @return returns true if the biome was registered successfully
*/
public static boolean registerBiomeType(BiomeGenBase biome, Type ... types)
{
if(BiomeGenBase.biomeList[biome.biomeID] != null)
{
for(Type type : types)
{
if(typeInfoList[type.ordinal()] == null)
{
typeInfoList[type.ordinal()] = new ArrayList<BiomeGenBase>();
}
typeInfoList[type.ordinal()].add(biome);
}
if(biomeList[biome.biomeID] == null)
{
biomeList[biome.biomeID] = new BiomeInfo(types);
}
else
{
for(Type type : types)
{
biomeList[biome.biomeID].typeList.add(type);
}
}
return true;
}
return false;
}
/**
* Returns a list of biomes registered with a specific type
*
* @param type the Type to look for
* @return a list of biomes of the specified type, null if there are none
*/
public static BiomeGenBase[] getBiomesForType(Type type)
{
if(typeInfoList[type.ordinal()] != null)
{
return (BiomeGenBase[])typeInfoList[type.ordinal()].toArray(new BiomeGenBase[0]);
}
return new BiomeGenBase[0];
}
/**
* Gets a list of Types that a specific biome is registered with
*
* @param biome the biome to check
* @return the list of types, null if there are none
*/
public static Type[] getTypesForBiome(BiomeGenBase biome)
{
checkRegistration(biome);
if(biomeList[biome.biomeID] != null)
{
return (Type[])biomeList[biome.biomeID].typeList.toArray(new Type[0]);
}
return new Type[0];
}
/**
* Checks to see if two biomes are registered as having the same type
*
* @param biomeA
* @param biomeB
* @return returns true if a common type is found, false otherwise
*/
public static boolean areBiomesEquivalent(BiomeGenBase biomeA, BiomeGenBase biomeB)
{
int a = biomeA.biomeID;
int b = biomeB.biomeID;
checkRegistration(biomeA);
checkRegistration(biomeB);
if(biomeList[a] != null && biomeList[b] != null)
{
for(Type type : biomeList[a].typeList)
{
if(containsType(biomeList[b], type))
{
return true;
}
}
}
return false;
}
/**
* Checks to see if the given biome is registered as being a specific type
*
* @param biome the biome to be considered
* @param type the type to check for
* @return returns true if the biome is registered as being of type type, false otherwise
*/
public static boolean isBiomeOfType(BiomeGenBase biome, Type type)
{
checkRegistration(biome);
if(biomeList[biome.biomeID] != null)
{
return containsType(biomeList[biome.biomeID], type);
}
return false;
}
/**
* Checks to see if the given biome has been registered as being of any type
* @param biome the biome to consider
* @return returns true if the biome has been registered, false otherwise
*/
public static boolean isBiomeRegistered(BiomeGenBase biome)
{
return biomeList[biome.biomeID] != null;
}
public static boolean isBiomeRegistered(int biomeID)
{
return biomeList[biomeID] != null;
}
/**
* Loops through the biome list and automatically adds tags to any biome that does not have any
* This should be called in postInit to make sure all biomes have been registered
*
* DO NOT call this during world generation
*/
public static void registerAllBiomes()
{
for(int i = 0; i < BIOME_LIST_SIZE; i++)
{
if(BiomeGenBase.biomeList[i] != null)
{
checkRegistration(BiomeGenBase.biomeList[i]);
}
}
}
/**
* Automatically looks for and registers a given biome with appropriate tags
* This method is called automatically if a biome has not been registered with any tags,
* And another method requests information about it
*
* NOTE: You can opt out of having your biome registered by registering it as type NULL
*
* @param biome the biome to be considered
*/
public static void makeBestGuess(BiomeGenBase biome)
{
if(biome.theBiomeDecorator.treesPerChunk >= 3)
{
if(biome.isHighHumidity() && biome.temperature >= 1.0F)
{
BiomeDictionary.registerBiomeType(biome, JUNGLE);
}
else if(!biome.isHighHumidity())
{
BiomeDictionary.registerBiomeType(biome, FOREST);
}
}
else if(biome.maxHeight <= 0.3F && biome.maxHeight >= 0.0F)
{
if(!biome.isHighHumidity() || biome.minHeight >= 0.0F)
{
BiomeDictionary.registerBiomeType(biome, PLAINS);
}
}
if(biome.isHighHumidity() && biome.minHeight < 0.0F && (biome.maxHeight <= 0.3F && biome.maxHeight >= 0.0F))
{
BiomeDictionary.registerBiomeType(biome, SWAMP);
}
if(biome.minHeight <= -0.5F)
{
BiomeDictionary.registerBiomeType(biome, WATER);
}
if(biome.maxHeight >= 1.5F)
{
BiomeDictionary.registerBiomeType(biome, MOUNTAIN);
}
if(biome.getEnableSnow() || biome.temperature < 0.2F)
{
BiomeDictionary.registerBiomeType(biome, FROZEN);
}
if(!biome.isHighHumidity() && biome.temperature >= 1.0F)
{
BiomeDictionary.registerBiomeType(biome, DESERT);
}
}
//Internal implementation
private static void checkRegistration(BiomeGenBase biome)
{
if(!isBiomeRegistered(biome))
{
makeBestGuess(biome);
}
}
private static boolean containsType(BiomeInfo info, Type type)
{
return info.typeList.contains(type);
}
private static void registerVanillaBiomes()
{
registerBiomeType(ocean, WATER );
registerBiomeType(plains, PLAINS );
registerBiomeType(desert, DESERT );
registerBiomeType(extremeHills, MOUNTAIN );
registerBiomeType(forest, FOREST );
registerBiomeType(taiga, FOREST, FROZEN);
registerBiomeType(taigaHills, FOREST, FROZEN);
registerBiomeType(swampland, SWAMP );
registerBiomeType(river, WATER );
registerBiomeType(frozenOcean, WATER, FROZEN);
registerBiomeType(frozenRiver, WATER, FROZEN);
registerBiomeType(icePlains, FROZEN );
registerBiomeType(iceMountains, FROZEN );
registerBiomeType(beach, BEACH );
registerBiomeType(desertHills, DESERT );
registerBiomeType(jungle, JUNGLE );
registerBiomeType(jungleHills, JUNGLE );
registerBiomeType(forestHills, FOREST );
registerBiomeType(sky, END );
registerBiomeType(hell, NETHER );
registerBiomeType(mushroomIsland, MUSHROOM );
registerBiomeType(extremeHillsEdge, MOUNTAIN );
registerBiomeType(mushroomIslandShore, MUSHROOM, BEACH);
}
}
@@ -1,70 +0,0 @@
package net.minecraftforge.common;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import net.minecraft.world.biome.BiomeGenBase;
import net.minecraft.world.gen.ChunkProviderGenerate;
import net.minecraft.world.chunk.IChunkProvider;
import net.minecraft.world.gen.structure.MapGenStronghold;
import net.minecraft.world.gen.structure.MapGenVillage;
import net.minecraft.world.biome.WorldChunkManager;
import com.google.common.collect.Lists;
public class BiomeManager
{
public static void addVillageBiome(BiomeGenBase biome, boolean canSpawn)
{
if (!MapGenVillage.villageSpawnBiomes.contains(biome))
{
ArrayList<BiomeGenBase> biomes = new ArrayList<BiomeGenBase>(MapGenVillage.villageSpawnBiomes);
biomes.add(biome);
MapGenVillage.villageSpawnBiomes = biomes;
}
}
public static void removeVillageBiome(BiomeGenBase biome)
{
if (MapGenVillage.villageSpawnBiomes.contains(biome))
{
ArrayList<BiomeGenBase> biomes = new ArrayList<BiomeGenBase>(MapGenVillage.villageSpawnBiomes);
biomes.remove(biome);
MapGenVillage.villageSpawnBiomes = biomes;
}
}
public static void addStrongholdBiome(BiomeGenBase biome)
{
if (!MapGenStronghold.allowedBiomes.contains(biome))
{
MapGenStronghold.allowedBiomes.add(biome);
}
}
public static void removeStrongholdBiome(BiomeGenBase biome)
{
if (MapGenStronghold.allowedBiomes.contains(biome))
{
MapGenStronghold.allowedBiomes.remove(biome);
}
}
public static void addSpawnBiome(BiomeGenBase biome)
{
if (!WorldChunkManager.allowedBiomes.contains(biome))
{
WorldChunkManager.allowedBiomes.add(biome);
}
}
public static void removeSpawnBiome(BiomeGenBase biome)
{
if (WorldChunkManager.allowedBiomes.contains(biome))
{
WorldChunkManager.allowedBiomes.remove(biome);
}
}
}
@@ -1,260 +0,0 @@
package net.minecraftforge.common;
import java.util.*;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.WeightedRandom;
import net.minecraft.util.WeightedRandomChestContent;
import net.minecraft.world.WorldServer;
import net.minecraft.world.gen.structure.*;
import net.minecraftforge.oredict.OreDictionary;
public class ChestGenHooks
{
//Currently implemented categories for chests/dispensers, Dungeon loot is still in DungeonHooks
public static final String MINESHAFT_CORRIDOR = "mineshaftCorridor";
public static final String PYRAMID_DESERT_CHEST = "pyramidDesertyChest";
public static final String PYRAMID_JUNGLE_CHEST = "pyramidJungleChest";
public static final String PYRAMID_JUNGLE_DISPENSER = "pyramidJungleDispenser";
public static final String STRONGHOLD_CORRIDOR = "strongholdCorridor";
public static final String STRONGHOLD_LIBRARY = "strongholdLibrary";
public static final String STRONGHOLD_CROSSING = "strongholdCrossing";
public static final String VILLAGE_BLACKSMITH = "villageBlacksmith";
public static final String BONUS_CHEST = "bonusChest";
public static final String DUNGEON_CHEST = "dungeonChest";
private static final HashMap<String, ChestGenHooks> chestInfo = new HashMap<String, ChestGenHooks>();
private static boolean hasInit = false;
static
{
init();
}
private static void init()
{
if (hasInit)
{
return;
}
hasInit = true;
addInfo(MINESHAFT_CORRIDOR, StructureMineshaftPieces.mineshaftChestContents, 3, 7);
addInfo(PYRAMID_DESERT_CHEST, ComponentScatteredFeatureDesertPyramid.itemsToGenerateInTemple, 2, 7);
addInfo(PYRAMID_JUNGLE_CHEST, ComponentScatteredFeatureJunglePyramid.junglePyramidsChestContents, 2, 7);
addInfo(PYRAMID_JUNGLE_DISPENSER, ComponentScatteredFeatureJunglePyramid.junglePyramidsDispenserContents, 2, 2);
addInfo(STRONGHOLD_CORRIDOR, ComponentStrongholdChestCorridor.strongholdChestContents, 2, 4);
addInfo(STRONGHOLD_LIBRARY, ComponentStrongholdLibrary.strongholdLibraryChestContents, 1, 5);
addInfo(STRONGHOLD_CROSSING, ComponentStrongholdRoomCrossing.strongholdRoomCrossingChestContents, 1, 5);
addInfo(VILLAGE_BLACKSMITH, ComponentVillageHouse2.villageBlacksmithChestContents, 3, 9);
addInfo(BONUS_CHEST, WorldServer.bonusChestContent, 10, 10);
ItemStack book = new ItemStack(Item.enchantedBook, 1, 0);
WeightedRandomChestContent tmp = new WeightedRandomChestContent(book, 1, 1, 1);
getInfo(MINESHAFT_CORRIDOR ).addItem(tmp);
getInfo(PYRAMID_DESERT_CHEST).addItem(tmp);
getInfo(PYRAMID_JUNGLE_CHEST).addItem(tmp);
getInfo(STRONGHOLD_CORRIDOR ).addItem(tmp);
getInfo(STRONGHOLD_LIBRARY ).addItem(new WeightedRandomChestContent(book, 1, 5, 2));
getInfo(STRONGHOLD_CROSSING ).addItem(tmp);
//Wish Dungeons would get on the same wave length as other world gen...
ChestGenHooks d = new ChestGenHooks(DUNGEON_CHEST);
d.countMin = 8;
d.countMax = 8;
chestInfo.put(DUNGEON_CHEST, d);
addDungeonLoot(d, new ItemStack(Item.saddle), 100, 1, 1);
addDungeonLoot(d, new ItemStack(Item.ingotIron), 100, 1, 4);
addDungeonLoot(d, new ItemStack(Item.bread), 100, 1, 1);
addDungeonLoot(d, new ItemStack(Item.wheat), 100, 1, 4);
addDungeonLoot(d, new ItemStack(Item.gunpowder), 100, 1, 4);
addDungeonLoot(d, new ItemStack(Item.silk), 100, 1, 4);
addDungeonLoot(d, new ItemStack(Item.bucketEmpty), 100, 1, 1);
addDungeonLoot(d, new ItemStack(Item.appleGold), 1, 1, 1);
addDungeonLoot(d, new ItemStack(Item.redstone), 50, 1, 4);
addDungeonLoot(d, new ItemStack(Item.record13), 5, 1, 1);
addDungeonLoot(d, new ItemStack(Item.recordCat), 5, 1, 1);
addDungeonLoot(d, new ItemStack(Item.dyePowder, 1, 3), 100, 1, 1);
addDungeonLoot(d, book, 100, 1, 1);
}
static void addDungeonLoot(ChestGenHooks dungeon, ItemStack item, int weight, int min, int max)
{
dungeon.addItem(new WeightedRandomChestContent(item, min, max, weight));
}
private static void addInfo(String category, WeightedRandomChestContent[] items, int min, int max)
{
chestInfo.put(category, new ChestGenHooks(category, items, min, max));
}
/**
* Retrieves, or creates the info class for the specified category.
*
* @param category The category name
* @return A instance of ChestGenHooks for the specified category.
*/
public static ChestGenHooks getInfo(String category)
{
if (!chestInfo.containsKey(category))
{
chestInfo.put(category, new ChestGenHooks(category));
}
return chestInfo.get(category);
}
/**
* Generates an array of items based on the input min/max count.
* If the stack can not hold the total amount, it will be split into
* stacks of size 1.
*
* @param rand A random number generator
* @param source Source item stack
* @param min Minimum number of items
* @param max Maximum number of items
* @return An array containing the generated item stacks
*/
public static ItemStack[] generateStacks(Random rand, ItemStack source, int min, int max)
{
int count = min + (rand.nextInt(max - min + 1));
ItemStack[] ret;
if (source.getItem() == null)
{
ret = new ItemStack[0];
}
else if (count > source.getItem().getItemStackLimit())
{
ret = new ItemStack[count];
for (int x = 0; x < count; x++)
{
ret[x] = source.copy();
ret[x].stackSize = 1;
}
}
else
{
ret = new ItemStack[1];
ret[0] = source.copy();
ret[0].stackSize = count;
}
return ret;
}
//shortcut functions, See the non-static versions below
public static WeightedRandomChestContent[] getItems(String category, Random rnd){ return getInfo(category).getItems(rnd); }
public static int getCount(String category, Random rand){ return getInfo(category).getCount(rand); }
public static void addItem(String category, WeightedRandomChestContent item){ getInfo(category).addItem(item); }
public static void removeItem(String category, ItemStack item){ getInfo(category).removeItem(item); }
public static ItemStack getOneItem(String category, Random rand){ return getInfo(category).getOneItem(rand); }
private String category;
private int countMin = 0;
private int countMax = 0;
//TO-DO: Privatize this once again when we remove the Deprecated stuff in DungeonHooks
ArrayList<WeightedRandomChestContent> contents = new ArrayList<WeightedRandomChestContent>();
public ChestGenHooks(String category)
{
this.category = category;
}
public ChestGenHooks(String category, WeightedRandomChestContent[] items, int min, int max)
{
this(category);
for (WeightedRandomChestContent item : items)
{
contents.add(item);
}
countMin = min;
countMax = max;
}
/**
* Adds a new entry into the possible items to generate.
*
* @param item The item to add.
*/
public void addItem(WeightedRandomChestContent item)
{
contents.add(item);
}
/**
* Removes all items that match the input item stack, Only metadata and item ID are checked.
* If the input item has a metadata of -1, all metadatas will match.
*
* @param item The item to check
*/
public void removeItem(ItemStack item)
{
Iterator<WeightedRandomChestContent> itr = contents.iterator();
while(itr.hasNext())
{
WeightedRandomChestContent cont = itr.next();
if (item.isItemEqual(cont.theItemId) || (item.getItemDamage() == OreDictionary.WILDCARD_VALUE && item.itemID == cont.theItemId.itemID))
{
itr.remove();
}
}
}
/**
* Gets an array of all random objects that are associated with this category.
*
* @return The random objects
*/
public WeightedRandomChestContent[] getItems(Random rnd)
{
ArrayList<WeightedRandomChestContent> ret = new ArrayList<WeightedRandomChestContent>();
for (WeightedRandomChestContent orig : contents)
{
Item item = orig.theItemId.getItem();
if (item != null)
{
WeightedRandomChestContent n = item.getChestGenBase(this, rnd, orig);
if (n != null)
{
ret.add(n);
}
}
}
return ret.toArray(new WeightedRandomChestContent[ret.size()]);
}
/**
* Gets a random number between countMin and countMax.
*
* @param rand A RNG
* @return A random number where countMin <= num <= countMax
*/
public int getCount(Random rand)
{
return countMin < countMax ? countMin + rand.nextInt(countMax - countMin) : countMin;
}
/**
* Returns a single ItemStack from the possible items in this registry,
* Useful if you just want a quick and dirty random Item.
*
* @param rand A Random Number gen
* @return A single ItemStack, or null if it could not get one.
*/
public ItemStack getOneItem(Random rand)
{
WeightedRandomChestContent[] items = getItems(rand);
WeightedRandomChestContent item = (WeightedRandomChestContent)WeightedRandom.getRandomItem(rand, items);
ItemStack[] stacks = ChestGenHooks.generateStacks(rand, item.theItemId, item.theMinimumChanceToGenerateItem, item.theMaximumChanceToGenerateItem);
return (stacks.length > 0 ? stacks[0] : null);
}
//Accessors
public int getMin(){ return countMin; }
public int getMax(){ return countMax; }
public void setMin(int value){ countMin = value; }
public void setMax(int value){ countMax = value; }
}
@@ -1,269 +0,0 @@
package net.minecraftforge.common;
import static net.minecraftforge.common.Configuration.NEW_LINE;
import static net.minecraftforge.common.Configuration.allowedProperties;
import java.io.BufferedWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.base.Splitter;
public class ConfigCategory implements Map<String, Property>
{
private String name;
private String comment;
private ArrayList<ConfigCategory> children = new ArrayList<ConfigCategory>();
private Map<String, Property> properties = new TreeMap<String, Property>();
public final ConfigCategory parent;
private boolean changed = false;
public ConfigCategory(String name)
{
this(name, null);
}
public ConfigCategory(String name, ConfigCategory parent)
{
this.name = name;
this.parent = parent;
if (parent != null)
{
parent.children.add(this);
}
}
public boolean equals(Object obj)
{
if (obj instanceof ConfigCategory)
{
ConfigCategory cat = (ConfigCategory)obj;
return name.equals(cat.name) && children.equals(cat.children);
}
return false;
}
public String getQualifiedName()
{
return getQualifiedName(name, parent);
}
public static String getQualifiedName(String name, ConfigCategory parent)
{
return (parent == null ? name : parent.getQualifiedName() + Configuration.CATEGORY_SPLITTER + name);
}
public ConfigCategory getFirstParent()
{
return (parent == null ? this : parent.getFirstParent());
}
public boolean isChild()
{
return parent != null;
}
public Map<String, Property> getValues()
{
return ImmutableMap.copyOf(properties);
}
public void setComment(String comment)
{
this.comment = comment;
}
public boolean containsKey(String key)
{
return properties.containsKey(key);
}
public Property get(String key)
{
return properties.get(key);
}
private void write(BufferedWriter out, String... data) throws IOException
{
write(out, true, data);
}
private void write(BufferedWriter out, boolean new_line, String... data) throws IOException
{
for (int x = 0; x < data.length; x++)
{
out.write(data[x]);
}
if (new_line) out.write(NEW_LINE);
}
public void write(BufferedWriter out, int indent) throws IOException
{
String pad0 = getIndent(indent);
String pad1 = getIndent(indent + 1);
String pad2 = getIndent(indent + 2);
write(out, pad0, "####################");
write(out, pad0, "# ", name);
if (comment != null)
{
write(out, pad0, "#===================");
Splitter splitter = Splitter.onPattern("\r?\n");
for (String line : splitter.split(comment))
{
write(out, pad0, "# ", line);
}
}
write(out, pad0, "####################", NEW_LINE);
if (!allowedProperties.matchesAllOf(name))
{
name = '"' + name + '"';
}
write(out, pad0, name, " {");
Property[] props = properties.values().toArray(new Property[properties.size()]);
for (int x = 0; x < props.length; x++)
{
Property prop = props[x];
if (prop.comment != null)
{
if (x != 0)
{
out.newLine();
}
Splitter splitter = Splitter.onPattern("\r?\n");
for (String commentLine : splitter.split(prop.comment))
{
write(out, pad1, "# ", commentLine);
}
}
String propName = prop.getName();
if (!allowedProperties.matchesAllOf(propName))
{
propName = '"' + propName + '"';
}
if (prop.isList())
{
char type = prop.getType().getID();
write(out, pad1, String.valueOf(type), ":", propName, " <");
for (String line : prop.getStringList())
{
write(out, pad2, line);
}
write(out, pad1, " >");
}
else if (prop.getType() == null)
{
write(out, pad1, propName, "=", prop.getString());
}
else
{
char type = prop.getType().getID();
write(out, pad1, String.valueOf(type), ":", propName, "=", prop.getString());
}
}
for (ConfigCategory child : children)
{
child.write(out, indent + 1);
}
write(out, pad0, "}", NEW_LINE);
}
private String getIndent(int indent)
{
StringBuilder buf = new StringBuilder("");
for (int x = 0; x < indent; x++)
{
buf.append(" ");
}
return buf.toString();
}
public boolean hasChanged()
{
if (changed) return true;
for (Property prop : properties.values())
{
if (prop.hasChanged()) return true;
}
return false;
}
void resetChangedState()
{
changed = false;
for (Property prop : properties.values())
{
prop.resetChangedState();
}
}
//Map bouncer functions for compatibility with older mods, to be removed once all mods stop using it.
@Override public int size(){ return properties.size(); }
@Override public boolean isEmpty() { return properties.isEmpty(); }
@Override public boolean containsKey(Object key) { return properties.containsKey(key); }
@Override public boolean containsValue(Object value){ return properties.containsValue(value); }
@Override public Property get(Object key) { return properties.get(key); }
@Override public Property put(String key, Property value)
{
changed = true;
return properties.put(key, value);
}
@Override public Property remove(Object key)
{
changed = true;
return properties.remove(key);
}
@Override public void putAll(Map<? extends String, ? extends Property> m)
{
changed = true;
properties.putAll(m);
}
@Override public void clear()
{
changed = true;
properties.clear();
}
@Override public Set<String> keySet() { return properties.keySet(); }
@Override public Collection<Property> values() { return properties.values(); }
@Override //Immutable copy, changes will NOT be reflected in this category
public Set<java.util.Map.Entry<String, Property>> entrySet()
{
return ImmutableSet.copyOf(properties.entrySet());
}
public Set<ConfigCategory> getChildren(){ return ImmutableSet.copyOf(children); }
public void removeChild(ConfigCategory child)
{
if (children.contains(child))
{
children.remove(child);
changed = true;
}
}
}
@@ -1,927 +0,0 @@
/**
* This software is provided under the terms of the Minecraft Forge Public
* License v1.0.
*/
package net.minecraftforge.common;
import static net.minecraftforge.common.Property.Type.BOOLEAN;
import static net.minecraftforge.common.Property.Type.DOUBLE;
import static net.minecraftforge.common.Property.Type.INTEGER;
import static net.minecraftforge.common.Property.Type.STRING;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PushbackInputStream;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import com.google.common.base.CharMatcher;
import com.google.common.collect.ImmutableSet;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.relauncher.FMLInjectionData;
/**
* This class offers advanced configurations capabilities, allowing to provide
* various categories for configuration variables.
*/
public class Configuration
{
private static boolean[] configMarkers = new boolean[Item.itemsList.length];
private static final int ITEM_SHIFT = 256;
private static final int MAX_BLOCKS = 4096;
public static final String CATEGORY_GENERAL = "general";
public static final String CATEGORY_BLOCK = "block";
public static final String CATEGORY_ITEM = "item";
public static final String ALLOWED_CHARS = "._-";
public static final String DEFAULT_ENCODING = "UTF-8";
public static final String CATEGORY_SPLITTER = ".";
public static final String NEW_LINE;
private static final Pattern CONFIG_START = Pattern.compile("START: \"([^\\\"]+)\"");
private static final Pattern CONFIG_END = Pattern.compile("END: \"([^\\\"]+)\"");
public static final CharMatcher allowedProperties = CharMatcher.JAVA_LETTER_OR_DIGIT.or(CharMatcher.anyOf(ALLOWED_CHARS));
private static Configuration PARENT = null;
File file;
private Map<String, ConfigCategory> categories = new TreeMap<String, ConfigCategory>();
private Map<String, Configuration> children = new TreeMap<String, Configuration>();
private boolean caseSensitiveCustomCategories;
public String defaultEncoding = DEFAULT_ENCODING;
private String fileName = null;
public boolean isChild = false;
private boolean changed = false;
static
{
Arrays.fill(configMarkers, false);
NEW_LINE = System.getProperty("line.separator");
}
public Configuration(){}
/**
* Create a configuration file for the file given in parameter.
*/
public Configuration(File file)
{
this.file = file;
String basePath = ((File)(FMLInjectionData.data()[6])).getAbsolutePath().replace(File.separatorChar, '/').replace("/.", "");
String path = file.getAbsolutePath().replace(File.separatorChar, '/').replace("/./", "/").replace(basePath, "");
if (PARENT != null)
{
PARENT.setChild(path, this);
isChild = true;
}
else
{
fileName = path;
load();
}
}
public Configuration(File file, boolean caseSensitiveCustomCategories)
{
this(file);
this.caseSensitiveCustomCategories = caseSensitiveCustomCategories;
}
/**
* Gets or create a block id property. If the block id property key is
* already in the configuration, then it will be used. Otherwise,
* defaultId will be used, except if already taken, in which case this
* will try to determine a free default id.
*/
public Property getBlock(String key, int defaultID) { return getBlock(CATEGORY_BLOCK, key, defaultID, null); }
public Property getBlock(String key, int defaultID, String comment) { return getBlock(CATEGORY_BLOCK, key, defaultID, comment); }
public Property getBlock(String category, String key, int defaultID) { return getBlockInternal(category, key, defaultID, null, 256, Block.blocksList.length); }
public Property getBlock(String category, String key, int defaultID, String comment) { return getBlockInternal(category, key, defaultID, comment, 256, Block.blocksList.length); }
/**
* Special version of getBlock to be used when you want to garentee the ID you get is below 256
* This should ONLY be used by mods who do low level terrain generation, or ones that add new
* biomes.
* EXA: ExtraBiomesXL
*
* Specifically, if your block is used BEFORE the Chunk is created, and placed in the terrain byte array directly.
* If you add a new biome and you set the top/filler block, they need to be <256, nothing else.
*
* If you're adding a new ore, DON'T call this function.
*
* Normal mods such as '50 new ores' do not need to be below 256 so should use the normal getBlock
*/
public Property getTerrainBlock(String category, String key, int defaultID, String comment)
{
return getBlockInternal(category, key, defaultID, comment, 0, 256);
}
private Property getBlockInternal(String category, String key, int defaultID, String comment, int lower, int upper)
{
Property prop = get(category, key, -1, comment);
if (prop.getInt() != -1)
{
configMarkers[prop.getInt()] = true;
return prop;
}
else
{
if (defaultID < lower)
{
FMLLog.warning(
"Mod attempted to get a block ID with a default in the Terrain Generation section, " +
"mod authors should make sure there defaults are above 256 unless explicitly needed " +
"for terrain generation. Most ores do not need to be below 256.");
FMLLog.warning("Config \"%s\" Category: \"%s\" Key: \"%s\" Default: %d", fileName, category, key, defaultID);
defaultID = upper - 1;
}
if (Block.blocksList[defaultID] == null && !configMarkers[defaultID])
{
prop.set(defaultID);
configMarkers[defaultID] = true;
return prop;
}
else
{
for (int j = upper - 1; j > 0; j--)
{
if (Block.blocksList[j] == null && !configMarkers[j])
{
prop.set(j);
configMarkers[j] = true;
return prop;
}
}
throw new RuntimeException("No more block ids available for " + key);
}
}
}
public Property getItem(String key, int defaultID) { return getItem(CATEGORY_ITEM, key, defaultID, null); }
public Property getItem(String key, int defaultID, String comment) { return getItem(CATEGORY_ITEM, key, defaultID, comment); }
public Property getItem(String category, String key, int defaultID) { return getItem(category, key, defaultID, null); }
public Property getItem(String category, String key, int defaultID, String comment)
{
Property prop = get(category, key, -1, comment);
int defaultShift = defaultID + ITEM_SHIFT;
if (prop.getInt() != -1)
{
configMarkers[prop.getInt() + ITEM_SHIFT] = true;
return prop;
}
else
{
if (defaultID < MAX_BLOCKS - ITEM_SHIFT)
{
FMLLog.warning(
"Mod attempted to get a item ID with a default value in the block ID section, " +
"mod authors should make sure there defaults are above %d unless explicitly needed " +
"so that all block ids are free to store blocks.", MAX_BLOCKS - ITEM_SHIFT);
FMLLog.warning("Config \"%s\" Category: \"%s\" Key: \"%s\" Default: %d", fileName, category, key, defaultID);
}
if (Item.itemsList[defaultShift] == null && !configMarkers[defaultShift] && defaultShift >= Block.blocksList.length)
{
prop.set(defaultID);
configMarkers[defaultShift] = true;
return prop;
}
else
{
for (int x = Item.itemsList.length - 1; x >= ITEM_SHIFT; x--)
{
if (Item.itemsList[x] == null && !configMarkers[x])
{
prop.set(x - ITEM_SHIFT);
configMarkers[x] = true;
return prop;
}
}
throw new RuntimeException("No more item ids available for " + key);
}
}
}
public Property get(String category, String key, int defaultValue)
{
return get(category, key, defaultValue, null);
}
public Property get(String category, String key, int defaultValue, String comment)
{
Property prop = get(category, key, Integer.toString(defaultValue), comment, INTEGER);
if (!prop.isIntValue())
{
prop.set(defaultValue);
}
return prop;
}
public Property get(String category, String key, boolean defaultValue)
{
return get(category, key, defaultValue, null);
}
public Property get(String category, String key, boolean defaultValue, String comment)
{
Property prop = get(category, key, Boolean.toString(defaultValue), comment, BOOLEAN);
if (!prop.isBooleanValue())
{
prop.set(defaultValue);
}
return prop;
}
public Property get(String category, String key, double defaultValue)
{
return get(category, key, defaultValue, null);
}
public Property get(String category, String key, double defaultValue, String comment)
{
Property prop = get(category, key, Double.toString(defaultValue), comment, DOUBLE);
if (!prop.isDoubleValue())
{
prop.set(defaultValue);
}
return prop;
}
public Property get(String category, String key, String defaultValue)
{
return get(category, key, defaultValue, null);
}
public Property get(String category, String key, String defaultValue, String comment)
{
return get(category, key, defaultValue, comment, STRING);
}
public Property get(String category, String key, String[] defaultValue)
{
return get(category, key, defaultValue, null);
}
public Property get(String category, String key, String[] defaultValue, String comment)
{
return get(category, key, defaultValue, comment, STRING);
}
public Property get(String category, String key, int[] defaultValue)
{
return get(category, key, defaultValue, null);
}
public Property get(String category, String key, int[] defaultValue, String comment)
{
String[] values = new String[defaultValue.length];
for (int i = 0; i < defaultValue.length; i++)
{
values[i] = Integer.toString(defaultValue[i]);
}
Property prop = get(category, key, values, comment, INTEGER);
if (!prop.isIntList())
{
prop.set(values);
}
return prop;
}
public Property get(String category, String key, double[] defaultValue)
{
return get(category, key, defaultValue, null);
}
public Property get(String category, String key, double[] defaultValue, String comment)
{
String[] values = new String[defaultValue.length];
for (int i = 0; i < defaultValue.length; i++)
{
values[i] = Double.toString(defaultValue[i]);
}
Property prop = get(category, key, values, comment, DOUBLE);
if (!prop.isDoubleList())
{
prop.set(values);
}
return prop;
}
public Property get(String category, String key, boolean[] defaultValue)
{
return get(category, key, defaultValue, null);
}
public Property get(String category, String key, boolean[] defaultValue, String comment)
{
String[] values = new String[defaultValue.length];
for (int i = 0; i < defaultValue.length; i++)
{
values[i] = Boolean.toString(defaultValue[i]);
}
Property prop = get(category, key, values, comment, BOOLEAN);
if (!prop.isBooleanList())
{
prop.set(values);
}
return prop;
}
public Property get(String category, String key, String defaultValue, String comment, Property.Type type)
{
if (!caseSensitiveCustomCategories)
{
category = category.toLowerCase(Locale.ENGLISH);
}
ConfigCategory cat = getCategory(category);
if (cat.containsKey(key))
{
Property prop = cat.get(key);
if (prop.getType() == null)
{
prop = new Property(prop.getName(), prop.getString(), type);
cat.put(key, prop);
}
prop.comment = comment;
return prop;
}
else if (defaultValue != null)
{
Property prop = new Property(key, defaultValue, type);
prop.set(defaultValue); //Set and mark as dirty to signify it should save
cat.put(key, prop);
prop.comment = comment;
return prop;
}
else
{
return null;
}
}
public Property get(String category, String key, String[] defaultValue, String comment, Property.Type type)
{
if (!caseSensitiveCustomCategories)
{
category = category.toLowerCase(Locale.ENGLISH);
}
ConfigCategory cat = getCategory(category);
if (cat.containsKey(key))
{
Property prop = cat.get(key);
if (prop.getType() == null)
{
prop = new Property(prop.getName(), prop.getString(), type);
cat.put(key, prop);
}
prop.comment = comment;
return prop;
}
else if (defaultValue != null)
{
Property prop = new Property(key, defaultValue, type);
prop.comment = comment;
cat.put(key, prop);
return prop;
}
else
{
return null;
}
}
public boolean hasCategory(String category)
{
return categories.get(category) != null;
}
public boolean hasKey(String category, String key)
{
ConfigCategory cat = categories.get(category);
return cat != null && cat.containsKey(key);
}
public void load()
{
if (PARENT != null && PARENT != this)
{
return;
}
BufferedReader buffer = null;
UnicodeInputStreamReader input = null;
try
{
if (file.getParentFile() != null)
{
file.getParentFile().mkdirs();
}
if (!file.exists() && !file.createNewFile())
{
return;
}
if (file.canRead())
{
input = new UnicodeInputStreamReader(new FileInputStream(file), defaultEncoding);
defaultEncoding = input.getEncoding();
buffer = new BufferedReader(input);
String line;
ConfigCategory currentCat = null;
Property.Type type = null;
ArrayList<String> tmpList = null;
int lineNum = 0;
String name = null;
while (true)
{
lineNum++;
line = buffer.readLine();
if (line == null)
{
break;
}
Matcher start = CONFIG_START.matcher(line);
Matcher end = CONFIG_END.matcher(line);
if (start.matches())
{
fileName = start.group(1);
categories = new TreeMap<String, ConfigCategory>();
continue;
}
else if (end.matches())
{
fileName = end.group(1);
Configuration child = new Configuration();
child.categories = categories;
this.children.put(fileName, child);
continue;
}
int nameStart = -1, nameEnd = -1;
boolean skip = false;
boolean quoted = false;
for (int i = 0; i < line.length() && !skip; ++i)
{
if (Character.isLetterOrDigit(line.charAt(i)) || ALLOWED_CHARS.indexOf(line.charAt(i)) != -1 || (quoted && line.charAt(i) != '"'))
{
if (nameStart == -1)
{
nameStart = i;
}
nameEnd = i;
}
else if (Character.isWhitespace(line.charAt(i)))
{
// ignore space charaters
}
else
{
switch (line.charAt(i))
{
case '#':
skip = true;
continue;
case '"':
if (quoted)
{
quoted = false;
}
if (!quoted && nameStart == -1)
{
quoted = true;
}
break;
case '{':
name = line.substring(nameStart, nameEnd + 1);
String qualifiedName = ConfigCategory.getQualifiedName(name, currentCat);
ConfigCategory cat = categories.get(qualifiedName);
if (cat == null)
{
currentCat = new ConfigCategory(name, currentCat);
categories.put(qualifiedName, currentCat);
}
else
{
currentCat = cat;
}
name = null;
break;
case '}':
if (currentCat == null)
{
throw new RuntimeException(String.format("Config file corrupt, attepted to close to many categories '%s:%d'", fileName, lineNum));
}
currentCat = currentCat.parent;
break;
case '=':
name = line.substring(nameStart, nameEnd + 1);
if (currentCat == null)
{
throw new RuntimeException(String.format("'%s' has no scope in '%s:%d'", name, fileName, lineNum));
}
Property prop = new Property(name, line.substring(i + 1), type, true);
i = line.length();
currentCat.put(name, prop);
break;
case ':':
type = Property.Type.tryParse(line.substring(nameStart, nameEnd + 1).charAt(0));
nameStart = nameEnd = -1;
break;
case '<':
if (tmpList != null)
{
throw new RuntimeException(String.format("Malformed list property \"%s:%d\"", fileName, lineNum));
}
name = line.substring(nameStart, nameEnd + 1);
if (currentCat == null)
{
throw new RuntimeException(String.format("'%s' has no scope in '%s:%d'", name, fileName, lineNum));
}
tmpList = new ArrayList<String>();
skip = true;
break;
case '>':
if (tmpList == null)
{
throw new RuntimeException(String.format("Malformed list property \"%s:%d\"", fileName, lineNum));
}
currentCat.put(name, new Property(name, tmpList.toArray(new String[tmpList.size()]), type));
name = null;
tmpList = null;
type = null;
break;
default:
throw new RuntimeException(String.format("Unknown character '%s' in '%s:%d'", line.charAt(i), fileName, lineNum));
}
}
}
if (quoted)
{
throw new RuntimeException(String.format("Unmatched quote in '%s:%d'", fileName, lineNum));
}
else if (tmpList != null && !skip)
{
tmpList.add(line.trim());
}
}
}
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
if (buffer != null)
{
try
{
buffer.close();
} catch (IOException e){}
}
if (input != null)
{
try
{
input.close();
} catch (IOException e){}
}
}
resetChangedState();
}
public void save()
{
if (PARENT != null && PARENT != this)
{
PARENT.save();
return;
}
try
{
if (file.getParentFile() != null)
{
file.getParentFile().mkdirs();
}
if (!file.exists() && !file.createNewFile())
{
return;
}
if (file.canWrite())
{
FileOutputStream fos = new FileOutputStream(file);
BufferedWriter buffer = new BufferedWriter(new OutputStreamWriter(fos, defaultEncoding));
buffer.write("# Configuration file" + NEW_LINE + NEW_LINE);
if (children.isEmpty())
{
save(buffer);
}
else
{
for (Map.Entry<String, Configuration> entry : children.entrySet())
{
buffer.write("START: \"" + entry.getKey() + "\"" + NEW_LINE);
entry.getValue().save(buffer);
buffer.write("END: \"" + entry.getKey() + "\"" + NEW_LINE + NEW_LINE);
}
}
buffer.close();
fos.close();
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
private void save(BufferedWriter out) throws IOException
{
for (ConfigCategory cat : categories.values())
{
if (!cat.isChild())
{
cat.write(out, 0);
out.newLine();
}
}
}
public ConfigCategory getCategory(String category)
{
ConfigCategory ret = categories.get(category);
if (ret == null)
{
if (category.contains(CATEGORY_SPLITTER))
{
String[] hierarchy = category.split("\\"+CATEGORY_SPLITTER);
ConfigCategory parent = categories.get(hierarchy[0]);
if (parent == null)
{
parent = new ConfigCategory(hierarchy[0]);
categories.put(parent.getQualifiedName(), parent);
changed = true;
}
for (int i = 1; i < hierarchy.length; i++)
{
String name = ConfigCategory.getQualifiedName(hierarchy[i], parent);
ConfigCategory child = categories.get(name);
if (child == null)
{
child = new ConfigCategory(hierarchy[i], parent);
categories.put(name, child);
changed = true;
}
ret = child;
parent = child;
}
}
else
{
ret = new ConfigCategory(category);
categories.put(category, ret);
changed = true;
}
}
return ret;
}
public void removeCategory(ConfigCategory category)
{
for (ConfigCategory child : category.getChildren())
{
removeCategory(child);
}
if (categories.containsKey(category.getQualifiedName()))
{
categories.remove(category.getQualifiedName());
if (category.parent != null)
{
category.parent.removeChild(category);
}
changed = true;
}
}
public void addCustomCategoryComment(String category, String comment)
{
if (!caseSensitiveCustomCategories)
category = category.toLowerCase(Locale.ENGLISH);
getCategory(category).setComment(comment);
}
private void setChild(String name, Configuration child)
{
if (!children.containsKey(name))
{
children.put(name, child);
changed = true;
}
else
{
Configuration old = children.get(name);
child.categories = old.categories;
child.fileName = old.fileName;
old.changed = true;
}
}
public static void enableGlobalConfig()
{
PARENT = new Configuration(new File(Loader.instance().getConfigDir(), "global.cfg"));
PARENT.load();
}
public static class UnicodeInputStreamReader extends Reader
{
private final InputStreamReader input;
private final String defaultEnc;
public UnicodeInputStreamReader(InputStream source, String encoding) throws IOException
{
defaultEnc = encoding;
String enc = encoding;
byte[] data = new byte[4];
PushbackInputStream pbStream = new PushbackInputStream(source, data.length);
int read = pbStream.read(data, 0, data.length);
int size = 0;
int bom16 = (data[0] & 0xFF) << 8 | (data[1] & 0xFF);
int bom24 = bom16 << 8 | (data[2] & 0xFF);
int bom32 = bom24 << 8 | (data[3] & 0xFF);
if (bom24 == 0xEFBBBF)
{
enc = "UTF-8";
size = 3;
}
else if (bom16 == 0xFEFF)
{
enc = "UTF-16BE";
size = 2;
}
else if (bom16 == 0xFFFE)
{
enc = "UTF-16LE";
size = 2;
}
else if (bom32 == 0x0000FEFF)
{
enc = "UTF-32BE";
size = 4;
}
else if (bom32 == 0xFFFE0000) //This will never happen as it'll be caught by UTF-16LE,
{ //but if anyone ever runs across a 32LE file, i'd like to disect it.
enc = "UTF-32LE";
size = 4;
}
if (size < read)
{
pbStream.unread(data, size, read - size);
}
this.input = new InputStreamReader(pbStream, enc);
}
public String getEncoding()
{
return input.getEncoding();
}
@Override
public int read(char[] cbuf, int off, int len) throws IOException
{
return input.read(cbuf, off, len);
}
@Override
public void close() throws IOException
{
input.close();
}
}
public boolean hasChanged()
{
if (changed) return true;
for (ConfigCategory cat : categories.values())
{
if (cat.hasChanged()) return true;
}
for (Configuration child : children.values())
{
if (child.hasChanged()) return true;
}
return false;
}
private void resetChangedState()
{
changed = false;
for (ConfigCategory cat : categories.values())
{
cat.resetChangedState();
}
for (Configuration child : children.values())
{
child.resetChangedState();
}
}
public Set<String> getCategoryNames()
{
return ImmutableSet.copyOf(categories.keySet());
}
}
@@ -1,430 +0,0 @@
package net.minecraftforge.common;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import java.util.logging.Level;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.HashMultiset;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.MapMaker;
import com.google.common.collect.Maps;
import com.google.common.collect.Multiset;
import com.google.common.collect.Sets;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.FMLLog;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.ChunkCoordIntPair;
import net.minecraft.world.MinecraftException;
import net.minecraft.world.World;
import net.minecraft.world.WorldManager;
import net.minecraft.world.WorldProvider;
import net.minecraft.world.WorldProviderEnd;
import net.minecraft.world.WorldProviderHell;
import net.minecraft.world.WorldProviderSurface;
import net.minecraft.world.WorldServer;
import net.minecraft.world.WorldServerMulti;
import net.minecraft.world.WorldSettings;
import net.minecraft.world.storage.ISaveHandler;
import net.minecraft.world.storage.SaveHandler;
import net.minecraftforge.event.world.WorldEvent;
public class DimensionManager
{
private static Hashtable<Integer, Class<? extends WorldProvider>> providers = new Hashtable<Integer, Class<? extends WorldProvider>>();
private static Hashtable<Integer, Boolean> spawnSettings = new Hashtable<Integer, Boolean>();
private static Hashtable<Integer, WorldServer> worlds = new Hashtable<Integer, WorldServer>();
private static boolean hasInit = false;
private static Hashtable<Integer, Integer> dimensions = new Hashtable<Integer, Integer>();
private static ArrayList<Integer> unloadQueue = new ArrayList<Integer>();
private static BitSet dimensionMap = new BitSet(Long.SIZE << 4);
private static ConcurrentMap<World, World> weakWorldMap = new MapMaker().weakKeys().weakValues().<World,World>makeMap();
private static Multiset<Integer> leakedWorlds = HashMultiset.create();
public static boolean registerProviderType(int id, Class<? extends WorldProvider> provider, boolean keepLoaded)
{
if (providers.containsKey(id))
{
return false;
}
providers.put(id, provider);
spawnSettings.put(id, keepLoaded);
return true;
}
/**
* Unregisters a Provider type, and returns a array of all dimensions that are
* registered to this provider type.
* If the return size is greater then 0, it is required that the caller either
* change those dimensions's registered type, or replace this type before the
* world is attempted to load, else the loader will throw an exception.
*
* @param id The provider type ID to unreigster
* @return An array containing all dimension IDs still registered to this provider type.
*/
public static int[] unregisterProviderType(int id)
{
if (!providers.containsKey(id))
{
return new int[0];
}
providers.remove(id);
spawnSettings.remove(id);
int[] ret = new int[dimensions.size()];
int x = 0;
for (Map.Entry<Integer, Integer> ent : dimensions.entrySet())
{
if (ent.getValue() == id)
{
ret[x++] = ent.getKey();
}
}
return Arrays.copyOf(ret, x);
}
public static void init()
{
if (hasInit)
{
return;
}
hasInit = true;
registerProviderType( 0, WorldProviderSurface.class, true);
registerProviderType(-1, WorldProviderHell.class, true);
registerProviderType( 1, WorldProviderEnd.class, false);
registerDimension( 0, 0);
registerDimension(-1, -1);
registerDimension( 1, 1);
}
public static void registerDimension(int id, int providerType)
{
if (!providers.containsKey(providerType))
{
throw new IllegalArgumentException(String.format("Failed to register dimension for id %d, provider type %d does not exist", id, providerType));
}
if (dimensions.containsKey(id))
{
throw new IllegalArgumentException(String.format("Failed to register dimension for id %d, One is already registered", id));
}
dimensions.put(id, providerType);
if (id >= 0)
{
dimensionMap.set(id);
}
}
/**
* For unregistering a dimension when the save is changed (disconnected from a server or loaded a new save
*/
public static void unregisterDimension(int id)
{
if (!dimensions.containsKey(id))
{
throw new IllegalArgumentException(String.format("Failed to unregister dimension for id %d; No provider registered", id));
}
dimensions.remove(id);
}
public static boolean isDimensionRegistered(int dim)
{
return dimensions.containsKey(dim);
}
public static int getProviderType(int dim)
{
if (!dimensions.containsKey(dim))
{
throw new IllegalArgumentException(String.format("Could not get provider type for dimension %d, does not exist", dim));
}
return dimensions.get(dim);
}
public static WorldProvider getProvider(int dim)
{
return getWorld(dim).provider;
}
public static Integer[] getIDs(boolean check)
{
if (check)
{
List<World> allWorlds = Lists.newArrayList(weakWorldMap.keySet());
allWorlds.removeAll(worlds.values());
for (ListIterator<World> li = allWorlds.listIterator(); li.hasNext(); )
{
World w = li.next();
leakedWorlds.add(System.identityHashCode(w));
}
for (World w : allWorlds)
{
int leakCount = leakedWorlds.count(System.identityHashCode(w));
if (leakCount == 5)
{
FMLLog.fine("The world %x (%s) may have leaked: first encounter (5 occurences).\n", System.identityHashCode(w), w.getWorldInfo().getWorldName());
}
else if (leakCount % 5 == 0)
{
FMLLog.fine("The world %x (%s) may have leaked: seen %d times.\n", System.identityHashCode(w), w.getWorldInfo().getWorldName(), leakCount);
}
}
}
return getIDs();
}
public static Integer[] getIDs()
{
return worlds.keySet().toArray(new Integer[worlds.size()]); //Only loaded dims, since usually used to cycle through loaded worlds
}
public static void setWorld(int id, WorldServer world)
{
if (world != null) {
worlds.put(id, world);
weakWorldMap.put(world, world);
MinecraftServer.getServer().worldTickTimes.put(id, new long[100]);
FMLLog.info("Loading dimension %d (%s) (%s)", id, world.getWorldInfo().getWorldName(), world.getMinecraftServer());
} else {
worlds.remove(id);
MinecraftServer.getServer().worldTickTimes.remove(id);
FMLLog.info("Unloading dimension %d", id);
}
ArrayList<WorldServer> tmp = new ArrayList<WorldServer>();
if (worlds.get( 0) != null)
tmp.add(worlds.get( 0));
if (worlds.get(-1) != null)
tmp.add(worlds.get(-1));
if (worlds.get( 1) != null)
tmp.add(worlds.get( 1));
for (Entry<Integer, WorldServer> entry : worlds.entrySet())
{
int dim = entry.getKey();
if (dim >= -1 && dim <= 1)
{
continue;
}
tmp.add(entry.getValue());
}
MinecraftServer.getServer().worldServers = tmp.toArray(new WorldServer[tmp.size()]);
}
public static void initDimension(int dim) {
WorldServer overworld = getWorld(0);
if (overworld == null) {
throw new RuntimeException("Cannot Hotload Dim: Overworld is not Loaded!");
}
try {
DimensionManager.getProviderType(dim);
} catch (Exception e) {
System.err.println("Cannot Hotload Dim: " + e.getMessage());
return; //If a provider hasn't been registered then we can't hotload the dim
}
MinecraftServer mcServer = overworld.getMinecraftServer();
ISaveHandler savehandler = overworld.getSaveHandler();
WorldSettings worldSettings = new WorldSettings(overworld.getWorldInfo());
WorldServer world = (dim == 0 ? overworld : new WorldServerMulti(mcServer, savehandler, overworld.getWorldInfo().getWorldName(), dim, worldSettings, overworld, mcServer.theProfiler, overworld.getWorldLogAgent()));
world.addWorldAccess(new WorldManager(mcServer, world));
MinecraftForge.EVENT_BUS.post(new WorldEvent.Load(world));
if (!mcServer.isSinglePlayer())
{
world.getWorldInfo().setGameType(mcServer.getGameType());
}
mcServer.setDifficultyForAllWorlds(mcServer.getDifficulty());
}
public static WorldServer getWorld(int id)
{
return worlds.get(id);
}
public static WorldServer[] getWorlds()
{
return worlds.values().toArray(new WorldServer[worlds.size()]);
}
public static boolean shouldLoadSpawn(int dim)
{
int id = getProviderType(dim);
return spawnSettings.containsKey(id) && spawnSettings.get(id);
}
static
{
init();
}
/**
* Not public API: used internally to get dimensions that should load at
* server startup
*/
public static Integer[] getStaticDimensionIDs()
{
return dimensions.keySet().toArray(new Integer[dimensions.keySet().size()]);
}
public static WorldProvider createProviderFor(int dim)
{
try
{
if (dimensions.containsKey(dim))
{
WorldProvider provider = providers.get(getProviderType(dim)).newInstance();
provider.setDimension(dim);
return provider;
}
else
{
throw new RuntimeException(String.format("No WorldProvider bound for dimension %d", dim)); //It's going to crash anyway at this point. Might as well be informative
}
}
catch (Exception e)
{
FMLCommonHandler.instance().getFMLLogger().log(Level.SEVERE,String.format("An error occured trying to create an instance of WorldProvider %d (%s)",
dim, providers.get(getProviderType(dim)).getSimpleName()),e);
throw new RuntimeException(e);
}
}
public static void unloadWorld(int id) {
unloadQueue.add(id);
}
/*
* To be called by the server at the appropriate time, do not call from mod code.
*/
public static void unloadWorlds(Hashtable<Integer, long[]> worldTickTimes) {
for (int id : unloadQueue) {
WorldServer w = worlds.get(id);
try {
if (w != null)
{
w.saveAllChunks(true, null);
}
else
{
FMLLog.warning("Unexpected world unload - world %d is already unloaded", id);
}
} catch (MinecraftException e) {
e.printStackTrace();
}
finally
{
if (w != null)
{
MinecraftForge.EVENT_BUS.post(new WorldEvent.Unload(w));
w.flush();
setWorld(id, null);
}
}
}
unloadQueue.clear();
}
/**
* Return the next free dimension ID. Note: you are not guaranteed a contiguous
* block of free ids. Always call for each individual ID you wish to get.
* @return the next free dimension ID
*/
public static int getNextFreeDimId() {
int next = 0;
while (true)
{
next = dimensionMap.nextClearBit(next);
if (dimensions.containsKey(next))
{
dimensionMap.set(next);
}
else
{
return next;
}
}
}
public static NBTTagCompound saveDimensionDataMap()
{
int[] data = new int[(dimensionMap.length() + Integer.SIZE - 1 )/ Integer.SIZE];
NBTTagCompound dimMap = new NBTTagCompound();
for (int i = 0; i < data.length; i++)
{
int val = 0;
for (int j = 0; j < Integer.SIZE; j++)
{
val |= dimensionMap.get(i * Integer.SIZE + j) ? (1 << j) : 0;
}
data[i] = val;
}
dimMap.setIntArray("DimensionArray", data);
return dimMap;
}
public static void loadDimensionDataMap(NBTTagCompound compoundTag)
{
if (compoundTag == null)
{
dimensionMap.clear();
for (Integer id : dimensions.keySet())
{
if (id >= 0)
{
dimensionMap.set(id);
}
}
}
else
{
int[] intArray = compoundTag.getIntArray("DimensionArray");
for (int i = 0; i < intArray.length; i++)
{
for (int j = 0; j < Integer.SIZE; j++)
{
dimensionMap.set(i * Integer.SIZE + j, (intArray[i] & (1 << j)) != 0);
}
}
}
}
/**
* Return the current root directory for the world save. Accesses getSaveHandler from the overworld
* @return the root directory of the save
*/
public static File getCurrentSaveRootDirectory()
{
if (DimensionManager.getWorld(0) != null)
{
return ((SaveHandler)DimensionManager.getWorld(0).getSaveHandler()).getWorldDirectory();
}
else if (MinecraftServer.getServer() != null)
{
MinecraftServer srv = MinecraftServer.getServer();
SaveHandler saveHandler = (SaveHandler) srv.getActiveAnvilConverter().getSaveLoader(srv.getFolderName(), false);
return saveHandler.getWorldDirectory();
}
else
{
return null;
}
}
}
@@ -1,111 +0,0 @@
package net.minecraftforge.common;
import java.util.ArrayList;
import java.util.Random;
import cpw.mods.fml.common.FMLLog;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.WeightedRandom;
import net.minecraft.util.WeightedRandomChestContent;
import net.minecraft.util.WeightedRandomItem;
import static net.minecraftforge.common.ChestGenHooks.DUNGEON_CHEST;
public class DungeonHooks
{
private static ArrayList<DungeonMob> dungeonMobs = new ArrayList<DungeonMob>();
/**
* Adds a mob to the possible list of creatures the spawner will create.
* If the mob is already in the spawn list, the rarity will be added to the existing one,
* causing the mob to be more common.
*
* @param name The name of the monster, use the same name used when registering the entity.
* @param rarity The rarity of selecting this mob over others. Must be greater then 0.
* Vanilla Minecraft has the following mobs:
* Spider 100
* Skeleton 100
* Zombie 200
* Meaning, Zombies are twice as common as spiders or skeletons.
* @return The new rarity of the monster,
*/
public static float addDungeonMob(String name, int rarity)
{
if (rarity <= 0)
{
throw new IllegalArgumentException("Rarity must be greater then zero");
}
for (DungeonMob mob : dungeonMobs)
{
if (name.equals(mob.type))
{
return mob.itemWeight += rarity;
}
}
dungeonMobs.add(new DungeonMob(rarity, name));
return rarity;
}
/**
* Will completely remove a Mob from the dungeon spawn list.
*
* @param name The name of the mob to remove
* @return The rarity of the removed mob, prior to being removed.
*/
public static int removeDungeonMob(String name)
{
for (DungeonMob mob : dungeonMobs)
{
if (name.equals(mob.type))
{
dungeonMobs.remove(mob);
return mob.itemWeight;
}
}
return 0;
}
/**
* Gets a random mob name from the list.
* @param rand World generation random number generator
* @return The mob name
*/
public static String getRandomDungeonMob(Random rand)
{
DungeonMob mob = (DungeonMob)WeightedRandom.getRandomItem(rand, dungeonMobs);
if (mob == null)
{
return "";
}
return mob.type;
}
public static class DungeonMob extends WeightedRandomItem
{
public String type;
public DungeonMob(int weight, String type)
{
super(weight);
this.type = type;
}
@Override
public boolean equals(Object target)
{
return target instanceof DungeonMob && type.equals(((DungeonMob)target).type);
}
}
static
{
addDungeonMob("Skeleton", 100);
addDungeonMob("Zombie", 200);
addDungeonMob("Spider", 100);
}
}
@@ -1,286 +0,0 @@
package net.minecraftforge.common;
import java.lang.reflect.*;
import java.util.*;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.FMLLog;
import net.minecraft.block.EnumMobType;
import net.minecraft.block.material.Material;
import net.minecraft.enchantment.EnumEnchantmentType;
import net.minecraft.entity.EnumCreatureAttribute;
import net.minecraft.entity.EnumCreatureType;
import net.minecraft.entity.EnumEntitySize;
import net.minecraft.entity.player.EnumStatus;
import net.minecraft.item.EnumAction;
import net.minecraft.item.EnumArmorMaterial;
import net.minecraft.item.EnumToolMaterial;
import net.minecraft.util.EnumArt;
import net.minecraft.util.EnumMovingObjectType;
import net.minecraft.world.EnumSkyBlock;
import net.minecraft.world.gen.structure.EnumDoor;
import net.minecraftforge.classloading.FMLForgePlugin;
public class EnumHelper
{
private static Object reflectionFactory = null;
private static Method newConstructorAccessor = null;
private static Method newInstance = null;
private static Method newFieldAccessor = null;
private static Method fieldAccessorSet = null;
private static boolean isSetup = false;
//Some enums are decompiled with extra arguments, so lets check for that
private static Class[][] commonTypes =
{
{EnumAction.class},
{EnumArmorMaterial.class, int.class, int[].class, int.class},
{EnumArt.class, String.class, int.class, int.class, int.class, int.class},
{EnumCreatureAttribute.class},
{EnumCreatureType.class, Class.class, int.class, Material.class, boolean.class},
{EnumDoor.class},
{EnumEnchantmentType.class},
{EnumEntitySize.class},
{EnumMobType.class},
{EnumMovingObjectType.class},
{EnumSkyBlock.class, int.class},
{EnumStatus.class},
{EnumToolMaterial.class, int.class, int.class, float.class, int.class, int.class}
};
public static EnumAction addAction(String name)
{
return addEnum(EnumAction.class, name);
}
public static EnumArmorMaterial addArmorMaterial(String name, int durability, int[] reductionAmounts, int enchantability)
{
return addEnum(EnumArmorMaterial.class, name, durability, reductionAmounts, enchantability);
}
public static EnumArt addArt(String name, String tile, int sizeX, int sizeY, int offsetX, int offsetY)
{
return addEnum(EnumArt.class, name, tile, sizeX, sizeY, offsetX, offsetY);
}
public static EnumCreatureAttribute addCreatureAttribute(String name)
{
return addEnum(EnumCreatureAttribute.class, name);
}
public static EnumCreatureType addCreatureType(String name, Class typeClass, int maxNumber, Material material, boolean peaceful)
{
return addEnum(EnumCreatureType.class, name, typeClass, maxNumber, material, peaceful);
}
public static EnumDoor addDoor(String name)
{
return addEnum(EnumDoor.class, name);
}
public static EnumEnchantmentType addEnchantmentType(String name)
{
return addEnum(EnumEnchantmentType.class, name);
}
public static EnumEntitySize addEntitySize(String name)
{
return addEnum(EnumEntitySize.class, name);
}
public static EnumMobType addMobType(String name)
{
return addEnum(EnumMobType.class, name);
}
public static EnumMovingObjectType addMovingObjectType(String name)
{
if (!isSetup)
{
setup();
}
return addEnum(EnumMovingObjectType.class, name);
}
public static EnumSkyBlock addSkyBlock(String name, int lightValue)
{
return addEnum(EnumSkyBlock.class, name, lightValue);
}
public static EnumStatus addStatus(String name)
{
return addEnum(EnumStatus.class, name);
}
public static EnumToolMaterial addToolMaterial(String name, int harvestLevel, int maxUses, float efficiency, int damage, int enchantability)
{
return addEnum(EnumToolMaterial.class, name, harvestLevel, maxUses, efficiency, damage, enchantability);
}
private static void setup()
{
if (isSetup)
{
return;
}
try
{
Method getReflectionFactory = Class.forName("sun.reflect.ReflectionFactory").getDeclaredMethod("getReflectionFactory");
reflectionFactory = getReflectionFactory.invoke(null);
newConstructorAccessor = Class.forName("sun.reflect.ReflectionFactory").getDeclaredMethod("newConstructorAccessor", Constructor.class);
newInstance = Class.forName("sun.reflect.ConstructorAccessor").getDeclaredMethod("newInstance", Object[].class);
newFieldAccessor = Class.forName("sun.reflect.ReflectionFactory").getDeclaredMethod("newFieldAccessor", Field.class, boolean.class);
fieldAccessorSet = Class.forName("sun.reflect.FieldAccessor").getDeclaredMethod("set", Object.class, Object.class);
}
catch (Exception e)
{
e.printStackTrace();
}
isSetup = true;
}
/*
* Everything below this is found at the site below, and updated to be able to compile in Eclipse/Java 1.6+
* Also modified for use in decompiled code.
* Found at: http://niceideas.ch/roller2/badtrash/entry/java_create_enum_instances_dynamically
*/
private static Object getConstructorAccessor(Class<?> enumClass, Class<?>[] additionalParameterTypes) throws Exception
{
Class<?>[] parameterTypes = new Class[additionalParameterTypes.length + 2];
parameterTypes[0] = String.class;
parameterTypes[1] = int.class;
System.arraycopy(additionalParameterTypes, 0, parameterTypes, 2, additionalParameterTypes.length);
return newConstructorAccessor.invoke(reflectionFactory, enumClass.getDeclaredConstructor(parameterTypes));
}
private static < T extends Enum<? >> T makeEnum(Class<T> enumClass, String value, int ordinal, Class<?>[] additionalTypes, Object[] additionalValues) throws Exception
{
Object[] parms = new Object[additionalValues.length + 2];
parms[0] = value;
parms[1] = Integer.valueOf(ordinal);
System.arraycopy(additionalValues, 0, parms, 2, additionalValues.length);
return enumClass.cast(newInstance.invoke(getConstructorAccessor(enumClass, additionalTypes), new Object[] {parms}));
}
public static void setFailsafeFieldValue(Field field, Object target, Object value) throws Exception
{
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
Object fieldAccessor = newFieldAccessor.invoke(reflectionFactory, field, false);
fieldAccessorSet.invoke(fieldAccessor, target, value);
}
private static void blankField(Class<?> enumClass, String fieldName) throws Exception
{
for (Field field : Class.class.getDeclaredFields())
{
if (field.getName().contains(fieldName))
{
field.setAccessible(true);
setFailsafeFieldValue(field, enumClass, null);
break;
}
}
}
private static void cleanEnumCache(Class<?> enumClass) throws Exception
{
blankField(enumClass, "enumConstantDirectory");
blankField(enumClass, "enumConstants");
}
public static <T extends Enum<? >> T addEnum(Class<T> enumType, String enumName, Object... paramValues)
{
return addEnum(commonTypes, enumType, enumName, paramValues);
}
public static <T extends Enum<? >> T addEnum(Class[][] map, Class<T> enumType, String enumName, Object... paramValues)
{
for (Class[] lookup : map)
{
if (lookup[0] == enumType)
{
Class<?>[] paramTypes = new Class<?>[lookup.length - 1];
if (paramTypes.length > 0)
{
System.arraycopy(lookup, 1, paramTypes, 0, paramTypes.length);
}
return addEnum(enumType, enumName, paramTypes, paramValues);
}
}
return null;
}
@SuppressWarnings("unchecked")
public static <T extends Enum<? >> T addEnum(Class<T> enumType, String enumName, Class<?>[] paramTypes, Object[] paramValues)
{
if (!isSetup)
{
setup();
}
Field valuesField = null;
Field[] fields = enumType.getDeclaredFields();
for (Field field : fields)
{
String name = field.getName();
if (name.equals("$VALUES") || name.equals("ENUM$VALUES")) //Added 'ENUM$VALUES' because Eclipse's internal compiler doesn't follow standards
{
valuesField = field;
break;
}
}
int flags = (FMLForgePlugin.RUNTIME_DEOBF ? Modifier.PUBLIC : Modifier.PRIVATE) | Modifier.STATIC | Modifier.FINAL | 0x1000 /*SYNTHETIC*/;
if (valuesField == null)
{
String valueType = String.format("[L%s;", enumType.getName().replace('.', '/'));
for (Field field : fields)
{
if ((field.getModifiers() & flags) == flags &&
field.getType().getName().replace('.', '/').equals(valueType)) //Apparently some JVMs return .'s and some don't..
{
valuesField = field;
break;
}
}
}
if (valuesField == null)
{
FMLLog.severe("Could not find $VALUES field for enum: %s", enumType.getName());
FMLLog.severe("Runtime Deobf: %s", FMLForgePlugin.RUNTIME_DEOBF);
FMLLog.severe("Flags: %s", String.format("%16s", Integer.toBinaryString(flags)).replace(' ', '0'));
FMLLog.severe("Fields:");
for (Field field : fields)
{
String mods = String.format("%16s", Integer.toBinaryString(field.getModifiers())).replace(' ', '0');
FMLLog.severe(" %s %s: %s", mods, field.getName(), field.getType().getName());
}
return null;
}
valuesField.setAccessible(true);
try
{
T[] previousValues = (T[])valuesField.get(enumType);
List<T> values = new ArrayList<T>(Arrays.asList(previousValues));
T newValue = (T)makeEnum(enumType, enumName, values.size(), paramTypes, paramValues);
values.add(newValue);
setFailsafeFieldValue(valuesField, null, values.toArray((T[]) Array.newInstance(enumType, 0)));
cleanEnumCache(enumType);
return newValue;
}
catch (Exception e)
{
e.printStackTrace();
throw new RuntimeException(e.getMessage(), e);
}
}
static
{
if (!isSetup)
{
setup();
}
}
}
@@ -1,12 +0,0 @@
package net.minecraftforge.common;
public enum EnumPlantType
{
Plains,
Desert,
Beach,
Cave,
Water,
Nether,
Crop
}
@@ -1,25 +0,0 @@
package net.minecraftforge.common;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.ChatMessageComponent;
import net.minecraft.util.ChunkCoordinates;
import net.minecraft.world.World;
//Preliminary, simple Fake Player class
public class FakePlayer extends EntityPlayer
{
public FakePlayer(World world, String name)
{
super(world, name);
}
public void sendChatToPlayer(String s){}
public boolean canCommandSenderUseCommand(int i, String s){ return false; }
public ChunkCoordinates getPlayerCoordinates()
{
return new ChunkCoordinates(0,0,0);
}
@Override
public void func_110122_a(ChatMessageComponent chatmessagecomponent){}
}
@@ -1,18 +0,0 @@
package net.minecraftforge.common;
import net.minecraft.world.World;
//To be expanded for generic Mod fake players?
public class FakePlayerFactory
{
private static FakePlayer MINECRAFT_PLAYER = null;
public static FakePlayer getMinecraft(World world)
{
if (MINECRAFT_PLAYER == null)
{
MINECRAFT_PLAYER = new FakePlayer(world, "[Minecraft]");
}
return MINECRAFT_PLAYER;
}
}
@@ -1,999 +0,0 @@
package net.minecraftforge.common;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.BiMap;
import com.google.common.collect.ForwardingSet;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.MapMaker;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.Multiset;
import com.google.common.collect.SetMultimap;
import com.google.common.collect.Sets;
import com.google.common.collect.TreeMultiset;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.ModContainer;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.ChunkCoordIntPair;
import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.MathHelper;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraftforge.common.ForgeChunkManager.Ticket;
import net.minecraftforge.event.Event;
/**
* Manages chunkloading for mods.
*
* The basic principle is a ticket based system.
* 1. Mods register a callback {@link #setForcedChunkLoadingCallback(Object, LoadingCallback)}
* 2. Mods ask for a ticket {@link #requestTicket(Object, World, Type)} and then hold on to that ticket.
* 3. Mods request chunks to stay loaded {@link #forceChunk(Ticket, ChunkCoordIntPair)} or remove chunks from force loading {@link #unforceChunk(Ticket, ChunkCoordIntPair)}.
* 4. When a world unloads, the tickets associated with that world are saved by the chunk manager.
* 5. When a world loads, saved tickets are offered to the mods associated with the tickets. The {@link Ticket#getModData()} that is set by the mod should be used to re-register
* chunks to stay loaded (and maybe take other actions).
*
* The chunkloading is configurable at runtime. The file "config/forgeChunkLoading.cfg" contains both default configuration for chunkloading, and a sample individual mod
* specific override section.
*
* @author cpw
*
*/
public class ForgeChunkManager
{
private static int defaultMaxCount;
private static int defaultMaxChunks;
private static boolean overridesEnabled;
private static Map<World, Multimap<String, Ticket>> tickets = new MapMaker().weakKeys().makeMap();
private static Map<String, Integer> ticketConstraints = Maps.newHashMap();
private static Map<String, Integer> chunkConstraints = Maps.newHashMap();
private static SetMultimap<String, Ticket> playerTickets = HashMultimap.create();
private static Map<String, LoadingCallback> callbacks = Maps.newHashMap();
private static Map<World, ImmutableSetMultimap<ChunkCoordIntPair,Ticket>> forcedChunks = new MapMaker().weakKeys().makeMap();
private static BiMap<UUID,Ticket> pendingEntities = HashBiMap.create();
private static Map<World,Cache<Long, Chunk>> dormantChunkCache = new MapMaker().weakKeys().makeMap();
private static File cfgFile;
private static Configuration config;
private static int playerTicketLength;
private static int dormantChunkCacheSize;
private static Set<String> warnedMods = Sets.newHashSet();
/**
* All mods requiring chunkloading need to implement this to handle the
* re-registration of chunk tickets at world loading time
*
* @author cpw
*
*/
public interface LoadingCallback
{
/**
* Called back when tickets are loaded from the world to allow the
* mod to re-register the chunks associated with those tickets. The list supplied
* here is truncated to length prior to use. Tickets unwanted by the
* mod must be disposed of manually unless the mod is an OrderedLoadingCallback instance
* in which case, they will have been disposed of by the earlier callback.
*
* @param tickets The tickets to re-register. The list is immutable and cannot be manipulated directly. Copy it first.
* @param world the world
*/
public void ticketsLoaded(List<Ticket> tickets, World world);
}
/**
* This is a special LoadingCallback that can be implemented as well as the
* LoadingCallback to provide access to additional behaviour.
* Specifically, this callback will fire prior to Forge dropping excess
* tickets. Tickets in the returned list are presumed ordered and excess will
* be truncated from the returned list.
* This allows the mod to control not only if they actually <em>want</em> a ticket but
* also their preferred ticket ordering.
*
* @author cpw
*
*/
public interface OrderedLoadingCallback extends LoadingCallback
{
/**
* Called back when tickets are loaded from the world to allow the
* mod to decide if it wants the ticket still, and prioritise overflow
* based on the ticket count.
* WARNING: You cannot force chunks in this callback, it is strictly for allowing the mod
* to be more selective in which tickets it wishes to preserve in an overflow situation
*
* @param tickets The tickets that you will want to select from. The list is immutable and cannot be manipulated directly. Copy it first.
* @param world The world
* @param maxTicketCount The maximum number of tickets that will be allowed.
* @return A list of the tickets this mod wishes to continue using. This list will be truncated
* to "maxTicketCount" size after the call returns and then offered to the other callback
* method
*/
public List<Ticket> ticketsLoaded(List<Ticket> tickets, World world, int maxTicketCount);
}
public interface PlayerOrderedLoadingCallback extends LoadingCallback
{
/**
* Called back when tickets are loaded from the world to allow the
* mod to decide if it wants the ticket still.
* This is for player bound tickets rather than mod bound tickets. It is here so mods can
* decide they want to dump all player tickets
*
* WARNING: You cannot force chunks in this callback, it is strictly for allowing the mod
* to be more selective in which tickets it wishes to preserve
*
* @param tickets The tickets that you will want to select from. The list is immutable and cannot be manipulated directly. Copy it first.
* @param world The world
* @return A list of the tickets this mod wishes to use. This list will subsequently be offered
* to the main callback for action
*/
public ListMultimap<String, Ticket> playerTicketsLoaded(ListMultimap<String, Ticket> tickets, World world);
}
public enum Type
{
/**
* For non-entity registrations
*/
NORMAL,
/**
* For entity registrations
*/
ENTITY
}
public static class Ticket
{
private String modId;
private Type ticketType;
private LinkedHashSet<ChunkCoordIntPair> requestedChunks;
private NBTTagCompound modData;
public final World world;
private int maxDepth;
private String entityClazz;
private int entityChunkX;
private int entityChunkZ;
private Entity entity;
private String player;
Ticket(String modId, Type type, World world)
{
this.modId = modId;
this.ticketType = type;
this.world = world;
this.maxDepth = getMaxChunkDepthFor(modId);
this.requestedChunks = Sets.newLinkedHashSet();
}
Ticket(String modId, Type type, World world, String player)
{
this(modId, type, world);
if (player != null)
{
this.player = player;
}
else
{
FMLLog.log(Level.SEVERE, "Attempt to create a player ticket without a valid player");
throw new RuntimeException();
}
}
/**
* The chunk list depth can be manipulated up to the maximal grant allowed for the mod. This value is configurable. Once the maximum is reached,
* the least recently forced chunk, by original registration time, is removed from the forced chunk list.
*
* @param depth The new depth to set
*/
public void setChunkListDepth(int depth)
{
if (depth > getMaxChunkDepthFor(modId) || (depth <= 0 && getMaxChunkDepthFor(modId) > 0))
{
FMLLog.warning("The mod %s tried to modify the chunk ticket depth to: %d, its allowed maximum is: %d", modId, depth, getMaxChunkDepthFor(modId));
}
else
{
this.maxDepth = depth;
}
}
/**
* Gets the current max depth for this ticket.
* Should be the same as getMaxChunkListDepth()
* unless setChunkListDepth has been called.
*
* @return Current max depth
*/
public int getChunkListDepth()
{
return maxDepth;
}
/**
* Get the maximum chunk depth size
*
* @return The maximum chunk depth size
*/
public int getMaxChunkListDepth()
{
return getMaxChunkDepthFor(modId);
}
/**
* Bind the entity to the ticket for {@link Type#ENTITY} type tickets. Other types will throw a runtime exception.
*
* @param entity The entity to bind
*/
public void bindEntity(Entity entity)
{
if (ticketType!=Type.ENTITY)
{
throw new RuntimeException("Cannot bind an entity to a non-entity ticket");
}
this.entity = entity;
}
/**
* Retrieve the {@link NBTTagCompound} that stores mod specific data for the chunk ticket.
* Example data to store would be a TileEntity or Block location. This is persisted with the ticket and
* provided to the {@link LoadingCallback} for the mod. It is recommended to use this to recover
* useful state information for the forced chunks.
*
* @return The custom compound tag for mods to store additional chunkloading data
*/
public NBTTagCompound getModData()
{
if (this.modData == null)
{
this.modData = new NBTTagCompound();
}
return modData;
}
/**
* Get the entity associated with this {@link Type#ENTITY} type ticket
* @return the entity
*/
public Entity getEntity()
{
return entity;
}
/**
* Is this a player associated ticket rather than a mod associated ticket?
*/
public boolean isPlayerTicket()
{
return player != null;
}
/**
* Get the player associated with this ticket
*/
public String getPlayerName()
{
return player;
}
/**
* Get the associated mod id
*/
public String getModId()
{
return modId;
}
/**
* Gets the ticket type
*/
public Type getType()
{
return ticketType;
}
/**
* Gets a list of requested chunks for this ticket.
*/
public ImmutableSet getChunkList()
{
return ImmutableSet.copyOf(requestedChunks);
}
}
public static class ForceChunkEvent extends Event {
public final Ticket ticket;
public final ChunkCoordIntPair location;
public ForceChunkEvent(Ticket ticket, ChunkCoordIntPair location)
{
this.ticket = ticket;
this.location = location;
}
}
public static class UnforceChunkEvent extends Event {
public final Ticket ticket;
public final ChunkCoordIntPair location;
public UnforceChunkEvent(Ticket ticket, ChunkCoordIntPair location)
{
this.ticket = ticket;
this.location = location;
}
}
/**
* Allows dynamically loading world mods to test if there are chunk tickets in the world
* Mods that add dynamically generated worlds (like Mystcraft) should call this method
* to determine if the world should be loaded during server starting.
*
* @param chunkDir The chunk directory to test: should be equivalent to {@link WorldServer#getChunkSaveLocation()}
* @return if there are tickets outstanding for this world or not
*/
public static boolean savedWorldHasForcedChunkTickets(File chunkDir)
{
File chunkLoaderData = new File(chunkDir, "forcedchunks.dat");
if (chunkLoaderData.exists() && chunkLoaderData.isFile())
{
;
try
{
NBTTagCompound forcedChunkData = CompressedStreamTools.read(chunkLoaderData);
return forcedChunkData.getTagList("TicketList").tagCount() > 0;
}
catch (IOException e)
{
}
}
return false;
}
static void loadWorld(World world)
{
ArrayListMultimap<String, Ticket> newTickets = ArrayListMultimap.<String, Ticket>create();
tickets.put(world, newTickets);
forcedChunks.put(world, ImmutableSetMultimap.<ChunkCoordIntPair,Ticket>of());
if (!(world instanceof WorldServer))
{
return;
}
dormantChunkCache.put(world, CacheBuilder.newBuilder().maximumSize(dormantChunkCacheSize).<Long, Chunk>build());
WorldServer worldServer = (WorldServer) world;
File chunkDir = worldServer.getChunkSaveLocation();
File chunkLoaderData = new File(chunkDir, "forcedchunks.dat");
if (chunkLoaderData.exists() && chunkLoaderData.isFile())
{
ArrayListMultimap<String, Ticket> loadedTickets = ArrayListMultimap.<String, Ticket>create();
Map<String,ListMultimap<String,Ticket>> playerLoadedTickets = Maps.newHashMap();
NBTTagCompound forcedChunkData;
try
{
forcedChunkData = CompressedStreamTools.read(chunkLoaderData);
}
catch (IOException e)
{
FMLLog.log(Level.WARNING, e, "Unable to read forced chunk data at %s - it will be ignored", chunkLoaderData.getAbsolutePath());
return;
}
NBTTagList ticketList = forcedChunkData.getTagList("TicketList");
for (int i = 0; i < ticketList.tagCount(); i++)
{
NBTTagCompound ticketHolder = (NBTTagCompound) ticketList.tagAt(i);
String modId = ticketHolder.getString("Owner");
boolean isPlayer = "Forge".equals(modId);
if (!isPlayer && !Loader.isModLoaded(modId))
{
FMLLog.warning("Found chunkloading data for mod %s which is currently not available or active - it will be removed from the world save", modId);
continue;
}
if (!isPlayer && !callbacks.containsKey(modId))
{
FMLLog.warning("The mod %s has registered persistent chunkloading data but doesn't seem to want to be called back with it - it will be removed from the world save", modId);
continue;
}
NBTTagList tickets = ticketHolder.getTagList("Tickets");
for (int j = 0; j < tickets.tagCount(); j++)
{
NBTTagCompound ticket = (NBTTagCompound) tickets.tagAt(j);
modId = ticket.hasKey("ModId") ? ticket.getString("ModId") : modId;
Type type = Type.values()[ticket.getByte("Type")];
byte ticketChunkDepth = ticket.getByte("ChunkListDepth");
Ticket tick = new Ticket(modId, type, world);
if (ticket.hasKey("ModData"))
{
tick.modData = ticket.getCompoundTag("ModData");
}
if (ticket.hasKey("Player"))
{
tick.player = ticket.getString("Player");
if (!playerLoadedTickets.containsKey(tick.modId))
{
playerLoadedTickets.put(modId, ArrayListMultimap.<String,Ticket>create());
}
playerLoadedTickets.get(tick.modId).put(tick.player, tick);
}
else
{
loadedTickets.put(modId, tick);
}
if (type == Type.ENTITY)
{
tick.entityChunkX = ticket.getInteger("chunkX");
tick.entityChunkZ = ticket.getInteger("chunkZ");
UUID uuid = new UUID(ticket.getLong("PersistentIDMSB"), ticket.getLong("PersistentIDLSB"));
// add the ticket to the "pending entity" list
pendingEntities.put(uuid, tick);
}
}
}
for (Ticket tick : ImmutableSet.copyOf(pendingEntities.values()))
{
if (tick.ticketType == Type.ENTITY && tick.entity == null)
{
// force the world to load the entity's chunk
// the load will come back through the loadEntity method and attach the entity
// to the ticket
world.getChunkFromChunkCoords(tick.entityChunkX, tick.entityChunkZ);
}
}
for (Ticket tick : ImmutableSet.copyOf(pendingEntities.values()))
{
if (tick.ticketType == Type.ENTITY && tick.entity == null)
{
FMLLog.warning("Failed to load persistent chunkloading entity %s from store.", pendingEntities.inverse().get(tick));
loadedTickets.remove(tick.modId, tick);
}
}
pendingEntities.clear();
// send callbacks
for (String modId : loadedTickets.keySet())
{
LoadingCallback loadingCallback = callbacks.get(modId);
if (loadingCallback == null)
{
continue;
}
int maxTicketLength = getMaxTicketLengthFor(modId);
List<Ticket> tickets = loadedTickets.get(modId);
if (loadingCallback instanceof OrderedLoadingCallback)
{
OrderedLoadingCallback orderedLoadingCallback = (OrderedLoadingCallback) loadingCallback;
tickets = orderedLoadingCallback.ticketsLoaded(ImmutableList.copyOf(tickets), world, maxTicketLength);
}
if (tickets.size() > maxTicketLength)
{
FMLLog.warning("The mod %s has too many open chunkloading tickets %d. Excess will be dropped", modId, tickets.size());
tickets.subList(maxTicketLength, tickets.size()).clear();
}
ForgeChunkManager.tickets.get(world).putAll(modId, tickets);
loadingCallback.ticketsLoaded(ImmutableList.copyOf(tickets), world);
}
for (String modId : playerLoadedTickets.keySet())
{
LoadingCallback loadingCallback = callbacks.get(modId);
if (loadingCallback == null)
{
continue;
}
ListMultimap<String,Ticket> tickets = playerLoadedTickets.get(modId);
if (loadingCallback instanceof PlayerOrderedLoadingCallback)
{
PlayerOrderedLoadingCallback orderedLoadingCallback = (PlayerOrderedLoadingCallback) loadingCallback;
tickets = orderedLoadingCallback.playerTicketsLoaded(ImmutableListMultimap.copyOf(tickets), world);
playerTickets.putAll(tickets);
}
ForgeChunkManager.tickets.get(world).putAll("Forge", tickets.values());
loadingCallback.ticketsLoaded(ImmutableList.copyOf(tickets.values()), world);
}
}
}
static void unloadWorld(World world)
{
// World save fires before this event so the chunk loading info will be done
if (!(world instanceof WorldServer))
{
return;
}
forcedChunks.remove(world);
dormantChunkCache.remove(world);
// integrated server is shutting down
if (!MinecraftServer.getServer().isServerRunning())
{
playerTickets.clear();
tickets.clear();
}
}
/**
* Set a chunkloading callback for the supplied mod object
*
* @param mod The mod instance registering the callback
* @param callback The code to call back when forced chunks are loaded
*/
public static void setForcedChunkLoadingCallback(Object mod, LoadingCallback callback)
{
ModContainer container = getContainer(mod);
if (container == null)
{
FMLLog.warning("Unable to register a callback for an unknown mod %s (%s : %x)", mod, mod.getClass().getName(), System.identityHashCode(mod));
return;
}
callbacks.put(container.getModId(), callback);
}
/**
* Discover the available tickets for the mod in the world
*
* @param mod The mod that will own the tickets
* @param world The world
* @return The count of tickets left for the mod in the supplied world
*/
public static int ticketCountAvailableFor(Object mod, World world)
{
ModContainer container = getContainer(mod);
if (container!=null)
{
String modId = container.getModId();
int allowedCount = getMaxTicketLengthFor(modId);
return allowedCount - tickets.get(world).get(modId).size();
}
else
{
return 0;
}
}
private static ModContainer getContainer(Object mod)
{
ModContainer container = Loader.instance().getModObjectList().inverse().get(mod);
return container;
}
public static int getMaxTicketLengthFor(String modId)
{
int allowedCount = ticketConstraints.containsKey(modId) && overridesEnabled ? ticketConstraints.get(modId) : defaultMaxCount;
return allowedCount;
}
public static int getMaxChunkDepthFor(String modId)
{
int allowedCount = chunkConstraints.containsKey(modId) && overridesEnabled ? chunkConstraints.get(modId) : defaultMaxChunks;
return allowedCount;
}
public static int ticketCountAvailableFor(String username)
{
return playerTicketLength - playerTickets.get(username).size();
}
public static Ticket requestPlayerTicket(Object mod, String player, World world, Type type)
{
ModContainer mc = getContainer(mod);
if (mc == null)
{
FMLLog.log(Level.SEVERE, "Failed to locate the container for mod instance %s (%s : %x)", mod, mod.getClass().getName(), System.identityHashCode(mod));
return null;
}
if (playerTickets.get(player).size()>playerTicketLength)
{
FMLLog.warning("Unable to assign further chunkloading tickets to player %s (on behalf of mod %s)", player, mc.getModId());
return null;
}
Ticket ticket = new Ticket(mc.getModId(),type,world,player);
playerTickets.put(player, ticket);
tickets.get(world).put("Forge", ticket);
return ticket;
}
/**
* Request a chunkloading ticket of the appropriate type for the supplied mod
*
* @param mod The mod requesting a ticket
* @param world The world in which it is requesting the ticket
* @param type The type of ticket
* @return A ticket with which to register chunks for loading, or null if no further tickets are available
*/
public static Ticket requestTicket(Object mod, World world, Type type)
{
ModContainer container = getContainer(mod);
if (container == null)
{
FMLLog.log(Level.SEVERE, "Failed to locate the container for mod instance %s (%s : %x)", mod, mod.getClass().getName(), System.identityHashCode(mod));
return null;
}
String modId = container.getModId();
if (!callbacks.containsKey(modId))
{
FMLLog.severe("The mod %s has attempted to request a ticket without a listener in place", modId);
throw new RuntimeException("Invalid ticket request");
}
int allowedCount = ticketConstraints.containsKey(modId) ? ticketConstraints.get(modId) : defaultMaxCount;
if (tickets.get(world).get(modId).size() >= allowedCount)
{
if (!warnedMods.contains(modId))
{
FMLLog.info("The mod %s has attempted to allocate a chunkloading ticket beyond it's currently allocated maximum : %d", modId, allowedCount);
warnedMods.add(modId);
}
return null;
}
Ticket ticket = new Ticket(modId, type, world);
tickets.get(world).put(modId, ticket);
return ticket;
}
/**
* Release the ticket back to the system. This will also unforce any chunks held by the ticket so that they can be unloaded and/or stop ticking.
*
* @param ticket The ticket to release
*/
public static void releaseTicket(Ticket ticket)
{
if (ticket == null)
{
return;
}
if (ticket.isPlayerTicket() ? !playerTickets.containsValue(ticket) : !tickets.get(ticket.world).containsEntry(ticket.modId, ticket))
{
return;
}
if (ticket.requestedChunks!=null)
{
for (ChunkCoordIntPair chunk : ImmutableSet.copyOf(ticket.requestedChunks))
{
unforceChunk(ticket, chunk);
}
}
if (ticket.isPlayerTicket())
{
playerTickets.remove(ticket.player, ticket);
tickets.get(ticket.world).remove("Forge",ticket);
}
else
{
tickets.get(ticket.world).remove(ticket.modId, ticket);
}
}
/**
* Force the supplied chunk coordinate to be loaded by the supplied ticket. If the ticket's {@link Ticket#maxDepth} is exceeded, the least
* recently registered chunk is unforced and may be unloaded.
* It is safe to force the chunk several times for a ticket, it will not generate duplication or change the ordering.
*
* @param ticket The ticket registering the chunk
* @param chunk The chunk to force
*/
public static void forceChunk(Ticket ticket, ChunkCoordIntPair chunk)
{
if (ticket == null || chunk == null)
{
return;
}
if (ticket.ticketType == Type.ENTITY && ticket.entity == null)
{
throw new RuntimeException("Attempted to use an entity ticket to force a chunk, without an entity");
}
if (ticket.isPlayerTicket() ? !playerTickets.containsValue(ticket) : !tickets.get(ticket.world).containsEntry(ticket.modId, ticket))
{
FMLLog.severe("The mod %s attempted to force load a chunk with an invalid ticket. This is not permitted.", ticket.modId);
return;
}
ticket.requestedChunks.add(chunk);
MinecraftForge.EVENT_BUS.post(new ForceChunkEvent(ticket, chunk));
ImmutableSetMultimap<ChunkCoordIntPair, Ticket> newMap = ImmutableSetMultimap.<ChunkCoordIntPair,Ticket>builder().putAll(forcedChunks.get(ticket.world)).put(chunk, ticket).build();
forcedChunks.put(ticket.world, newMap);
if (ticket.maxDepth > 0 && ticket.requestedChunks.size() > ticket.maxDepth)
{
ChunkCoordIntPair removed = ticket.requestedChunks.iterator().next();
unforceChunk(ticket,removed);
}
}
/**
* Reorganize the internal chunk list so that the chunk supplied is at the *end* of the list
* This helps if you wish to guarantee a certain "automatic unload ordering" for the chunks
* in the ticket list
*
* @param ticket The ticket holding the chunk list
* @param chunk The chunk you wish to push to the end (so that it would be unloaded last)
*/
public static void reorderChunk(Ticket ticket, ChunkCoordIntPair chunk)
{
if (ticket == null || chunk == null || !ticket.requestedChunks.contains(chunk))
{
return;
}
ticket.requestedChunks.remove(chunk);
ticket.requestedChunks.add(chunk);
}
/**
* Unforce the supplied chunk, allowing it to be unloaded and stop ticking.
*
* @param ticket The ticket holding the chunk
* @param chunk The chunk to unforce
*/
public static void unforceChunk(Ticket ticket, ChunkCoordIntPair chunk)
{
if (ticket == null || chunk == null)
{
return;
}
ticket.requestedChunks.remove(chunk);
MinecraftForge.EVENT_BUS.post(new UnforceChunkEvent(ticket, chunk));
LinkedHashMultimap<ChunkCoordIntPair, Ticket> copy = LinkedHashMultimap.create(forcedChunks.get(ticket.world));
copy.remove(chunk, ticket);
ImmutableSetMultimap<ChunkCoordIntPair, Ticket> newMap = ImmutableSetMultimap.copyOf(copy);
forcedChunks.put(ticket.world,newMap);
}
static void loadConfiguration()
{
for (String mod : config.getCategoryNames())
{
if (mod.equals("Forge") || mod.equals("defaults"))
{
continue;
}
Property modTC = config.get(mod, "maximumTicketCount", 200);
Property modCPT = config.get(mod, "maximumChunksPerTicket", 25);
ticketConstraints.put(mod, modTC.getInt(200));
chunkConstraints.put(mod, modCPT.getInt(25));
}
if (config.hasChanged())
{
config.save();
}
}
/**
* The list of persistent chunks in the world. This set is immutable.
* @param world
* @return the list of persistent chunks in the world
*/
public static ImmutableSetMultimap<ChunkCoordIntPair, Ticket> getPersistentChunksFor(World world)
{
return forcedChunks.containsKey(world) ? forcedChunks.get(world) : ImmutableSetMultimap.<ChunkCoordIntPair,Ticket>of();
}
static void saveWorld(World world)
{
// only persist persistent worlds
if (!(world instanceof WorldServer)) { return; }
WorldServer worldServer = (WorldServer) world;
File chunkDir = worldServer.getChunkSaveLocation();
File chunkLoaderData = new File(chunkDir, "forcedchunks.dat");
NBTTagCompound forcedChunkData = new NBTTagCompound();
NBTTagList ticketList = new NBTTagList();
forcedChunkData.setTag("TicketList", ticketList);
Multimap<String, Ticket> ticketSet = tickets.get(worldServer);
for (String modId : ticketSet.keySet())
{
NBTTagCompound ticketHolder = new NBTTagCompound();
ticketList.appendTag(ticketHolder);
ticketHolder.setString("Owner", modId);
NBTTagList tickets = new NBTTagList();
ticketHolder.setTag("Tickets", tickets);
for (Ticket tick : ticketSet.get(modId))
{
NBTTagCompound ticket = new NBTTagCompound();
ticket.setByte("Type", (byte) tick.ticketType.ordinal());
ticket.setByte("ChunkListDepth", (byte) tick.maxDepth);
if (tick.isPlayerTicket())
{
ticket.setString("ModId", tick.modId);
ticket.setString("Player", tick.player);
}
if (tick.modData != null)
{
ticket.setCompoundTag("ModData", tick.modData);
}
if (tick.ticketType == Type.ENTITY && tick.entity != null && tick.entity.addEntityID(new NBTTagCompound()))
{
ticket.setInteger("chunkX", MathHelper.floor_double(tick.entity.chunkCoordX));
ticket.setInteger("chunkZ", MathHelper.floor_double(tick.entity.chunkCoordZ));
ticket.setLong("PersistentIDMSB", tick.entity.getPersistentID().getMostSignificantBits());
ticket.setLong("PersistentIDLSB", tick.entity.getPersistentID().getLeastSignificantBits());
tickets.appendTag(ticket);
}
else if (tick.ticketType != Type.ENTITY)
{
tickets.appendTag(ticket);
}
}
}
try
{
CompressedStreamTools.write(forcedChunkData, chunkLoaderData);
}
catch (IOException e)
{
FMLLog.log(Level.WARNING, e, "Unable to write forced chunk data to %s - chunkloading won't work", chunkLoaderData.getAbsolutePath());
return;
}
}
static void loadEntity(Entity entity)
{
UUID id = entity.getPersistentID();
Ticket tick = pendingEntities.get(id);
if (tick != null)
{
tick.bindEntity(entity);
pendingEntities.remove(id);
}
}
public static void putDormantChunk(long coords, Chunk chunk)
{
Cache<Long, Chunk> cache = dormantChunkCache.get(chunk.worldObj);
if (cache != null)
{
cache.put(coords, chunk);
}
}
public static Chunk fetchDormantChunk(long coords, World world)
{
Cache<Long, Chunk> cache = dormantChunkCache.get(world);
if (cache == null)
{
return null;
}
Chunk chunk = cache.getIfPresent(coords);
if (chunk != null)
{
for (List<Entity> eList : chunk.entityLists)
{
for (Entity e: eList)
{
e.resetEntityId();
}
}
}
return chunk;
}
static void captureConfig(File configDir)
{
cfgFile = new File(configDir,"forgeChunkLoading.cfg");
config = new Configuration(cfgFile, true);
try
{
config.load();
}
catch (Exception e)
{
File dest = new File(cfgFile.getParentFile(),"forgeChunkLoading.cfg.bak");
if (dest.exists())
{
dest.delete();
}
cfgFile.renameTo(dest);
FMLLog.log(Level.SEVERE, e, "A critical error occured reading the forgeChunkLoading.cfg file, defaults will be used - the invalid file is backed up at forgeChunkLoading.cfg.bak");
}
config.addCustomCategoryComment("defaults", "Default configuration for forge chunk loading control");
Property maxTicketCount = config.get("defaults", "maximumTicketCount", 200);
maxTicketCount.comment = "The default maximum ticket count for a mod which does not have an override\n" +
"in this file. This is the number of chunk loading requests a mod is allowed to make.";
defaultMaxCount = maxTicketCount.getInt(200);
Property maxChunks = config.get("defaults", "maximumChunksPerTicket", 25);
maxChunks.comment = "The default maximum number of chunks a mod can force, per ticket, \n" +
"for a mod without an override. This is the maximum number of chunks a single ticket can force.";
defaultMaxChunks = maxChunks.getInt(25);
Property playerTicketCount = config.get("defaults", "playerTicketCount", 500);
playerTicketCount.comment = "The number of tickets a player can be assigned instead of a mod. This is shared across all mods and it is up to the mods to use it.";
playerTicketLength = playerTicketCount.getInt(500);
Property dormantChunkCacheSizeProperty = config.get("defaults", "dormantChunkCacheSize", 0);
dormantChunkCacheSizeProperty.comment = "Unloaded chunks can first be kept in a dormant cache for quicker\n" +
"loading times. Specify the size (in chunks) of that cache here";
dormantChunkCacheSize = dormantChunkCacheSizeProperty.getInt(0);
FMLLog.info("Configured a dormant chunk cache size of %d", dormantChunkCacheSizeProperty.getInt(0));
Property modOverridesEnabled = config.get("defaults", "enabled", true);
modOverridesEnabled.comment = "Are mod overrides enabled?";
overridesEnabled = modOverridesEnabled.getBoolean(true);
config.addCustomCategoryComment("Forge", "Sample mod specific control section.\n" +
"Copy this section and rename the with the modid for the mod you wish to override.\n" +
"A value of zero in either entry effectively disables any chunkloading capabilities\n" +
"for that mod");
Property sampleTC = config.get("Forge", "maximumTicketCount", 200);
sampleTC.comment = "Maximum ticket count for the mod. Zero disables chunkloading capabilities.";
sampleTC = config.get("Forge", "maximumChunksPerTicket", 25);
sampleTC.comment = "Maximum chunks per ticket for the mod.";
for (String mod : config.getCategoryNames())
{
if (mod.equals("Forge") || mod.equals("defaults"))
{
continue;
}
Property modTC = config.get(mod, "maximumTicketCount", 200);
Property modCPT = config.get(mod, "maximumChunksPerTicket", 25);
}
}
public static ConfigCategory getConfigFor(Object mod)
{
ModContainer container = getContainer(mod);
if (container != null)
{
return config.getCategory(container.getModId());
}
return null;
}
public static void addConfigProperty(Object mod, String propertyName, String value, Property.Type type)
{
ModContainer container = getContainer(mod);
if (container != null)
{
ConfigCategory cat = config.getCategory(container.getModId());
cat.put(propertyName, new Property(propertyName, value, type));
}
}
}
@@ -1,71 +0,0 @@
package net.minecraftforge.common;
public enum ForgeDirection
{
/** -Y */
DOWN(0, -1, 0),
/** +Y */
UP(0, 1, 0),
/** -Z */
NORTH(0, 0, -1),
/** +Z */
SOUTH(0, 0, 1),
/** -X */
WEST(-1, 0, 0),
/** +X */
EAST(1, 0, 0),
/**
* Used only by getOrientation, for invalid inputs
*/
UNKNOWN(0, 0, 0);
public final int offsetX;
public final int offsetY;
public final int offsetZ;
public final int flag;
public static final ForgeDirection[] VALID_DIRECTIONS = {DOWN, UP, NORTH, SOUTH, WEST, EAST};
public static final int[] OPPOSITES = {1, 0, 3, 2, 5, 4, 6};
// Left hand rule rotation matrix for all possible axes of rotation
public static final int[][] ROTATION_MATRIX = {
{0, 1, 4, 5, 3, 2, 6},
{0, 1, 5, 4, 2, 3, 6},
{5, 4, 2, 3, 0, 1, 6},
{4, 5, 2, 3, 1, 0, 6},
{2, 3, 1, 0, 4, 5, 6},
{3, 2, 0, 1, 4, 5, 6},
{0, 1, 2, 3, 4, 5, 6},
};
private ForgeDirection(int x, int y, int z)
{
offsetX = x;
offsetY = y;
offsetZ = z;
flag = 1 << ordinal();
}
public static ForgeDirection getOrientation(int id)
{
if (id >= 0 && id < VALID_DIRECTIONS.length)
{
return VALID_DIRECTIONS[id];
}
return UNKNOWN;
}
public ForgeDirection getOpposite()
{
return getOrientation(OPPOSITES[ordinal()]);
}
public ForgeDirection getRotation(ForgeDirection axis)
{
return getOrientation(ROTATION_MATRIX[axis.ordinal()][ordinal()]);
}
}
@@ -1,184 +0,0 @@
package net.minecraftforge.common;
import java.io.File;
import java.util.Arrays;
import java.util.Map;
import java.util.logging.Level;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.server.management.PlayerInstance;
import net.minecraft.world.storage.SaveHandler;
import net.minecraft.world.storage.WorldInfo;
import net.minecraftforge.common.network.ForgeConnectionHandler;
import net.minecraftforge.common.network.ForgeNetworkHandler;
import net.minecraftforge.common.network.ForgePacketHandler;
import net.minecraftforge.common.network.ForgeTinyPacketHandler;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import cpw.mods.fml.common.DummyModContainer;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.LoadController;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.ModMetadata;
import cpw.mods.fml.common.WorldAccessContainer;
import cpw.mods.fml.common.event.FMLConstructionEvent;
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.network.FMLNetworkHandler;
import cpw.mods.fml.common.network.NetworkMod;
import static net.minecraftforge.common.ForgeVersion.*;
@NetworkMod(
channels = "FORGE",
connectionHandler = ForgeConnectionHandler.class,
packetHandler = ForgePacketHandler.class,
tinyPacketHandler = ForgeTinyPacketHandler.class
)
public class ForgeDummyContainer extends DummyModContainer implements WorldAccessContainer
{
public static int clumpingThreshold = 64;
public static boolean legacyFurnaceSides = false;
public static boolean removeErroringEntities = false;
public static boolean removeErroringTileEntities = false;
public static boolean disableStitchedFileSaving = false;
public ForgeDummyContainer()
{
super(new ModMetadata());
ModMetadata meta = getMetadata();
meta.modId = "Forge";
meta.name = "Minecraft Forge";
meta.version = String.format("%d.%d.%d.%d", majorVersion, minorVersion, revisionVersion, buildVersion);
meta.credits = "Made possible with help from many people";
meta.authorList = Arrays.asList("LexManos", "Eloraam", "Spacetoad");
meta.description = "Minecraft Forge is a common open source API allowing a broad range of mods " +
"to work cooperatively together. It allows many mods to be created without " +
"them editing the main Minecraft code.";
meta.url = "http://MinecraftForge.net";
meta.updateUrl = "http://MinecraftForge.net/forum/index.php/topic,5.0.html";
meta.screenshots = new String[0];
meta.logoFile = "/forge_logo.png";
Configuration config = null;
File cfgFile = new File(Loader.instance().getConfigDir(), "forge.cfg");
try
{
config = new Configuration(cfgFile);
}
catch (Exception e)
{
System.out.println("Error loading forge.cfg, deleting file and resetting: ");
e.printStackTrace();
if (cfgFile.exists())
cfgFile.delete();
config = new Configuration(cfgFile);
}
if (!config.isChild)
{
config.load();
Property enableGlobalCfg = config.get(Configuration.CATEGORY_GENERAL, "enableGlobalConfig", false);
if (enableGlobalCfg.getBoolean(false))
{
Configuration.enableGlobalConfig();
}
}
Property prop;
prop = config.get(Configuration.CATEGORY_GENERAL, "clumpingThreshold", 64);
prop.comment = "Controls the number threshold at which Packet51 is preferred over Packet52, default and minimum 64, maximum 1024";
clumpingThreshold = prop.getInt(64);
if (clumpingThreshold > 1024 || clumpingThreshold < 64)
{
clumpingThreshold = 64;
prop.set(64);
}
prop = config.get(Configuration.CATEGORY_GENERAL, "legacyFurnaceOutput", false);
prop.comment = "Controls the sides of vanilla furnaces for Forge's ISidedInventroy, Vanilla defines the output as the bottom, but mods/Forge define it as the sides. Settings this to true will restore the old side relations.";
legacyFurnaceSides = prop.getBoolean(false);
prop = config.get(Configuration.CATEGORY_GENERAL, "removeErroringEntities", false);
prop.comment = "Set this to just remove any TileEntity that throws a error in there update method instead of closing the server and reporting a crash log. BE WARNED THIS COULD SCREW UP EVERYTHING USE SPARINGLY WE ARE NOT RESPONSIBLE FOR DAMAGES.";
removeErroringEntities = prop.getBoolean(false);
if (removeErroringEntities)
{
FMLLog.warning("Enableing removal of erroring Entities USE AT YOUR OWN RISK");
}
prop = config.get(Configuration.CATEGORY_GENERAL, "removeErroringTileEntities", false);
prop.comment = "Set this to just remove any TileEntity that throws a error in there update method instead of closing the server and reporting a crash log. BE WARNED THIS COULD SCREW UP EVERYTHING USE SPARINGLY WE ARE NOT RESPONSIBLE FOR DAMAGES.";
removeErroringTileEntities = prop.getBoolean(false);
if (removeErroringTileEntities)
{
FMLLog.warning("Enableing removal of erroring Tile Entities USE AT YOUR OWN RISK");
}
prop = config.get(Configuration.CATEGORY_GENERAL, "disableStitchedFileSaving", true);
prop.comment = "Set this to just disable the texture stitcher from writing the 'debug.stitched_{name}.png file to disc. Just a small performance tweak. Default: true";
disableStitchedFileSaving = prop.getBoolean(true);
if (config.hasChanged())
{
config.save();
}
}
@Override
public boolean registerBus(EventBus bus, LoadController controller)
{
bus.register(this);
return true;
}
@Subscribe
public void modConstruction(FMLConstructionEvent evt)
{
FMLLog.info("Registering Forge Packet Handler");
try
{
FMLNetworkHandler.instance().registerNetworkMod(new ForgeNetworkHandler(this));
FMLLog.info("Succeeded registering Forge Packet Handler");
}
catch (Exception e)
{
FMLLog.log(Level.SEVERE, e, "Failed to register packet handler for Forge");
}
}
@Subscribe
public void preInit(FMLPreInitializationEvent evt)
{
ForgeChunkManager.captureConfig(evt.getModConfigurationDirectory());
}
@Subscribe
public void postInit(FMLPostInitializationEvent evt)
{
ForgeChunkManager.loadConfiguration();
}
@Override
public NBTTagCompound getDataForWriting(SaveHandler handler, WorldInfo info)
{
NBTTagCompound forgeData = new NBTTagCompound();
NBTTagCompound dimData = DimensionManager.saveDimensionDataMap();
forgeData.setCompoundTag("DimensionData", dimData);
return forgeData;
}
@Override
public void readData(SaveHandler handler, WorldInfo info, Map<String, NBTBase> propertyMap, NBTTagCompound tag)
{
if (tag.hasKey("DimensionData"))
{
DimensionManager.loadDimensionDataMap(tag.hasKey("DimensionData") ? tag.getCompoundTag("DimensionData") : null);
}
}
}
@@ -1,401 +0,0 @@
package net.minecraftforge.common;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import net.minecraft.block.Block;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemArmor;
import net.minecraft.item.ItemAxe;
import net.minecraft.item.ItemPickaxe;
import net.minecraft.item.ItemSpade;
import net.minecraft.item.ItemStack;
import net.minecraft.network.NetServerHandler;
import net.minecraft.util.ChatMessageComponent;
import net.minecraft.util.DamageSource;
import net.minecraft.util.EnumMovingObjectType;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.util.WeightedRandom;
import net.minecraft.util.WeightedRandomItem;
import net.minecraft.world.World;
import net.minecraftforge.event.ForgeEventFactory;
import net.minecraftforge.event.ServerChatEvent;
import net.minecraftforge.event.entity.item.ItemTossEvent;
import net.minecraftforge.event.entity.living.LivingAttackEvent;
import net.minecraftforge.event.entity.living.LivingDeathEvent;
import net.minecraftforge.event.entity.living.LivingDropsEvent;
import net.minecraftforge.event.entity.living.LivingEvent.LivingJumpEvent;
import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent;
import net.minecraftforge.event.entity.living.LivingFallEvent;
import net.minecraftforge.event.entity.living.LivingHurtEvent;
import net.minecraftforge.event.entity.living.LivingSetAttackTargetEvent;
public class ForgeHooks
{
static class GrassEntry extends WeightedRandomItem
{
public final Block block;
public final int metadata;
public GrassEntry(Block block, int meta, int weight)
{
super(weight);
this.block = block;
this.metadata = meta;
}
}
static class SeedEntry extends WeightedRandomItem
{
public final ItemStack seed;
public SeedEntry(ItemStack seed, int weight)
{
super(weight);
this.seed = seed;
}
}
static final List<GrassEntry> grassList = new ArrayList<GrassEntry>();
static final List<SeedEntry> seedList = new ArrayList<SeedEntry>();
public static void plantGrass(World world, int x, int y, int z)
{
GrassEntry grass = (GrassEntry)WeightedRandom.getRandomItem(world.rand, grassList);
if (grass == null || grass.block == null || !grass.block.canBlockStay(world, x, y, z))
{
return;
}
world.setBlock(x, y, z, grass.block.blockID, grass.metadata, 3);
}
public static ItemStack getGrassSeed(World world)
{
SeedEntry entry = (SeedEntry)WeightedRandom.getRandomItem(world.rand, seedList);
if (entry == null || entry.seed == null)
{
return null;
}
return entry.seed.copy();
}
private static boolean toolInit = false;
static HashMap<Item, List> toolClasses = new HashMap<Item, List>();
static HashMap<List, Integer> toolHarvestLevels = new HashMap<List, Integer>();
static HashSet<List> toolEffectiveness = new HashSet<List>();
public static boolean canHarvestBlock(Block block, EntityPlayer player, int metadata)
{
if (block.blockMaterial.isToolNotRequired())
{
return true;
}
ItemStack stack = player.inventory.getCurrentItem();
if (stack == null)
{
return player.canHarvestBlock(block);
}
List info = toolClasses.get(stack.getItem());
if (info == null)
{
return player.canHarvestBlock(block);
}
Object[] tmp = info.toArray();
String toolClass = (String)tmp[0];
int harvestLevel = (Integer)tmp[1];
Integer blockHarvestLevel = toolHarvestLevels.get(Arrays.asList(block, metadata, toolClass));
if (blockHarvestLevel == null)
{
return player.canHarvestBlock(block);
}
if (blockHarvestLevel > harvestLevel)
{
return false;
}
return true;
}
public static boolean canToolHarvestBlock(Block block, int metadata, ItemStack stack)
{
if (stack == null) return false;
List info = toolClasses.get(stack.getItem());
if (info == null) return false;
Object[] tmp = info.toArray();
String toolClass = (String)tmp[0];
int harvestLevel = (Integer)tmp[1];
Integer blockHarvestLevel = toolHarvestLevels.get(Arrays.asList(block, metadata, toolClass));
return !(blockHarvestLevel == null || blockHarvestLevel > harvestLevel);
}
public static float blockStrength(Block block, EntityPlayer player, World world, int x, int y, int z)
{
int metadata = world.getBlockMetadata(x, y, z);
float hardness = block.getBlockHardness(world, x, y, z);
if (hardness < 0.0F)
{
return 0.0F;
}
if (!canHarvestBlock(block, player, metadata))
{
float speed = ForgeEventFactory.getBreakSpeed(player, block, metadata, 1.0f);
return (speed < 0 ? 0 : speed) / hardness / 100F;
}
else
{
return player.getCurrentPlayerStrVsBlock(block, false, metadata) / hardness / 30F;
}
}
public static boolean isToolEffective(ItemStack stack, Block block, int metadata)
{
List toolClass = toolClasses.get(stack.getItem());
return toolClass != null && toolEffectiveness.contains(Arrays.asList(block, metadata, toolClass.get(0)));
}
static void initTools()
{
if (toolInit)
{
return;
}
toolInit = true;
MinecraftForge.setToolClass(Item.pickaxeWood, "pickaxe", 0);
MinecraftForge.setToolClass(Item.pickaxeStone, "pickaxe", 1);
MinecraftForge.setToolClass(Item.pickaxeIron, "pickaxe", 2);
MinecraftForge.setToolClass(Item.pickaxeGold, "pickaxe", 0);
MinecraftForge.setToolClass(Item.pickaxeDiamond, "pickaxe", 3);
MinecraftForge.setToolClass(Item.axeWood, "axe", 0);
MinecraftForge.setToolClass(Item.axeStone, "axe", 1);
MinecraftForge.setToolClass(Item.axeIron, "axe", 2);
MinecraftForge.setToolClass(Item.axeGold, "axe", 0);
MinecraftForge.setToolClass(Item.axeDiamond, "axe", 3);
MinecraftForge.setToolClass(Item.shovelWood, "shovel", 0);
MinecraftForge.setToolClass(Item.shovelStone, "shovel", 1);
MinecraftForge.setToolClass(Item.shovelIron, "shovel", 2);
MinecraftForge.setToolClass(Item.shovelGold, "shovel", 0);
MinecraftForge.setToolClass(Item.shovelDiamond, "shovel", 3);
for (Block block : ItemPickaxe.blocksEffectiveAgainst)
{
MinecraftForge.setBlockHarvestLevel(block, "pickaxe", 0);
}
for (Block block : ItemSpade.blocksEffectiveAgainst)
{
MinecraftForge.setBlockHarvestLevel(block, "shovel", 0);
}
for (Block block : ItemAxe.blocksEffectiveAgainst)
{
MinecraftForge.setBlockHarvestLevel(block, "axe", 0);
}
MinecraftForge.setBlockHarvestLevel(Block.obsidian, "pickaxe", 3);
MinecraftForge.setBlockHarvestLevel(Block.oreEmerald, "pickaxe", 2);
MinecraftForge.setBlockHarvestLevel(Block.oreDiamond, "pickaxe", 2);
MinecraftForge.setBlockHarvestLevel(Block.blockDiamond, "pickaxe", 2);
MinecraftForge.setBlockHarvestLevel(Block.oreGold, "pickaxe", 2);
MinecraftForge.setBlockHarvestLevel(Block.blockGold, "pickaxe", 2);
MinecraftForge.setBlockHarvestLevel(Block.oreIron, "pickaxe", 1);
MinecraftForge.setBlockHarvestLevel(Block.blockIron, "pickaxe", 1);
MinecraftForge.setBlockHarvestLevel(Block.oreLapis, "pickaxe", 1);
MinecraftForge.setBlockHarvestLevel(Block.blockLapis, "pickaxe", 1);
MinecraftForge.setBlockHarvestLevel(Block.oreRedstone, "pickaxe", 2);
MinecraftForge.setBlockHarvestLevel(Block.oreRedstoneGlowing, "pickaxe", 2);
MinecraftForge.removeBlockEffectiveness(Block.oreRedstone, "pickaxe");
MinecraftForge.removeBlockEffectiveness(Block.obsidian, "pickaxe");
MinecraftForge.removeBlockEffectiveness(Block.oreRedstoneGlowing, "pickaxe");
}
public static int getTotalArmorValue(EntityPlayer player)
{
int ret = 0;
for (int x = 0; x < player.inventory.armorInventory.length; x++)
{
ItemStack stack = player.inventory.armorInventory[x];
if (stack != null && stack.getItem() instanceof ISpecialArmor)
{
ret += ((ISpecialArmor)stack.getItem()).getArmorDisplay(player, stack, x);
}
else if (stack != null && stack.getItem() instanceof ItemArmor)
{
ret += ((ItemArmor)stack.getItem()).damageReduceAmount;
}
}
return ret;
}
static
{
grassList.add(new GrassEntry(Block.plantYellow, 0, 20));
grassList.add(new GrassEntry(Block.plantRed, 0, 10));
seedList.add(new SeedEntry(new ItemStack(Item.seeds), 10));
initTools();
}
/**
* Called when a player uses 'pick block', calls new Entity and Block hooks.
*/
public static boolean onPickBlock(MovingObjectPosition target, EntityPlayer player, World world)
{
ItemStack result = null;
boolean isCreative = player.capabilities.isCreativeMode;
if (target.typeOfHit == EnumMovingObjectType.TILE)
{
int x = target.blockX;
int y = target.blockY;
int z = target.blockZ;
Block var8 = Block.blocksList[world.getBlockId(x, y, z)];
if (var8 == null)
{
return false;
}
result = var8.getPickBlock(target, world, x, y, z);
}
else
{
if (target.typeOfHit != EnumMovingObjectType.ENTITY || target.entityHit == null || !isCreative)
{
return false;
}
result = target.entityHit.getPickedResult(target);
}
if (result == null)
{
return false;
}
for (int x = 0; x < 9; x++)
{
ItemStack stack = player.inventory.getStackInSlot(x);
if (stack != null && stack.isItemEqual(result) && ItemStack.areItemStackTagsEqual(stack, result))
{
player.inventory.currentItem = x;
return true;
}
}
if (!isCreative)
{
return false;
}
int slot = player.inventory.getFirstEmptyStack();
if (slot < 0 || slot >= 9)
{
slot = player.inventory.currentItem;
}
player.inventory.setInventorySlotContents(slot, result);
player.inventory.currentItem = slot;
return true;
}
//Optifine Helper Functions u.u, these are here specifically for Optifine
//Note: When using Optfine, these methods are invoked using reflection, which
//incurs a major performance penalty.
public static void onLivingSetAttackTarget(EntityLivingBase entity, EntityLivingBase target)
{
MinecraftForge.EVENT_BUS.post(new LivingSetAttackTargetEvent(entity, target));
}
public static boolean onLivingUpdate(EntityLivingBase entity)
{
return MinecraftForge.EVENT_BUS.post(new LivingUpdateEvent(entity));
}
public static boolean onLivingAttack(EntityLivingBase entity, DamageSource src, float amount)
{
return MinecraftForge.EVENT_BUS.post(new LivingAttackEvent(entity, src, amount));
}
public static float onLivingHurt(EntityLivingBase entity, DamageSource src, float amount)
{
LivingHurtEvent event = new LivingHurtEvent(entity, src, amount);
return (MinecraftForge.EVENT_BUS.post(event) ? 0 : event.ammount);
}
public static boolean onLivingDeath(EntityLivingBase entity, DamageSource src)
{
return MinecraftForge.EVENT_BUS.post(new LivingDeathEvent(entity, src));
}
public static boolean onLivingDrops(EntityLivingBase entity, DamageSource source, ArrayList<EntityItem> drops, int lootingLevel, boolean recentlyHit, int specialDropValue)
{
return MinecraftForge.EVENT_BUS.post(new LivingDropsEvent(entity, source, drops, lootingLevel, recentlyHit, specialDropValue));
}
public static float onLivingFall(EntityLivingBase entity, float distance)
{
LivingFallEvent event = new LivingFallEvent(entity, distance);
return (MinecraftForge.EVENT_BUS.post(event) ? 0.0f : event.distance);
}
public static boolean isLivingOnLadder(Block block, World world, int x, int y, int z, EntityLivingBase entity)
{
return block != null && block.isLadder(world, x, y, z, entity);
}
public static void onLivingJump(EntityLivingBase entity)
{
MinecraftForge.EVENT_BUS.post(new LivingJumpEvent(entity));
}
public static EntityItem onPlayerTossEvent(EntityPlayer player, ItemStack item)
{
player.captureDrops = true;
EntityItem ret = player.dropPlayerItemWithRandomChoice(item, false);
player.capturedDrops.clear();
player.captureDrops = false;
ItemTossEvent event = new ItemTossEvent(ret, player);
if (MinecraftForge.EVENT_BUS.post(event))
{
return null;
}
player.joinEntityItemWithWorld(event.entityItem);
return event.entityItem;
}
public static float getEnchantPower(World world, int x, int y, int z)
{
if (world.isAirBlock(x, y, z))
{
return 0;
}
Block block = Block.blocksList[world.getBlockId(x, y, z)];
return (block == null ? 0 : block.getEnchantPowerBonus(world, x, y, z));
}
public static ChatMessageComponent onServerChatEvent(NetServerHandler net, String raw, ChatMessageComponent comp)
{
ServerChatEvent event = new ServerChatEvent(net.playerEntity, raw, comp);
if (MinecraftForge.EVENT_BUS.post(event))
{
return null;
}
return event.component;
}
}
@@ -1,78 +0,0 @@
package net.minecraftforge.common;
import java.util.UUID;
import cpw.mods.fml.common.FMLLog;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraftforge.event.*;
import net.minecraftforge.event.entity.*;
import net.minecraftforge.event.world.WorldEvent;
public class ForgeInternalHandler
{
@ForgeSubscribe(priority = EventPriority.HIGHEST)
public void onEntityJoinWorld(EntityJoinWorldEvent event)
{
if (!event.world.isRemote)
{
ForgeChunkManager.loadEntity(event.entity);
}
Entity entity = event.entity;
if (entity.getClass().equals(EntityItem.class))
{
ItemStack stack = entity.getDataWatcher().getWatchableObjectItemStack(10);
if (stack == null)
{
//entity.setDead();
//event.setCanceled(true);
return;
}
Item item = stack.getItem();
if (item == null)
{
FMLLog.warning("Attempted to add a EntityItem to the world with a invalid item: ID %d at " +
"(%2.2f, %2.2f, %2.2f), this is most likely a config issue between you and the server. Please double check your configs",
stack.itemID, entity.posX, entity.posY, entity.posZ);
entity.setDead();
event.setCanceled(true);
return;
}
if (item.hasCustomEntity(stack))
{
Entity newEntity = item.createEntity(event.world, entity, stack);
if (newEntity != null)
{
entity.setDead();
event.setCanceled(true);
event.world.spawnEntityInWorld(newEntity);
}
}
}
}
@ForgeSubscribe(priority = EventPriority.HIGHEST)
public void onDimensionLoad(WorldEvent.Load event)
{
ForgeChunkManager.loadWorld(event.world);
}
@ForgeSubscribe(priority = EventPriority.HIGHEST)
public void onDimensionSave(WorldEvent.Save event)
{
ForgeChunkManager.saveWorld(event.world);
}
@ForgeSubscribe(priority = EventPriority.HIGHEST)
public void onDimensionUnload(WorldEvent.Unload event)
{
ForgeChunkManager.unloadWorld(event.world);
}
}
@@ -1,44 +0,0 @@
/**
* This software is provided under the terms of the Minecraft Forge Public
* License v1.0.
*/
package net.minecraftforge.common;
public class ForgeVersion
{
//This number is incremented every time we remove deprecated code/major API changes, never reset
public static final int majorVersion = 8;
//This number is incremented every minecraft release, never reset
public static final int minorVersion = 9;
//This number is incremented every time a interface changes or new major feature is added, and reset every Minecraft version
public static final int revisionVersion = 0;
//This number is incremented every time Jenkins builds Forge, and never reset. Should always be 0 in the repo code.
public static final int buildVersion = 0;
public static int getMajorVersion()
{
return majorVersion;
}
public static int getMinorVersion()
{
return minorVersion;
}
public static int getRevisionVersion()
{
return revisionVersion;
}
public static int getBuildVersion()
{
return buildVersion;
}
public static String getVersion()
{
return String.format("%d.%d.%d.%d", majorVersion, minorVersion, revisionVersion, buildVersion);
}
}
@@ -1,37 +0,0 @@
package net.minecraftforge.common;
import net.minecraft.entity.Entity;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.World;
/**
* Allows for custom entity data and logic to be hooked to existing entity classes.
*
* @author cpw, mithion
*
*/
public interface IExtendedEntityProperties {
/**
* Called when the entity that this class is attached to is saved.
* Any custom entity data that needs saving should be saved here.
* @param compound The compound to save to.
*/
public void saveNBTData(NBTTagCompound compound);
/**
* Called when the entity that this class is attached to is loaded.
* In order to hook into this, you will need to subscribe to the EntityConstructing event.
* Otherwise, you will need to initialize manually.
* @param compound The compound to load from.
*/
public void loadNBTData(NBTTagCompound compound);
/**
* Used to initialize the extended properties with the entity that this is attached to, as well
* as the world object.
* Called automatically if you register with the EntityConstructing event.
* @param entity The entity that this extended properties is attached to
* @param world The world in which the entity exists
*/
public void init(Entity entity, World world);
}
@@ -1,10 +0,0 @@
package net.minecraftforge.common;
import net.minecraft.world.World;
public interface IPlantable
{
public EnumPlantType getPlantType(World world, int x, int y, int z);
public int getPlantID(World world, int x, int y, int z);
public int getPlantMetadata(World world, int x, int y, int z);
}
@@ -1,53 +0,0 @@
package net.minecraftforge.common;
import java.util.ArrayList;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.world.World;
/**
*
* This allows for mods to create there own Shear-like items
* and have them interact with Blocks/Entities without extra work.
* Also, if your block/entity supports the Shears, this allows you
* to support mod-shears as well.
*
*/
public interface IShearable
{
/**
* Checks if the object is currently shearable
* Example: Sheep return false when they have no wool
*
* @param item The itemstack that is being used, Possible to be null
* @param world The current world
* @param x The X Position
* @param y The Y Position
* @param z The Z Position
* @return If this is shearable, and onSheared should be called.
*/
public boolean isShearable(ItemStack item, World world, int x, int y, int z);
/**
* Performs the shear function on this object.
* This is called for both client, and server.
* The object should perform all actions related to being sheared,
* except for dropping of the items.
*
* Returns a list of items that resulted from the shearing process.
*
* For entities, they should trust there internal location information
* over the values passed into this function.
*
* @param item The itemstack that is being used, Possible to be null
* @param world The current world
* @param x The X Position
* @param y The Y Position
* @param z The Z Position
* @param fortune The fortune level of the shears being used
* @return A ArrayList containing all items from this shearing. Possible to be null.
*/
public ArrayList<ItemStack> onSheared(ItemStack item, World world, int x, int y, int z, int fortune);
}
@@ -1,31 +0,0 @@
/**
* This software is provided under the terms of the Minecraft Forge Public
* License v1.0.
*/
package net.minecraftforge.common;
import net.minecraft.inventory.IInventory;
/** Inventory ranges mapped by side. This class is implemented by TileEntities
* that provide different inventory slot ranges to different sides.
*/
@Deprecated //A equivalent Interface is now in Minecraft Vanilla will be removed next major MC version
public interface ISidedInventory extends IInventory
{
/**
* Get the start of the side inventory.
* @param side The global side to get the start of range.
*/
@Deprecated
int getStartInventorySide(ForgeDirection side);
/**
* Get the size of the side inventory.
* @param side The global side.
*/
@Deprecated
int getSizeInventorySide(ForgeDirection side);
}
@@ -1,317 +0,0 @@
/**
* This software is provided under the terms of the Minecraft Forge Public
* License v1.0.
*/
package net.minecraftforge.common;
import java.util.ArrayList;
import java.util.Arrays;
import net.minecraft.util.DamageSource;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemArmor;
import net.minecraft.item.ItemStack;
/**
* This interface is to be implemented by ItemArmor classes. It will allow to
* modify computation of damage and health loss. Computation will be called
* before the actual armor computation, which can then be cancelled.
*
* @see ItemArmor
*/
public interface ISpecialArmor
{
/**
* Retrieves the modifiers to be used when calculating armor damage.
*
* Armor will higher priority will have damage applied to them before
* lower priority ones. If there are multiple pieces of armor with the
* same priority, damage will be distributed between them based on there
* absorption ratio.
*
* @param player The entity wearing the armor.
* @param armor The ItemStack of the armor item itself.
* @param source The source of the damage, which can be used to alter armor
* properties based on the type or source of damage.
* @param damage The total damage being applied to the entity
* @param slot The armor slot the item is in.
* @return A ArmorProperties instance holding information about how the armor effects damage.
*/
public ArmorProperties getProperties(EntityLivingBase player, ItemStack armor, DamageSource source, double damage, int slot);
/**
* Get the displayed effective armor.
*
* @param player The player wearing the armor.
* @param armor The ItemStack of the armor item itself.
* @param slot The armor slot the item is in.
* @return The number of armor points for display, 2 per shield.
*/
public abstract int getArmorDisplay(EntityPlayer player, ItemStack armor, int slot);
/**
* Applies damage to the ItemStack. The mod is responsible for reducing the
* item durability and stack size. If the stack is depleted it will be cleaned
* up automatically.
*
* @param entity The entity wearing the armor
* @param stack The ItemStack of the armor item itself.
* @param source The source of the damage, which can be used to alter armor
* properties based on the type or source of damage.
* @param damage The amount of damage being applied to the armor
* @param slot The armor slot the item is in.
*/
public abstract void damageArmor(EntityLivingBase entity, ItemStack stack, DamageSource source, int damage, int slot);
public static class ArmorProperties implements Comparable<ArmorProperties>
{
public int Priority = 0;
public int AbsorbMax = Integer.MAX_VALUE;
public double AbsorbRatio = 0;
public int Slot = 0;
private static final boolean DEBUG = false; //Only enable this if you wish to be spamed with debugging information.
//Left it in because I figured it'd be useful for modders developing custom armor.
public ArmorProperties(int priority, double ratio, int max)
{
Priority = priority;
AbsorbRatio = ratio;
AbsorbMax = max;
}
/**
* Gathers and applies armor reduction to damage being dealt to a entity.
*
* @param entity The Entity being damage
* @param inventory An array of armor items
* @param source The damage source type
* @param damage The total damage being done
* @return The left over damage that has not been absorbed by the armor
*/
public static float ApplyArmor(EntityLivingBase entity, ItemStack[] inventory, DamageSource source, double damage)
{
if (DEBUG)
{
System.out.println("Start: " + damage + " " + (damage * 25));
}
damage *= 25;
ArrayList<ArmorProperties> dmgVals = new ArrayList<ArmorProperties>();
for (int x = 0; x < inventory.length; x++)
{
ItemStack stack = inventory[x];
if (stack == null)
{
continue;
}
ArmorProperties prop = null;
if (stack.getItem() instanceof ISpecialArmor)
{
ISpecialArmor armor = (ISpecialArmor)stack.getItem();
prop = armor.getProperties(entity, stack, source, damage / 25D, x).copy();
}
else if (stack.getItem() instanceof ItemArmor && !source.isUnblockable())
{
ItemArmor armor = (ItemArmor)stack.getItem();
prop = new ArmorProperties(0, armor.damageReduceAmount / 25D, armor.getMaxDamage() + 1 - stack.getItemDamage());
}
if (prop != null)
{
prop.Slot = x;
dmgVals.add(prop);
}
}
if (dmgVals.size() > 0)
{
ArmorProperties[] props = dmgVals.toArray(new ArmorProperties[dmgVals.size()]);
StandardizeList(props, damage);
int level = props[0].Priority;
double ratio = 0;
for (ArmorProperties prop : props)
{
if (level != prop.Priority)
{
damage -= (damage * ratio);
ratio = 0;
level = prop.Priority;
}
ratio += prop.AbsorbRatio;
double absorb = damage * prop.AbsorbRatio;
if (absorb > 0)
{
ItemStack stack = inventory[prop.Slot];
int itemDamage = (int)(absorb / 25D < 1 ? 1 : absorb / 25D);
if (stack.getItem() instanceof ISpecialArmor)
{
((ISpecialArmor)stack.getItem()).damageArmor(entity, stack, source, itemDamage, prop.Slot);
}
else
{
if (DEBUG)
{
System.out.println("Item: " + stack.toString() + " Absorbed: " + (absorb / 25D) + " Damaged: " + itemDamage);
}
stack.damageItem(itemDamage, entity);
}
if (stack.stackSize <= 0)
{
/*if (entity instanceof EntityPlayer)
{
stack.onItemDestroyedByUse((EntityPlayer)entity);
}*/
inventory[prop.Slot] = null;
}
}
}
damage -= (damage * ratio);
}
if (DEBUG)
{
System.out.println("Return: " + (int)(damage / 25.0F) + " " + damage);
}
return (float)(damage / 25.0F);
}
/**
* Sorts and standardizes the distribution of damage over armor.
*
* @param armor The armor information
* @param damage The total damage being received
*/
private static void StandardizeList(ArmorProperties[] armor, double damage)
{
Arrays.sort(armor);
int start = 0;
double total = 0;
int priority = armor[0].Priority;
int pStart = 0;
boolean pChange = false;
boolean pFinished = false;
if (DEBUG)
{
for (ArmorProperties prop : armor)
{
System.out.println(prop);
}
System.out.println("========================");
}
for (int x = 0; x < armor.length; x++)
{
total += armor[x].AbsorbRatio;
if (x == armor.length - 1 || armor[x].Priority != priority)
{
if (armor[x].Priority != priority)
{
total -= armor[x].AbsorbRatio;
x--;
pChange = true;
}
if (total > 1)
{
for (int y = start; y <= x; y++)
{
double newRatio = armor[y].AbsorbRatio / total;
if (newRatio * damage > armor[y].AbsorbMax)
{
armor[y].AbsorbRatio = (double)armor[y].AbsorbMax / damage;
total = 0;
for (int z = pStart; z <= y; z++)
{
total += armor[z].AbsorbRatio;
}
start = y + 1;
x = y;
break;
}
else
{
armor[y].AbsorbRatio = newRatio;
pFinished = true;
}
}
if (pChange && pFinished)
{
damage -= (damage * total);
total = 0;
start = x + 1;
priority = armor[start].Priority;
pStart = start;
pChange = false;
pFinished = false;
if (damage <= 0)
{
for (int y = x + 1; y < armor.length; y++)
{
armor[y].AbsorbRatio = 0;
}
break;
}
}
}
else
{
for (int y = start; y <= x; y++)
{
total -= armor[y].AbsorbRatio;
if (damage * armor[y].AbsorbRatio > armor[y].AbsorbMax)
{
armor[y].AbsorbRatio = (double)armor[y].AbsorbMax / damage;
}
total += armor[y].AbsorbRatio;
}
damage -= (damage * total);
total = 0;
if (x != armor.length - 1)
{
start = x + 1;
priority = armor[start].Priority;
pStart = start;
pChange = false;
if (damage <= 0)
{
for (int y = x + 1; y < armor.length; y++)
{
armor[y].AbsorbRatio = 0;
}
break;
}
}
}
}
}
if (DEBUG)
{
for (ArmorProperties prop : armor)
{
System.out.println(prop);
}
}
}
public int compareTo(ArmorProperties o)
{
if (o.Priority != Priority)
{
return o.Priority - Priority;
}
double left = ( AbsorbRatio == 0 ? 0 : AbsorbMax * 100.0D / AbsorbRatio);
double right = (o.AbsorbRatio == 0 ? 0 : o.AbsorbMax * 100.0D / o.AbsorbRatio);
return (int)(left - right);
}
public String toString()
{
return String.format("%d, %d, %f, %d", Priority, AbsorbMax, AbsorbRatio, (AbsorbRatio == 0 ? 0 : (int)(AbsorbMax * 100.0D / AbsorbRatio)));
}
public ArmorProperties copy()
{
return new ArmorProperties(Priority, AbsorbRatio, AbsorbMax);
}
}
}
@@ -1,220 +0,0 @@
package net.minecraftforge.common;
import java.lang.reflect.Constructor;
import java.util.*;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.ModContainer;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.crash.CrashReport;
import net.minecraft.entity.monster.EntityEnderman;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraftforge.common.ForgeHooks.GrassEntry;
import net.minecraftforge.common.ForgeHooks.SeedEntry;
import net.minecraftforge.event.EventBus;
import net.minecraftforge.event.ForgeSubscribe;
import net.minecraftforge.event.entity.EntityEvent;
import net.minecraftforge.oredict.OreDictionary;
public class MinecraftForge
{
/**
* The core Forge EventBusses, all events for Forge will be fired on these,
* you should use this to register all your listeners.
* This replaces every register*Handler() function in the old version of Forge.
* TERRAIN_GEN_BUS for terrain gen events
* ORE_GEN_BUS for ore gen events
* EVENT_BUS for everything else
*/
public static final EventBus EVENT_BUS = new EventBus();
public static final EventBus TERRAIN_GEN_BUS = new EventBus();
public static final EventBus ORE_GEN_BUS = new EventBus();
private static final ForgeInternalHandler INTERNAL_HANDLER = new ForgeInternalHandler();
/** Register a new plant to be planted when bonemeal is used on grass.
* @param block The block to place.
* @param metadata The metadata to set for the block when being placed.
* @param weight The weight of the plant, where red flowers are
* 10 and yellow flowers are 20.
*/
public static void addGrassPlant(Block block, int metadata, int weight)
{
ForgeHooks.grassList.add(new GrassEntry(block, metadata, weight));
}
/**
* Register a new seed to be dropped when breaking tall grass.
*
* @param seed The item to drop as a seed.
* @param weight The relative probability of the seeds,
* where wheat seeds are 10.
*/
public static void addGrassSeed(ItemStack seed, int weight)
{
ForgeHooks.seedList.add(new SeedEntry(seed, weight));
}
/**
*
* Register a tool as a tool class with a given harvest level.
*
* @param tool The custom tool to register.
* @param toolClass The tool class to register as. The predefined tool
* clases are "pickaxe", "shovel", "axe". You can add
* others for custom tools.
* @param harvestLevel The harvest level of the tool.
*/
public static void setToolClass(Item tool, String toolClass, int harvestLevel)
{
ForgeHooks.toolClasses.put(tool, Arrays.asList(toolClass, harvestLevel));
}
/**
* Register a block to be harvested by a tool class. This is the metadata
* sensitive version, use it if your blocks are using metadata variants.
* By default, this sets the block class as effective against that type.
*
* @param block The block to register.
* @param metadata The metadata for the block subtype.
* @param toolClass The tool class to register as able to remove this block.
* You may register the same block multiple times with different tool
* classes, if multiple tool types can be used to harvest this block.
* @param harvestLevel The minimum tool harvest level required to successfully
* harvest the block.
* @see MinecraftForge#setToolClass for details on tool classes.
*/
public static void setBlockHarvestLevel(Block block, int metadata, String toolClass, int harvestLevel)
{
List key = Arrays.asList(block, metadata, toolClass);
ForgeHooks.toolHarvestLevels.put(key, harvestLevel);
ForgeHooks.toolEffectiveness.add(key);
}
/**
* Remove a block effectiveness mapping. Since setBlockHarvestLevel
* makes the tool class effective against the block by default, this can be
* used to remove that mapping. This will force a block to be harvested at
* the same speed regardless of tool quality, while still requiring a given
* harvesting level.
*
* @param block The block to remove effectiveness from.
* @param metadata The metadata for the block subtype.
* @param toolClass The tool class to remove the effectiveness mapping from.
* @see MinecraftForge#setToolClass for details on tool classes.
*/
public static void removeBlockEffectiveness(Block block, int metadata, String toolClass)
{
List key = Arrays.asList(block, metadata, toolClass);
ForgeHooks.toolEffectiveness.remove(key);
}
/**
* Register a block to be harvested by a tool class.
* By default, this sets the block class as effective against that type.
*
* @param block The block to register.
* @param toolClass The tool class to register as able to remove this block.
* You may register the same block multiple times with different tool
* classes, if multiple tool types can be used to harvest this block.
* @param harvestLevel The minimum tool harvest level required to successfully
* harvest the block.
* @see MinecraftForge#setToolClass for details on tool classes.
*/
public static void setBlockHarvestLevel(Block block, String toolClass, int harvestLevel)
{
for (int metadata = 0; metadata < 16; metadata++)
{
List key = Arrays.asList(block, metadata, toolClass);
ForgeHooks.toolHarvestLevels.put(key, harvestLevel);
ForgeHooks.toolEffectiveness.add(key);
}
}
/**
* Returns the block harvest level for a particular tool class.
*
* @param block The block to check.
* @param metadata The metadata for the block subtype.
* @param toolClass The tool class to check as able to remove this block.
* @see MinecraftForge#setToolClass for details on tool classes.
* @return The harvest level or -1 if no mapping exists.
*/
public static int getBlockHarvestLevel(Block block, int metadata, String toolClass)
{
ForgeHooks.initTools();
List key = Arrays.asList(block, metadata, toolClass);
Integer harvestLevel = ForgeHooks.toolHarvestLevels.get(key);
return (harvestLevel == null ? -1 : harvestLevel);
}
/**
* Remove a block effectiveness mapping. Since setBlockHarvestLevel
* makes the tool class effective against the block by default, this can be
* used to remove that mapping. This will force a block to be harvested at
* the same speed regardless of tool quality, while still requiring a given
* harvesting level.
*
* @param block The block to remove effectiveness from.
* @param toolClass The tool class to remove the effectiveness mapping from.
* @see MinecraftForge#setToolClass for details on tool classes.
*/
public static void removeBlockEffectiveness(Block block, String toolClass)
{
for (int metadata = 0; metadata < 16; metadata++)
{
List key = Arrays.asList(block, metadata, toolClass);
ForgeHooks.toolEffectiveness.remove(key);
}
}
/**
* Method invoked by FML before any other mods are loaded.
*/
public static void initialize()
{
System.out.printf("MinecraftForge v%s Initialized\n", ForgeVersion.getVersion());
FMLLog.info("MinecraftForge v%s Initialized", ForgeVersion.getVersion());
Block filler = new Block(0, Material.air)
{
@SideOnly(Side.CLIENT) public void func_94332_a(IconRegister register){}
};
Block.blocksList[0] = null;
Block.opaqueCubeLookup[0] = false;
Block.lightOpacity[0] = 0;
filler.setUnlocalizedName("ForgeFiller");
for (int x = 256; x < 4096; x++)
{
if (Item.itemsList[x] != null)
{
Block.blocksList[x] = filler;
}
}
boolean[] temp = new boolean[4096];
System.arraycopy(EntityEnderman.carriableBlocks, 0, temp, 0, EntityEnderman.carriableBlocks.length);
EntityEnderman.carriableBlocks = temp;
EVENT_BUS.register(INTERNAL_HANDLER);
OreDictionary.getOreName(0);
//Force these classes to be defined, Should prevent derp error hiding.
new CrashReport("ThisIsFake", new Exception("Not real"));
}
public static String getBrandingVersion()
{
return "Minecraft Forge "+ ForgeVersion.getVersion();
}
}
@@ -1,409 +0,0 @@
/**
* This software is provided under the terms of the Minecraft Forge Public
* License v1.0.
*/
package net.minecraftforge.common;
import java.util.ArrayList;
import net.minecraftforge.common.Property.Type;
public class Property
{
public enum Type
{
STRING,
INTEGER,
BOOLEAN,
DOUBLE;
private static Type[] values = {STRING, INTEGER, BOOLEAN, DOUBLE};
public static Type tryParse(char id)
{
for (int x = 0; x < values.length; x++)
{
if (values[x].getID() == id)
{
return values[x];
}
}
return STRING;
}
public char getID()
{
return name().charAt(0);
}
}
private String name;
private String value;
public String comment;
private String[] values;
private final boolean wasRead;
private final boolean isList;
private final Type type;
private boolean changed = false;
public Property()
{
wasRead = false;
type = null;
isList = false;
}
public Property(String name, String value, Type type)
{
this(name, value, type, false);
}
Property(String name, String value, Type type, boolean read)
{
setName(name);
this.value = value;
this.type = type;
wasRead = read;
isList = false;
}
public Property(String name, String[] values, Type type)
{
this(name, values, type, false);
}
Property(String name, String[] values, Type type, boolean read)
{
setName(name);
this.type = type;
this.values = values;
wasRead = read;
isList = true;
}
/**
* Returns the value in this property as it's raw string.
*
* @return current value
*/
public String getString()
{
return value;
}
/**
* Returns the value in this property as an integer,
* if the value is not a valid integer, it will return -1.
*
* @return The value
*/
public int getInt()
{
return getInt(-1);
}
/**
* Returns the value in this property as an integer,
* if the value is not a valid integer, it will return the
* provided default.
*
* @param _default The default to provide if the current value is not a valid integer
* @return The value
*/
public int getInt(int _default)
{
try
{
return Integer.parseInt(value);
}
catch (NumberFormatException e)
{
return _default;
}
}
/**
* Checks if the current value stored in this property can be converted to an integer.
* @return True if the type of the Property is an Integer
*/
public boolean isIntValue()
{
try
{
Integer.parseInt(value);
return true;
}
catch (NumberFormatException e)
{
return false;
}
}
/**
* Returns the value in this property as a boolean,
* if the value is not a valid boolean, it will return the
* provided default.
*
* @param _default The default to provide
* @return The value as a boolean, or the default
*/
public boolean getBoolean(boolean _default)
{
if (isBooleanValue())
{
return Boolean.parseBoolean(value);
}
else
{
return _default;
}
}
/**
* Checks if the current value held by this property is a valid boolean value.
* @return True if it is a boolean value
*/
public boolean isBooleanValue()
{
return ("true".equals(value.toLowerCase()) || "false".equals(value.toLowerCase()));
}
/**
* Checks if the current value held by this property is a valid double value.
* @return True if the value can be converted to an double
*/
public boolean isDoubleValue()
{
try
{
Double.parseDouble(value);
return true;
}
catch (NumberFormatException e)
{
return false;
}
}
/**
* Returns the value in this property as a double,
* if the value is not a valid double, it will return the
* provided default.
*
* @param _default The default to provide if the current value is not a valid double
* @return The value
*/
public double getDouble(double _default)
{
try
{
return Double.parseDouble(value);
}
catch (NumberFormatException e)
{
return _default;
}
}
public String[] getStringList()
{
return values;
}
/**
* Returns the integer value of all values that can
* be parsed in the list.
*
* @return Array of length 0 if none of the values could be parsed.
*/
public int[] getIntList()
{
ArrayList<Integer> nums = new ArrayList<Integer>();
for (String value : values)
{
try
{
nums.add(Integer.parseInt(value));
}
catch (NumberFormatException e){}
}
int[] primitives = new int[nums.size()];
for (int i = 0; i < nums.size(); i++)
{
primitives[i] = nums.get(i);
}
return primitives;
}
/**
* Checks if all of the current values stored in this property can be converted to an integer.
* @return True if the type of the Property is an Integer List
*/
public boolean isIntList()
{
for (String value : values)
{
try
{
Integer.parseInt(value);
}
catch (NumberFormatException e)
{
return false;
}
}
return true;
}
/**
* Returns the boolean value of all values that can
* be parsed in the list.
*
* @return Array of length 0 if none of the values could be parsed.
*/
public boolean[] getBooleanList()
{
ArrayList<Boolean> tmp = new ArrayList<Boolean>();
for (String value : values)
{
try
{
tmp.add(Boolean.parseBoolean(value));
}
catch (NumberFormatException e){}
}
boolean[] primitives = new boolean[tmp.size()];
for (int i = 0; i < tmp.size(); i++)
{
primitives[i] = tmp.get(i);
}
return primitives;
}
/**
* Checks if all of current values stored in this property can be converted to a boolean.
* @return True if it is a boolean value
*/
public boolean isBooleanList()
{
for (String value : values)
{
if (!"true".equalsIgnoreCase(value) && !"false".equalsIgnoreCase(value))
{
return false;
}
}
return true;
}
/**
* Returns the double value of all values that can
* be parsed in the list.
*
* @return Array of length 0 if none of the values could be parsed.
*/
public double[] getDoubleList()
{
ArrayList<Double> tmp = new ArrayList<Double>();
for (String value : values)
{
try
{
tmp.add(Double.parseDouble(value));
}
catch (NumberFormatException e) {}
}
double[] primitives = new double[tmp.size()];
for (int i = 0; i < tmp.size(); i++)
{
primitives[i] = tmp.get(i);
}
return primitives;
}
/**
* Checks if all of the current values stored in this property can be converted to a double.
* @return True if the type of the Property is a double List
*/
public boolean isDoubleList()
{
for (String value : values)
{
try
{
Double.parseDouble(value);
}
catch (NumberFormatException e)
{
return false;
}
}
return true;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
/**
* Determines if this config value was just created, or if it was read from the config file.
* This is useful for mods who auto-assign there blocks to determine if the ID returned is
* a configured one, or a automatically generated one.
*
* @return True if this property was loaded from the config file with a value
*/
public boolean wasRead()
{
return wasRead;
}
public Type getType()
{
return type;
}
public boolean isList()
{
return isList;
}
public boolean hasChanged(){ return changed; }
void resetChangedState(){ changed = false; }
public void set(String value)
{
this.value = value;
changed = true;
}
public void set(String[] values)
{
this.values = values;
changed = true;
}
public void set(int value){ set(Integer.toString(value)); }
public void set(boolean value){ set(Boolean.toString(value)); }
public void set(double value){ set(Double.toString(value)); }
}
@@ -1,47 +0,0 @@
package net.minecraftforge.common;
import net.minecraft.block.Block;
import net.minecraft.block.BlockChest;
import net.minecraft.block.BlockDispenser;
import net.minecraft.block.BlockDropper;
import net.minecraft.block.BlockPistonBase;
import net.minecraft.world.World;
import static net.minecraftforge.common.ForgeDirection.*;
public class RotationHelper {
private static final ForgeDirection[] UP_DOWN_AXES = new ForgeDirection[] { UP, DOWN };
public static ForgeDirection[] getValidVanillaBlockRotations(Block block)
{
return block instanceof BlockChest ? UP_DOWN_AXES : VALID_DIRECTIONS;
}
public static boolean rotateVanillaBlock(Block block, World worldObj, int x, int y, int z, ForgeDirection axis)
{
if (worldObj.isRemote)
{
return false;
}
if (block instanceof BlockChest && (axis == UP || axis == DOWN))
{
return rotateBlock(worldObj, x, y, z, axis, 0x7);
}
if (block instanceof BlockPistonBase || block instanceof BlockDropper || block instanceof BlockDispenser)
{
return rotateBlock(worldObj, x, y, z, axis, 0x7);
}
return false;
}
private static boolean rotateBlock(World worldObj, int x, int y, int z, ForgeDirection axis, int mask)
{
int rotMeta = worldObj.getBlockMetadata(x, y, z);
int masked = rotMeta & ~mask;
ForgeDirection orientation = ForgeDirection.getOrientation(rotMeta & mask);
ForgeDirection rotated = orientation.getRotation(axis);
worldObj.setBlockMetadataWithNotify(x,y,z,rotated.ordinal() & mask | masked,3);
return true;
}
}
@@ -1,44 +0,0 @@
package net.minecraftforge.common;
import java.io.File;
import net.minecraft.world.chunk.storage.IChunkLoader;
import net.minecraft.world.storage.IPlayerFileData;
import net.minecraft.world.storage.ISaveHandler;
import net.minecraft.world.MinecraftException;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.storage.WorldInfo;
import net.minecraft.world.WorldProvider;
import net.minecraft.world.WorldServer;
//Class used internally to provide the world specific data directories.
public class WorldSpecificSaveHandler implements ISaveHandler
{
private WorldServer world;
private ISaveHandler parent;
private File dataDir;
public WorldSpecificSaveHandler(WorldServer world, ISaveHandler parent)
{
this.world = world;
this.parent = parent;
dataDir = new File(world.getChunkSaveLocation(), "data");
dataDir.mkdirs();
}
@Override public WorldInfo loadWorldInfo() { return parent.loadWorldInfo(); }
@Override public void checkSessionLock() throws MinecraftException { parent.checkSessionLock(); }
@Override public IChunkLoader getChunkLoader(WorldProvider var1) { return parent.getChunkLoader(var1); }
@Override public void saveWorldInfoWithPlayer(WorldInfo var1, NBTTagCompound var2) { parent.saveWorldInfoWithPlayer(var1, var2); }
@Override public void saveWorldInfo(WorldInfo var1){ parent.saveWorldInfo(var1); }
@Override public IPlayerFileData getSaveHandler() { return parent.getSaveHandler(); }
@Override public void flush() { parent.flush(); }
@Override public String getWorldDirectoryName() { return parent.getWorldDirectoryName(); }
@Override
public File getMapFileFromName(String name)
{
return new File(dataDir, name + ".dat");
}
}
@@ -1,49 +0,0 @@
package net.minecraftforge.common.network;
import net.minecraft.network.INetworkManager;
import net.minecraft.network.NetLoginHandler;
import net.minecraft.network.packet.NetHandler;
import net.minecraft.network.packet.Packet1Login;
import net.minecraft.server.MinecraftServer;
import cpw.mods.fml.common.network.IConnectionHandler;
import cpw.mods.fml.common.network.Player;
public class ForgeConnectionHandler implements IConnectionHandler {
@Override
public void playerLoggedIn(Player player, NetHandler netHandler, INetworkManager manager)
{
}
@Override
public String connectionReceived(NetLoginHandler netHandler, INetworkManager manager)
{
return null;
}
@Override
public void connectionOpened(NetHandler netClientHandler, String server, int port, INetworkManager manager)
{
}
@Override
public void connectionOpened(NetHandler netClientHandler, MinecraftServer server, INetworkManager manager)
{
}
@Override
public void connectionClosed(INetworkManager manager)
{
}
@Override
public void clientLoggedIn(NetHandler clientHandler, INetworkManager manager, Packet1Login login)
{
}
}
@@ -1,20 +0,0 @@
package net.minecraftforge.common.network;
import net.minecraftforge.common.ForgeDummyContainer;
import cpw.mods.fml.common.network.NetworkMod;
import cpw.mods.fml.common.network.NetworkModHandler;
public class ForgeNetworkHandler extends NetworkModHandler
{
public ForgeNetworkHandler(ForgeDummyContainer container)
{
super(container,container.getClass().getAnnotation(NetworkMod.class));
configureNetworkMod(container);
}
@Override
public boolean acceptVersion(String version)
{
return true;
}
}
@@ -1,187 +0,0 @@
package net.minecraftforge.common.network;
import java.util.Arrays;
import java.util.concurrent.ConcurrentMap;
import java.util.logging.Level;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.network.INetworkManager;
import net.minecraft.network.packet.NetHandler;
import net.minecraft.network.packet.Packet250CustomPayload;
import net.minecraftforge.common.network.packet.DimensionRegisterPacket;
import com.google.common.base.Throwables;
import com.google.common.collect.MapMaker;
import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteStreams;
import com.google.common.primitives.Bytes;
import com.google.common.primitives.Ints;
import com.google.common.primitives.UnsignedBytes;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.network.FMLNetworkException;
public abstract class ForgePacket
{
public static final String CHANNEL_ID = "FORGE";
enum Type
{
/**
* Registers a dimension for a provider on client
*/
REGISTERDIMENSION(DimensionRegisterPacket.class);
private Class<? extends ForgePacket> packetType;
private ConcurrentMap<INetworkManager, ForgePacket> partTracker;
private Type(Class<? extends ForgePacket> clazz)
{
this.packetType = clazz;
}
ForgePacket make()
{
try
{
return this.packetType.newInstance();
}
catch (Exception e)
{
Throwables.propagateIfPossible(e);
FMLLog.log(Level.SEVERE, e, "A bizarre critical error occured during packet encoding");
throw new FMLNetworkException(e);
}
}
private ForgePacket consumePart(INetworkManager network, byte[] data)
{
if (partTracker == null)
{
partTracker = new MapMaker().weakKeys().weakValues().makeMap();
}
if (!partTracker.containsKey(network))
{
partTracker.put(network, make());
}
ForgePacket pkt = partTracker.get(network);
ByteArrayDataInput bdi = ByteStreams.newDataInput(data);
int chunkIdx = UnsignedBytes.toInt(bdi.readByte());
int chunkTotal = UnsignedBytes.toInt(bdi.readByte());
int chunkLength = bdi.readInt();
if (pkt.partials == null)
{
pkt.partials = new byte[chunkTotal][];
}
pkt.partials[chunkIdx] = new byte[chunkLength];
bdi.readFully(pkt.partials[chunkIdx]);
for (int i = 0; i < pkt.partials.length; i++)
{
if (pkt.partials[i] == null)
{
return null;
}
}
return pkt;
}
}
private Type type;
private byte[][] partials;
public static Packet250CustomPayload[] makePacketSet(ForgePacket packet)
{
byte[] packetData = packet.generatePacket();
if (packetData.length < 32000)
{
return new Packet250CustomPayload[]
{
new Packet250CustomPayload(CHANNEL_ID,
Bytes.concat(new byte[]
{
UnsignedBytes.checkedCast(0), //IsMultipart: False
UnsignedBytes.checkedCast(packet.getID())
},
packetData))
};
}
else
{
byte[][] chunks = new byte[packetData.length / 32000 + 1][];
for (int i = 0; i < packetData.length / 32000 + 1; i++)
{
int len = Math.min(32000, packetData.length - i* 32000);
chunks[i] = Bytes.concat(new byte[]
{
UnsignedBytes.checkedCast(1), //IsMultipart: True
UnsignedBytes.checkedCast(packet.getID()), //Packet ID
UnsignedBytes.checkedCast(i), //Part Number
UnsignedBytes.checkedCast(chunks.length), //Total Parts
},
Ints.toByteArray(len), //Length
Arrays.copyOfRange(packetData, i * 32000, len + i * 32000));
}
Packet250CustomPayload[] ret = new Packet250CustomPayload[chunks.length];
for (int i = 0; i < chunks.length; i++)
{
ret[i] = new Packet250CustomPayload(CHANNEL_ID, chunks[i]);
}
return ret;
}
}
public static ForgePacket readPacket(INetworkManager network, byte[] payload)
{
boolean multipart = UnsignedBytes.toInt(payload[0]) == 1;
int type = UnsignedBytes.toInt(payload[1]);
Type eType = Type.values()[type];
byte[] data = Arrays.copyOfRange(payload, 2, payload.length);
if (multipart)
{
ForgePacket pkt = eType.consumePart(network, data);
if (pkt != null)
{
return pkt.consumePacket(Bytes.concat(pkt.partials));
}
return null;
}
else
{
return eType.make().consumePacket(data);
}
}
public ForgePacket()
{
for (Type t : Type.values())
{
if (t.packetType == getClass())
{
type = t;
continue;
}
}
if (type == null)
{
throw new RuntimeException("ForgePacket constructor called on ungregistered type.");
}
}
public byte getID()
{
return UnsignedBytes.checkedCast(type.ordinal());
}
public abstract byte[] generatePacket();
public abstract ForgePacket consumePacket(byte[] data);
public abstract void execute(INetworkManager network, EntityPlayer player);
}
@@ -1,26 +0,0 @@
package net.minecraftforge.common.network;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.network.INetworkManager;
import net.minecraft.network.NetLoginHandler;
import net.minecraft.network.packet.Packet250CustomPayload;
import cpw.mods.fml.common.network.FMLPacket;
import cpw.mods.fml.common.network.IPacketHandler;
import cpw.mods.fml.common.network.Player;
public class ForgePacketHandler implements IPacketHandler {
@Override
public void onPacketData(INetworkManager network, Packet250CustomPayload packet, Player player)
{
ForgePacket pkt = ForgePacket.readPacket(network, packet.data);
// Part of an incomplete multipart packet
if (pkt == null)
{
return;
}
pkt.execute(network, (EntityPlayer)player);
}
}
@@ -1,15 +0,0 @@
package net.minecraftforge.common.network;
import net.minecraft.network.packet.NetHandler;
import net.minecraft.network.packet.Packet131MapData;
import cpw.mods.fml.common.network.ITinyPacketHandler;
public class ForgeTinyPacketHandler implements ITinyPacketHandler {
@Override
public void handle(NetHandler handler, Packet131MapData mapData)
{
}
}
@@ -1,69 +0,0 @@
/**
* This software is provided under the terms of the Minecraft Forge Public
* License v1.0.
*/
package net.minecraftforge.common.network.packet;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.network.INetworkManager;
import net.minecraft.network.packet.NetHandler;
import net.minecraftforge.common.DimensionManager;
import net.minecraftforge.common.network.ForgePacket;
import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
/**
* This class offers the ability for servers to register dimensions on client.
*/
public class DimensionRegisterPacket extends ForgePacket
{
/** The dimension ID to register on client */
public int dimensionId;
/** The provider ID to register with dimension on client */
public int providerId;
// nullary constructor required by ForgePacket.make()
public DimensionRegisterPacket() {}
public DimensionRegisterPacket(int dimensionId, int providerId)
{
this.dimensionId = dimensionId;
this.providerId = providerId;
}
@Override
public byte[] generatePacket()
{
ByteArrayDataOutput dat = ByteStreams.newDataOutput();
dat.writeInt(this.dimensionId);
dat.writeInt(this.providerId);
return dat.toByteArray();
}
@Override
public ForgePacket consumePacket(byte[] data)
{
ByteArrayDataInput dat = ByteStreams.newDataInput(data);
dimensionId = dat.readInt();
providerId = dat.readInt();
return this;
}
@Override
public void execute(INetworkManager network, EntityPlayer player)
{
if (!(player instanceof EntityPlayerMP))
{
if (!DimensionManager.isDimensionRegistered(dimensionId))
{
DimensionManager.registerDimension(dimensionId, providerId);
}
}
}
}
@@ -1,130 +0,0 @@
package net.minecraftforge.event;
import static org.objectweb.asm.Opcodes.*;
import java.lang.reflect.Method;
import java.util.HashMap;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type;
import com.google.common.collect.Maps;
public class ASMEventHandler implements IEventListener
{
private static int IDs = 0;
private static final String HANDLER_DESC = Type.getInternalName(IEventListener.class);
private static final String HANDLER_FUNC_DESC = Type.getMethodDescriptor(IEventListener.class.getDeclaredMethods()[0]);
private static final ASMClassLoader LOADER = new ASMClassLoader();
private static final HashMap<Method, Class<?>> cache = Maps.newHashMap();
private final IEventListener handler;
private final ForgeSubscribe subInfo;
public ASMEventHandler(Object target, Method method) throws Exception
{
handler = (IEventListener)createWrapper(method).getConstructor(Object.class).newInstance(target);
subInfo = method.getAnnotation(ForgeSubscribe.class);
}
@Override
public void invoke(Event event)
{
if (handler != null)
{
if (!event.isCancelable() || !event.isCanceled() || subInfo.receiveCanceled())
{
handler.invoke(event);
}
}
}
public EventPriority getPriority()
{
return subInfo.priority();
}
public Class<?> createWrapper(Method callback)
{
if (cache.containsKey(callback))
{
return cache.get(callback);
}
ClassWriter cw = new ClassWriter(0);
MethodVisitor mv;
String name = getUniqueName(callback);
String desc = name.replace('.', '/');
String instType = Type.getInternalName(callback.getDeclaringClass());
String eventType = Type.getInternalName(callback.getParameterTypes()[0]);
/*
System.out.println("Name: " + name);
System.out.println("Desc: " + desc);
System.out.println("InstType: " + instType);
System.out.println("Callback: " + callback.getName() + Type.getMethodDescriptor(callback));
System.out.println("Event: " + eventType);
*/
cw.visit(V1_6, ACC_PUBLIC | ACC_SUPER, desc, null, "java/lang/Object", new String[]{ HANDLER_DESC });
cw.visitSource(".dynamic", null);
{
cw.visitField(ACC_PUBLIC, "instance", "Ljava/lang/Object;", null, null).visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "(Ljava/lang/Object;)V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitFieldInsn(PUTFIELD, desc, "instance", "Ljava/lang/Object;");
mv.visitInsn(RETURN);
mv.visitMaxs(2, 2);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC, "invoke", HANDLER_FUNC_DESC, null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, desc, "instance", "Ljava/lang/Object;");
mv.visitTypeInsn(CHECKCAST, instType);
mv.visitVarInsn(ALOAD, 1);
mv.visitTypeInsn(CHECKCAST, eventType);
mv.visitMethodInsn(INVOKEVIRTUAL, instType, callback.getName(), Type.getMethodDescriptor(callback));
mv.visitInsn(RETURN);
mv.visitMaxs(2, 2);
mv.visitEnd();
}
cw.visitEnd();
Class<?> ret = LOADER.define(name, cw.toByteArray());
cache.put(callback, ret);
return ret;
}
private String getUniqueName(Method callback)
{
return String.format("%s_%d_%s_%s_%s", getClass().getName(), IDs++,
callback.getDeclaringClass().getSimpleName(),
callback.getName(),
callback.getParameterTypes()[0].getSimpleName());
}
private static class ASMClassLoader extends ClassLoader
{
private ASMClassLoader()
{
super(ASMClassLoader.class.getClassLoader());
}
public Class<?> define(String name, byte[] data)
{
return defineClass(name, data, 0, data.length);
}
}
}
@@ -1,11 +0,0 @@
package net.minecraftforge.event;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Retention(value = RUNTIME)
@Target(value = TYPE)
public @interface Cancelable{}
@@ -1,21 +0,0 @@
package net.minecraftforge.event;
import net.minecraft.command.ICommand;
import net.minecraft.command.ICommandSender;
@Cancelable
public class CommandEvent extends Event
{
public final ICommand command;
public final ICommandSender sender;
public String[] parameters;
public Throwable exception;
public CommandEvent(ICommand command, ICommandSender sender, String[] parameters)
{
this.command = command;
this.sender = sender;
this.parameters = parameters;
}
}
-155
View File
@@ -1,155 +0,0 @@
package net.minecraftforge.event;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Base Event class that all other events are derived from
*/
public class Event
{
@Retention(value = RUNTIME)
@Target(value = TYPE)
public @interface HasResult{}
public enum Result
{
DENY,
DEFAULT,
ALLOW
}
private boolean isCanceled = false;
private final boolean isCancelable;
private Result result = Result.DEFAULT;
private final boolean hasResult;
private static ListenerList listeners = new ListenerList();
private static final Map<Class, Map<Class, Boolean>> annotationMap = new ConcurrentHashMap<Class, Map<Class, Boolean>>();
public Event()
{
setup();
isCancelable = hasAnnotation(Cancelable.class);
hasResult = hasAnnotation(HasResult.class);
}
private boolean hasAnnotation(Class annotation)
{
Class me = this.getClass();
Map<Class, Boolean> list = annotationMap.get(me);
if (list == null)
{
list = new ConcurrentHashMap<Class, Boolean>();
annotationMap.put(me, list);
}
Boolean cached = list.get(annotation);
if (cached != null)
{
return cached;
}
Class cls = me;
while (cls != Event.class)
{
if (cls.isAnnotationPresent(annotation))
{
list.put(annotation, true);
return true;
}
cls = cls.getSuperclass();
}
list.put(annotation, false);
return false;
}
/**
* Determine if this function is cancelable at all.
* @return If access to setCanceled should be allowed
*/
public boolean isCancelable()
{
return isCancelable;
}
/**
* Determine if this event is canceled and should stop executing.
* @return The current canceled state
*/
public boolean isCanceled()
{
return isCanceled;
}
/**
* Sets the state of this event, not all events are cancelable, and any attempt to
* cancel a event that can't be will result in a IllegalArgumentException.
*
* The functionality of setting the canceled state is defined on a per-event bases.
*
* @param cancel The new canceled value
*/
public void setCanceled(boolean cancel)
{
if (!isCancelable())
{
throw new IllegalArgumentException("Attempted to cancel a uncancelable event");
}
isCanceled = cancel;
}
/**
* Determines if this event expects a significant result value.
*/
public boolean hasResult()
{
return hasResult;
}
/**
* Returns the value set as the result of this event
*/
public Result getResult()
{
return result;
}
/**
* Sets the result value for this event, not all events can have a result set, and any attempt to
* set a result for a event that isn't expecting it will result in a IllegalArgumentException.
*
* The functionality of setting the result is defined on a per-event bases.
*
* @param value The new result
*/
public void setResult(Result value)
{
result = value;
}
/**
* Called by the base constructor, this is used by ASM generated
* event classes to setup various functionality such as the listener's list.
*/
protected void setup()
{
}
/**
* Returns a ListenerList object that contains all listeners
* that are registered to this event.
*
* @return Listener List
*/
public ListenerList getListenerList()
{
return listeners;
}
}
@@ -1,112 +0,0 @@
package net.minecraftforge.event;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import com.google.common.reflect.TypeToken;
public class EventBus
{
private static int maxID = 0;
private ConcurrentHashMap<Object, ArrayList<IEventListener>> listeners = new ConcurrentHashMap<Object, ArrayList<IEventListener>>();
private final int busID = maxID++;
public EventBus()
{
ListenerList.resize(busID + 1);
}
public void register(Object target)
{
if (listeners.containsKey(target))
{
return;
}
Set<? extends Class<?>> supers = TypeToken.of(target.getClass()).getTypes().rawTypes();
for (Method method : target.getClass().getMethods())
{
for (Class<?> cls : supers)
{
try
{
Method real = cls.getDeclaredMethod(method.getName(), method.getParameterTypes());
if (real.isAnnotationPresent(ForgeSubscribe.class))
{
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length != 1)
{
throw new IllegalArgumentException(
"Method " + method + " has @ForgeSubscribe annotation, but requires " + parameterTypes.length +
" arguments. Event handler methods must require a single argument."
);
}
Class<?> eventType = parameterTypes[0];
if (!Event.class.isAssignableFrom(eventType))
{
throw new IllegalArgumentException("Method " + method + " has @ForgeSubscribe annotation, but takes a argument that is not a Event " + eventType);
}
register(eventType, target, method);
break;
}
}
catch (NoSuchMethodException e)
{
;
}
}
}
}
private void register(Class<?> eventType, Object target, Method method)
{
try
{
Constructor<?> ctr = eventType.getConstructor();
ctr.setAccessible(true);
Event event = (Event)ctr.newInstance();
ASMEventHandler listener = new ASMEventHandler(target, method);
event.getListenerList().register(busID, listener.getPriority(), listener);
ArrayList<IEventListener> others = listeners.get(target);
if (others == null)
{
others = new ArrayList<IEventListener>();
listeners.put(target, others);
}
others.add(listener);
}
catch (Exception e)
{
e.printStackTrace();
}
}
public void unregister(Object object)
{
ArrayList<IEventListener> list = listeners.remove(object);
for (IEventListener listener : list)
{
ListenerList.unregiterAll(busID, listener);
}
}
public boolean post(Event event)
{
IEventListener[] listeners = event.getListenerList().getListeners(busID);
for (IEventListener listener : listeners)
{
listener.invoke(event);
}
return (event.isCancelable() ? event.isCanceled() : false);
}
}
@@ -1,16 +0,0 @@
package net.minecraftforge.event;
public enum EventPriority
{
/*Priority of event listeners, listeners will be sorted with respect to this priority level.
*
* Note:
* Due to using a ArrayList in the ListenerList,
* these need to stay in a contiguous index starting at 0. {Default ordinal}
*/
HIGHEST, //First to execute
HIGH,
NORMAL,
LOW,
LOWEST //Last to execute
}
@@ -1,78 +0,0 @@
package net.minecraftforge.event;
import java.util.List;
import net.minecraft.block.Block;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EnumCreatureType;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.Event.Result;
import net.minecraftforge.event.entity.living.LivingPackSizeEvent;
import net.minecraftforge.event.entity.living.LivingSpawnEvent;
import net.minecraftforge.event.entity.player.PlayerDestroyItemEvent;
import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.event.entity.player.PlayerInteractEvent.Action;
import net.minecraftforge.event.world.WorldEvent;
@SuppressWarnings("deprecation")
public class ForgeEventFactory
{
public static boolean doPlayerHarvestCheck(EntityPlayer player, Block block, boolean success)
{
PlayerEvent.HarvestCheck event = new PlayerEvent.HarvestCheck(player, block, success);
MinecraftForge.EVENT_BUS.post(event);
return event.success;
}
public static float getBreakSpeed(EntityPlayer player, Block block, int metadata, float original)
{
PlayerEvent.BreakSpeed event = new PlayerEvent.BreakSpeed(player, block, metadata, original);
return (MinecraftForge.EVENT_BUS.post(event) ? -1 : event.newSpeed);
}
public static PlayerInteractEvent onPlayerInteract(EntityPlayer player, Action action, int x, int y, int z, int face)
{
PlayerInteractEvent event = new PlayerInteractEvent(player, action, x, y, z, face);
MinecraftForge.EVENT_BUS.post(event);
return event;
}
public static void onPlayerDestroyItem(EntityPlayer player, ItemStack stack)
{
MinecraftForge.EVENT_BUS.post(new PlayerDestroyItemEvent(player, stack));
}
public static Result canEntitySpawn(EntityLiving entity, World world, float x, float y, float z)
{
LivingSpawnEvent.CheckSpawn event = new LivingSpawnEvent.CheckSpawn(entity, world, x, y, z);
MinecraftForge.EVENT_BUS.post(event);
return event.getResult();
}
public static boolean doSpecialSpawn(EntityLiving entity, World world, float x, float y, float z)
{
return MinecraftForge.EVENT_BUS.post(new LivingSpawnEvent.SpecialSpawn(entity, world, x, y, z));
}
public static List getPotentialSpawns(WorldServer world, EnumCreatureType type, int x, int y, int z, List oldList)
{
WorldEvent.PotentialSpawns event = new WorldEvent.PotentialSpawns(world, type, x, y, z, oldList);
if (MinecraftForge.EVENT_BUS.post(event))
{
return null;
}
return event.list;
}
public static int getMaxSpawnPackSize(EntityLiving entity)
{
LivingPackSizeEvent maxCanSpawnEvent = new LivingPackSizeEvent(entity);
MinecraftForge.EVENT_BUS.post(maxCanSpawnEvent);
return maxCanSpawnEvent.getResult() == Result.ALLOW ? maxCanSpawnEvent.maxPackSize : entity.getMaxSpawnedInChunk();
}
}
@@ -1,15 +0,0 @@
package net.minecraftforge.event;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.RetentionPolicy.*;
import static java.lang.annotation.ElementType.*;
@Retention(value = RUNTIME)
@Target(value = METHOD)
public @interface ForgeSubscribe
{
public EventPriority priority() default EventPriority.NORMAL;
public boolean receiveCanceled() default false;
}
@@ -1,8 +0,0 @@
package net.minecraftforge.event;
public interface IEventListener
{
public void invoke(Event event);
}
Loaded 100 of 565 files, more files were not shown because too many files have changed in this diff. Show more