├── .gitignore
├── LICENSE
├── README.md
├── build.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── src
├── api
└── java
│ └── dan200
│ └── computercraft
│ └── api
│ ├── ComputerCraftAPI.java
│ ├── filesystem
│ ├── IMount.java
│ └── IWritableMount.java
│ ├── lua
│ ├── ILuaContext.java
│ ├── ILuaObject.java
│ └── LuaException.java
│ ├── media
│ ├── IMedia.java
│ └── IMediaProvider.java
│ ├── peripheral
│ ├── IComputerAccess.java
│ ├── IPeripheral.java
│ └── IPeripheralProvider.java
│ ├── redstone
│ └── IBundledRedstoneProvider.java
│ └── turtle
│ ├── ITurtleAccess.java
│ ├── ITurtleCommand.java
│ ├── ITurtleUpgrade.java
│ ├── TurtleAnimation.java
│ ├── TurtleCommandResult.java
│ ├── TurtleSide.java
│ ├── TurtleUpgradeType.java
│ └── TurtleVerb.java
└── main
├── java
└── pcl
│ └── OpenFM
│ ├── Block
│ ├── BlockRadio.java
│ └── BlockSpeaker.java
│ ├── BuildInfo.java
│ ├── ClientProxy.java
│ ├── CommonProxy.java
│ ├── ConnectionHandler.java
│ ├── ContentRegistry.java
│ ├── GUI
│ ├── GuiRadio.java
│ ├── GuiRadioBase.java
│ ├── OFMConfigGUI.java
│ ├── OFMGuiButton.java
│ ├── OFMGuiFactory.java
│ ├── OFMGuiHandler.java
│ └── OFMGuiTextField.java
│ ├── Handler
│ ├── CardSlot.java
│ ├── ChatMessage.java
│ ├── ClientEvent.java
│ ├── OFMBreakEvent.java
│ └── ServerEvent.java
│ ├── Items
│ ├── ItemBlockRadio.java
│ ├── ItemMemoryCard.java
│ └── ItemTuner.java
│ ├── OFMConfiguration.java
│ ├── OpenFM.java
│ ├── TileEntity
│ ├── MemoryCardSlot.java
│ ├── RadioContainer.java
│ ├── RadioRenderer.java
│ ├── TileEntityRadio.java
│ └── TileEntitySpeaker.java
│ ├── misc
│ ├── DepLoader.java
│ ├── FileUtils.java
│ └── Speaker.java
│ ├── network
│ ├── MessageRadioBase.java
│ ├── PacketHandler.java
│ ├── RadioBlockMessageHandler.java
│ └── message
│ │ ├── BaseRadioMessage.java
│ │ ├── MessageRadioAddSpeaker.java
│ │ ├── MessageRadioAddStation.java
│ │ ├── MessageRadioDelStation.java
│ │ ├── MessageRadioLocked.java
│ │ ├── MessageRadioPlaying.java
│ │ ├── MessageRadioReadCard.java
│ │ ├── MessageRadioRedstone.java
│ │ ├── MessageRadioScreenColor.java
│ │ ├── MessageRadioScreenText.java
│ │ ├── MessageRadioStreamURL.java
│ │ ├── MessageRadioSync.java
│ │ ├── MessageRadioVolume.java
│ │ └── MessageRadioWriteCard.java
│ └── player
│ ├── AudioPlayer.java
│ ├── MarkErrorInputStream.java
│ ├── PlayBackEvent.java
│ ├── PlaybackListener.java
│ └── PlayerDispatcher.java
└── resources
├── assets
└── openfm
│ ├── deps
│ ├── jaad-0.8.5.jar
│ ├── mp3spi-1.9.5-1.jar
│ └── vorbisspi-1.0.3-1.jar
│ ├── lang
│ ├── en_US.lang
│ ├── ru_RU.lang
│ ├── zh_CN.lang
│ └── zh_TW.lang
│ └── textures
│ ├── blocks
│ ├── radio_front.png
│ ├── radio_side.png
│ ├── speaker_rear.png
│ └── speaker_side.png
│ ├── gui
│ ├── buttons.png
│ └── gui_radio.png
│ └── items
│ ├── ItemMemoryCard.png
│ └── ItemTuner.png
└── mcmod.info
/.gitignore:
--------------------------------------------------------------------------------
1 | #################
2 | ## Eclipse
3 | #################
4 |
5 | *.pydevproject
6 | .project
7 | .metadata
8 | *.tmp
9 | *.bak
10 | *.swp
11 | *~.nib
12 | local.properties
13 | .classpath
14 | .settings/
15 | .loadpath
16 |
17 | # External tool builders
18 | .externalToolBuilders/
19 |
20 | # Locally stored "Eclipse launch configurations"
21 | *.launch
22 |
23 | # CDT-specific
24 | .cproject
25 |
26 | # PDT-specific
27 | .buildpath
28 |
29 | #############
30 | ## Windows detritus
31 | #############
32 |
33 | # Windows image file caches
34 | Thumbs.db
35 | ehthumbs.db
36 |
37 | # Folder config file
38 | Desktop.ini
39 |
40 | # Recycle Bin used on file shares
41 | $RECYCLE.BIN/
42 |
43 | # Mac crap
44 | .DS_Store
45 |
46 |
47 | #############
48 | ## Python
49 | #############
50 |
51 | *.py[co]
52 |
53 | # Packages
54 | *.egg
55 | *.egg-info
56 | dist/
57 | build/
58 | eggs/
59 | parts/
60 | var/
61 | sdist/
62 | develop-eggs/
63 | .installed.cfg
64 |
65 | # Installer logs
66 | pip-log.txt
67 |
68 | # Unit test / coverage reports
69 | .coverage
70 | .tox
71 |
72 | #Translations
73 | *.mo
74 |
75 | #Mr Developer
76 | .mr.developer.cfg
77 |
78 | # Gradle
79 | /.gradle/
80 | /build/
81 | /run/
82 | /run_client/
83 | /run_server/
84 | /eclipse/
85 | /runtime/
86 | /server_runtime/
87 | *~
88 | *.lnk
89 | output.txt
90 | /bin
91 |
92 | #############
93 | ## IntelliJ IDEA project files
94 | #############
95 |
96 | *.iml
97 | *.ipr
98 | *.iws
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Caitlyn
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # OpenFM
2 |
3 | Streaming radio for Minecraft, with OpenComputers, and ComputerCraft support.
4 |
5 | fm = component.openfm_radio
6 |
7 | fm.setURL("http://listen.radionomy.com/DeepHouse")
8 |
9 | fm.start()
10 |
11 | fm.stop()
12 |
13 | fm.volUp()
14 |
15 | fm.volDown()
16 |
17 | fm.getVol()
18 |
19 | fm.setScreenColor(0xFF0000) Sets the text color to red on the display
20 |
21 | fm.setScreenText("Text to display on radio") Text will scroll if larger than the display.
22 |
23 |
24 | Highly modified version of Dragon's Radio Mod, Dragon's Radio Mod is Licenses MIT.
25 |
26 | Downloads via Curse http://www.curse.com/mc-mods/Minecraft/236839-openfm
27 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | mavenCentral()
4 | maven {
5 | name = "forge"
6 | url = "http://files.minecraftforge.net/maven"
7 | }
8 | maven {
9 | name = "sonatype"
10 | url = "https://oss.sonatype.org/content/repositories/snapshots/"
11 | }
12 | }
13 | dependencies {
14 | classpath 'net.minecraftforge.gradle:ForgeGradle:1.2-SNAPSHOT'
15 | }
16 | }
17 |
18 | apply plugin: 'forge'
19 | apply plugin: 'maven'
20 |
21 | sourceCompatibility = 1.7
22 | targetCompatibility = 1.7
23 |
24 | repositories {
25 | mavenCentral()
26 | maven {
27 | name = "OC repo"
28 | url = "http://maven.cil.li/"
29 | }
30 | }
31 |
32 | configurations {
33 | shade
34 | compile.extendsFrom shade
35 | }
36 |
37 |
38 | dependencies {
39 | compile "li.cil.oc:OpenComputers:MC1.7.10-1.6.+:dev"
40 | shade "javazoom:jlayer:1.0.1"
41 | shade "com.squareup.okhttp:okhttp:2.5.0"
42 | shade "com.googlecode.soundlibs:tritonus-share:0.3.7-2"
43 | }
44 |
45 | if (System.getenv().BUILD_NUMBER != null)
46 | ext.buildNumber = System.getenv().BUILD_NUMBER?.toInteger()
47 | else
48 | ext.buildNumber = 0
49 |
50 | version = "0.1.0"
51 | group = "pcl.OpenFM"
52 | archivesBaseName = "OpenFM-1.7.10"
53 |
54 | minecraft {
55 | version = "1.7.10-10.13.4.1448-1.7.10"
56 | replace "@VERSION@", project.version
57 | replace "@BUILD@", project.ext.buildNumber
58 | }
59 |
60 | jar {
61 | configurations.shade.each { dep ->
62 | from(project.zipTree(dep)){
63 | exclude 'META-INF', 'META-INF/**'
64 | }
65 | }
66 | }
67 |
68 | jar.classifier = "${ext.buildNumber}"
69 | jar.manifest = manifest { attributes(
70 | "FMLCorePlugin": "pcl.OpenFM.misc.DepLoader",
71 | "FMLCorePluginContainsFMLMod": "icanhazfmlmodpweeze"
72 | ) }
73 | def curseforge_key = 0
74 | def curse_changlog = "default"
75 | if (project.hasProperty('opensecurity_curseforge_key')) {
76 | curseforge_key = project.opensecurity_curseforge_key
77 | curse_changlog = project.changelog
78 | }
79 |
80 | apply plugin: 'curseforge'
81 | curse {
82 | apiKey = curseforge_key
83 | projectId = "236839"
84 | releaseType = "release"
85 | changelog = curse_changlog
86 | addGameVersion project.minecraft.version
87 | }
88 |
89 | processResources {
90 | // replace stuff in mcmod.info, nothing else
91 | from(sourceSets.main.resources.srcDirs) {
92 | include 'mcmod.info'
93 |
94 | // replace version and mcversion
95 | expand 'version':project.version + "." + project.ext.buildNumber, 'mcversion':project.minecraft.version
96 | }
97 |
98 | // copy everything else, thats not the mcmod.info
99 | from(sourceSets.main.resources.srcDirs) {
100 | exclude 'mcmod.info'
101 | }
102 | }
103 |
104 | // this is needed for IntelliJ so we don't have to copy over the assets manually every time
105 | idea {
106 | module {
107 | outputDir = file('build/classes/main')
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PC-Logix/OpenFM/1f364f36fd13655f45e5fe5601004f8b76bb02ec/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Oct 29 18:00:54 CDT 2013
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=http\://services.gradle.org/distributions/gradle-1.8-bin.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/src/api/java/dan200/computercraft/api/ComputerCraftAPI.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This file is part of the public ComputerCraft API - http://www.computercraft.info
3 | * Copyright Daniel Ratcliffe, 2011-2014. This API may be redistributed unmodified and in full only.
4 | * For help using the API, and posting your mods, visit the forums at computercraft.info.
5 | */
6 |
7 | package dan200.computercraft.api;
8 |
9 | import dan200.computercraft.api.filesystem.IMount;
10 | import dan200.computercraft.api.filesystem.IWritableMount;
11 | import dan200.computercraft.api.media.IMediaProvider;
12 | import dan200.computercraft.api.peripheral.IPeripheralProvider;
13 | import dan200.computercraft.api.redstone.IBundledRedstoneProvider;
14 | import dan200.computercraft.api.turtle.ITurtleUpgrade;
15 | import net.minecraft.world.World;
16 |
17 | import java.lang.reflect.Method;
18 |
19 | /**
20 | * The static entry point to the ComputerCraft API.
21 | * Members in this class must be called after mod_ComputerCraft has been initialised,
22 | * but may be called before it is fully loaded.
23 | */
24 | public final class ComputerCraftAPI
25 | {
26 | /**
27 | * Creates a numbered directory in a subfolder of the save directory for a given world, and returns that number.
28 | * Use in conjuction with createSaveDirMount() to create a unique place for your peripherals or media items to store files.
29 | * @param world The world for which the save dir should be created. This should be the serverside world object.
30 | * @param parentSubPath The folder path within the save directory where the new directory should be created. eg: "computercraft/disk"
31 | * @return The numerical value of the name of the new folder, or -1 if the folder could not be created for some reason.
32 | * eg: if createUniqueNumberedSaveDir( world, "computer/disk" ) was called returns 42, then "computer/disk/42" is now available for writing.
33 | * @see #createSaveDirMount(World, String, long)
34 | */
35 | public static int createUniqueNumberedSaveDir( World world, String parentSubPath )
36 | {
37 | findCC();
38 | if( computerCraft_createUniqueNumberedSaveDir != null )
39 | {
40 | try {
41 | return ((Integer)computerCraft_createUniqueNumberedSaveDir.invoke( null, world, parentSubPath )).intValue();
42 | } catch (Exception e){
43 | // It failed
44 | }
45 | }
46 | return -1;
47 | }
48 |
49 | /**
50 | * Creates a file system mount that maps to a subfolder of the save directory for a given world, and returns it.
51 | * Use in conjuction with IComputerAccess.mount() or IComputerAccess.mountWritable() to mount a folder from the
52 | * users save directory onto a computers file system.
53 | * @param world The world for which the save dir can be found. This should be the serverside world object.
54 | * @param subPath The folder path within the save directory that the mount should map to. eg: "computer/disk/42".
55 | * Use createUniqueNumberedSaveDir() to create a new numbered folder to use.
56 | * @param capacity The ammount of data that can be stored in the directory before it fills up, in bytes.
57 | * @return The mount, or null if it could be created for some reason. Use IComputerAccess.mount() or IComputerAccess.mountWritable()
58 | * to mount this on a Computers' file system.
59 | * @see #createUniqueNumberedSaveDir(World, String)
60 | * @see dan200.computercraft.api.peripheral.IComputerAccess#mount(String, dan200.computercraft.api.filesystem.IMount)
61 | * @see dan200.computercraft.api.peripheral.IComputerAccess#mountWritable(String, dan200.computercraft.api.filesystem.IWritableMount)
62 | * @see dan200.computercraft.api.filesystem.IMount
63 | * @see IWritableMount
64 | */
65 | public static IWritableMount createSaveDirMount( World world, String subPath, long capacity )
66 | {
67 | findCC();
68 | if( computerCraft_createSaveDirMount != null )
69 | {
70 | try {
71 | return (IWritableMount)computerCraft_createSaveDirMount.invoke( null, world, subPath, capacity );
72 | } catch (Exception e){
73 | // It failed
74 | }
75 | }
76 | return null;
77 | }
78 |
79 | /**
80 | * Creates a file system mount to a resource folder, and returns it.
81 | * Use in conjuction with IComputerAccess.mount() or IComputerAccess.mountWritable() to mount a resource folder onto a computers file system.
82 | * The files in this mount will be a combination of files in the specified mod jar, and resource packs that contain resources with the same domain and path.
83 | * @param modClass A class in whose jar to look first for the resources to mount. Using your main mod class is recommended. eg: MyMod.class
84 | * @param domain The domain under which to look for resources. eg: "mymod"
85 | * @param subPath The domain under which to look for resources. eg: "mymod/lua/myfiles"
86 | * @return The mount, or null if it could be created for some reason. Use IComputerAccess.mount() or IComputerAccess.mountWritable()
87 | * to mount this on a Computers' file system.
88 | * @see dan200.computercraft.api.peripheral.IComputerAccess#mount(String, dan200.computercraft.api.filesystem.IMount)
89 | * @see dan200.computercraft.api.peripheral.IComputerAccess#mountWritable(String, IWritableMount)
90 | * @see dan200.computercraft.api.filesystem.IMount
91 | */
92 | public static IMount createResourceMount( Class modClass, String domain, String subPath )
93 | {
94 | findCC();
95 | if( computerCraft_createResourceMount != null )
96 | {
97 | try {
98 | return (IMount)computerCraft_createResourceMount.invoke( null, modClass, domain, subPath );
99 | } catch (Exception e){
100 | // It failed
101 | }
102 | }
103 | return null;
104 | }
105 |
106 | /**
107 | * Registers a peripheral handler to convert blocks into IPeripheral implementations.
108 | * @see dan200.computercraft.api.peripheral.IPeripheral
109 | * @see dan200.computercraft.api.peripheral.IPeripheralProvider
110 | */
111 | public static void registerPeripheralProvider( IPeripheralProvider handler )
112 | {
113 | findCC();
114 | if ( computerCraft_registerPeripheralProvider != null)
115 | {
116 | try {
117 | computerCraft_registerPeripheralProvider.invoke( null, handler );
118 | } catch (Exception e){
119 | // It failed
120 | }
121 | }
122 | }
123 |
124 | /**
125 | * Registers a new turtle turtle for use in ComputerCraft. After calling this,
126 | * users should be able to craft Turtles with your new turtle. It is recommended to call
127 | * this during the load() method of your mod.
128 | * @see dan200.computercraft.api.turtle.ITurtleUpgrade
129 | */
130 | public static void registerTurtleUpgrade( ITurtleUpgrade upgrade )
131 | {
132 | if( upgrade != null )
133 | {
134 | findCC();
135 | if( computerCraft_registerTurtleUpgrade != null )
136 | {
137 | try {
138 | computerCraft_registerTurtleUpgrade.invoke( null, upgrade );
139 | } catch( Exception e ) {
140 | // It failed
141 | }
142 | }
143 | }
144 | }
145 |
146 | /**
147 | * Registers a bundled redstone handler to provide bundled redstone output for blocks
148 | * @see dan200.computercraft.api.redstone.IBundledRedstoneProvider
149 | */
150 | public static void registerBundledRedstoneProvider( IBundledRedstoneProvider handler )
151 | {
152 | findCC();
153 | if( computerCraft_registerBundledRedstoneProvider != null )
154 | {
155 | try {
156 | computerCraft_registerBundledRedstoneProvider.invoke( null, handler );
157 | } catch (Exception e) {
158 | // It failed
159 | }
160 | }
161 | }
162 |
163 | /**
164 | * If there is a Computer or Turtle at a certain position in the world, get it's bundled redstone output.
165 | * @see dan200.computercraft.api.redstone.IBundledRedstoneProvider
166 | * @return If there is a block capable of emitting bundled redstone at the location, it's signal (0-65535) will be returned.
167 | * If there is no block capable of emitting bundled redstone at the location, -1 will be returned.
168 | */
169 | public static int getBundledRedstoneOutput( World world, int x, int y, int z, int side )
170 | {
171 | findCC();
172 | if( computerCraft_getDefaultBundledRedstoneOutput != null )
173 | {
174 | try {
175 | return ((Integer)computerCraft_getDefaultBundledRedstoneOutput.invoke( null, world, x, y, z, side )).intValue();
176 | } catch (Exception e){
177 | // It failed
178 | }
179 | }
180 | return -1;
181 | }
182 |
183 | /**
184 | * Registers a media handler to provide IMedia implementations for Items
185 | * @see dan200.computercraft.api.media.IMediaProvider
186 | */
187 | public static void registerMediaProvider( IMediaProvider handler )
188 | {
189 | findCC();
190 | if( computerCraft_registerMediaProvider != null )
191 | {
192 | try {
193 | computerCraft_registerMediaProvider.invoke( null, handler );
194 | } catch (Exception e){
195 | // It failed
196 | }
197 | }
198 | }
199 |
200 | // The functions below here are private, and are used to interface with the non-API ComputerCraft classes.
201 | // Reflection is used here so you can develop your mod in MCP without decompiling ComputerCraft and including
202 | // it in your solution.
203 |
204 | private static void findCC()
205 | {
206 | if( !ccSearched ) {
207 | try {
208 | computerCraft = Class.forName( "dan200.computercraft.ComputerCraft" );
209 | computerCraft_createUniqueNumberedSaveDir = findCCMethod( "createUniqueNumberedSaveDir", new Class[]{
210 | World.class, String.class
211 | } );
212 | computerCraft_createSaveDirMount = findCCMethod( "createSaveDirMount", new Class[] {
213 | World.class, String.class, Long.TYPE
214 | } );
215 | computerCraft_createResourceMount = findCCMethod( "createResourceMount", new Class[] {
216 | Class.class, String.class, String.class
217 | } );
218 | computerCraft_registerPeripheralProvider = findCCMethod( "registerPeripheralProvider", new Class[] {
219 | IPeripheralProvider.class
220 | } );
221 | computerCraft_registerTurtleUpgrade = findCCMethod( "registerTurtleUpgrade", new Class[] {
222 | ITurtleUpgrade.class
223 | } );
224 | computerCraft_registerBundledRedstoneProvider = findCCMethod( "registerBundledRedstoneProvider", new Class[] {
225 | IBundledRedstoneProvider.class
226 | } );
227 | computerCraft_getDefaultBundledRedstoneOutput = findCCMethod( "getDefaultBundledRedstoneOutput", new Class[] {
228 | World.class, Integer.TYPE, Integer.TYPE, Integer.TYPE, Integer.TYPE
229 | } );
230 | computerCraft_registerMediaProvider = findCCMethod( "registerMediaProvider", new Class[] {
231 | IMediaProvider.class
232 | } );
233 | } catch( Exception e ) {
234 | System.out.println( "ComputerCraftAPI: ComputerCraft not found." );
235 | } finally {
236 | ccSearched = true;
237 | }
238 | }
239 | }
240 |
241 | private static Method findCCMethod( String name, Class[] args )
242 | {
243 | try {
244 | if( computerCraft != null )
245 | {
246 | return computerCraft.getMethod( name, args );
247 | }
248 | return null;
249 | } catch( NoSuchMethodException e ) {
250 | System.out.println( "ComputerCraftAPI: ComputerCraft method " + name + " not found." );
251 | return null;
252 | }
253 | }
254 |
255 | private static boolean ccSearched = false;
256 | private static Class computerCraft = null;
257 | private static Method computerCraft_createUniqueNumberedSaveDir = null;
258 | private static Method computerCraft_createSaveDirMount = null;
259 | private static Method computerCraft_createResourceMount = null;
260 | private static Method computerCraft_registerPeripheralProvider = null;
261 | private static Method computerCraft_registerTurtleUpgrade = null;
262 | private static Method computerCraft_registerBundledRedstoneProvider = null;
263 | private static Method computerCraft_getDefaultBundledRedstoneOutput = null;
264 | private static Method computerCraft_registerMediaProvider = null;
265 | }
266 |
--------------------------------------------------------------------------------
/src/api/java/dan200/computercraft/api/filesystem/IMount.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This file is part of the public ComputerCraft API - http://www.computercraft.info
3 | * Copyright Daniel Ratcliffe, 2011-2014. This API may be redistributed unmodified and in full only.
4 | * For help using the API, and posting your mods, visit the forums at computercraft.info.
5 | */
6 |
7 | package dan200.computercraft.api.filesystem;
8 |
9 | import java.io.IOException;
10 | import java.io.InputStream;
11 | import java.util.List;
12 |
13 | /**
14 | * Represents a read only part of a virtual filesystem that can be mounted onto a computercraft using IComputerAccess.mount().
15 | * Ready made implementations of this interface can be created using ComputerCraftAPI.createSaveDirMount() or ComputerCraftAPI.createResourceMount(), or you're free to implement it yourselves!
16 | * @see dan200.computercraft.api.ComputerCraftAPI#createSaveDirMount(World, String)
17 | * @see dan200.computercraft.api.ComputerCraftAPI#createResourceMount(Class, String, String)
18 | * @see dan200.computercraft.api.peripheral.IComputerAccess#mount(String, IMount)
19 | * @see IWritableMount
20 | */
21 | public interface IMount
22 | {
23 | /**
24 | * Returns whether a file with a given path exists or not.
25 | * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram"
26 | * @return true if the file exists, false otherwise
27 | */
28 | public boolean exists( String path ) throws IOException;
29 |
30 | /**
31 | * Returns whether a file with a given path is a directory or not.
32 | * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprograms"
33 | * @return true if the file exists and is a directory, false otherwise
34 | */
35 | public boolean isDirectory( String path ) throws IOException;
36 |
37 | /**
38 | * Returns the file names of all the files in a directory.
39 | * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprograms"
40 | * @param contents A list of strings. Add all the file names to this list
41 | */
42 | public void list( String path, List contents ) throws IOException;
43 |
44 | /**
45 | * Returns the size of a file with a given path, in bytes
46 | * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram"
47 | * @return the size of the file, in bytes
48 | */
49 | public long getSize( String path ) throws IOException;
50 |
51 | /**
52 | * Opens a file with a given path, and returns an inputstream representing it's contents.
53 | * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram"
54 | * @return a stream representing the contents of the file
55 | */
56 | public InputStream openForRead( String path ) throws IOException;
57 | }
58 |
--------------------------------------------------------------------------------
/src/api/java/dan200/computercraft/api/filesystem/IWritableMount.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This file is part of the public ComputerCraft API - http://www.computercraft.info
3 | * Copyright Daniel Ratcliffe, 2011-2014. This API may be redistributed unmodified and in full only.
4 | * For help using the API, and posting your mods, visit the forums at computercraft.info.
5 | */
6 |
7 | package dan200.computercraft.api.filesystem;
8 |
9 | import java.io.IOException;
10 | import java.io.OutputStream;
11 |
12 | /**
13 | * Represents a part of a virtual filesystem that can be mounted onto a computercraft using IComputerAccess.mount() or IComputerAccess.mountWritable(), that can also be written to.
14 | * Ready made implementations of this interface can be created using ComputerCraftAPI.createSaveDirMount(), or you're free to implement it yourselves!
15 | * @see dan200.computercraft.api.ComputerCraftAPI#createSaveDirMount(World, String)
16 | * @see dan200.computercraft.api.peripheral.IComputerAccess#mountWritable(String, dan200.computercraft.api.filesystem.IMount)
17 | * @see dan200.computercraft.api.filesystem.IMount
18 | */
19 | public interface IWritableMount extends IMount
20 | {
21 | /**
22 | * Creates a directory at a given path inside the virtual file system.
23 | * @param path A file path in normalised format, relative to the mount location. ie: "programs/mynewprograms"
24 | */
25 | public void makeDirectory( String path ) throws IOException;
26 |
27 | /**
28 | * Deletes a directory at a given path inside the virtual file system.
29 | * @param path A file path in normalised format, relative to the mount location. ie: "programs/myoldprograms"
30 | */
31 | public void delete( String path ) throws IOException;
32 |
33 | /**
34 | * Opens a file with a given path, and returns an outputstream for writing to it.
35 | * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram"
36 | * @return a stream for writing to
37 | */
38 | public OutputStream openForWrite( String path ) throws IOException;
39 |
40 | /**
41 | * Opens a file with a given path, and returns an outputstream for appending to it.
42 | * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram"
43 | * @return a stream for writing to
44 | */
45 | public OutputStream openForAppend( String path ) throws IOException;
46 |
47 | /**
48 | * Get the ammount of free space on the mount, in bytes. You should decrease this value as the user writes to the mount, and write operations should fail once it reaches zero.
49 | * @return The ammount of free space, in bytes.
50 | */
51 | public long getRemainingSpace() throws IOException;
52 | }
53 |
--------------------------------------------------------------------------------
/src/api/java/dan200/computercraft/api/lua/ILuaContext.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This file is part of the public ComputerCraft API - http://www.computercraft.info
3 | * Copyright Daniel Ratcliffe, 2011-2014. This API may be redistributed unmodified and in full only.
4 | * For help using the API, and posting your mods, visit the forums at computercraft.info.
5 | */
6 |
7 | package dan200.computercraft.api.lua;
8 |
9 | /**
10 | * An interface passed to peripherals and ILuaObjects' by computers or turtles, providing methods
11 | * that allow the peripheral call to wait for events before returning, just like in lua.
12 | * This is very useful if you need to signal work to be performed on the main thread, and don't want to return
13 | * until the work has been completed.
14 | */
15 | public interface ILuaContext
16 | {
17 | /**
18 | * Wait for an event to occur on the computercraft, suspending the thread until it arises. This method is exactly equivalent to os.pullEvent() in lua.
19 | * @param filter A specific event to wait for, or null to wait for any event
20 | * @return An object array containing the name of the event that occurred, and any event parameters
21 | * @throws Exception If the user presses CTRL+T to terminate the current program while pullEvent() is waiting for an event, a "Terminated" exception will be thrown here.
22 | * Do not attempt to common this exception, unless you wish to prevent termination, which is not recommended.
23 | * @throws InterruptedException If the user shuts down or reboots the computercraft while pullEvent() is waiting for an event, InterruptedException will be thrown. This exception must not be caught or intercepted, or the computercraft will leak memory and end up in a broken state.
24 | */
25 | public Object[] pullEvent( String filter ) throws LuaException, InterruptedException;
26 |
27 | /**
28 | * The same as pullEvent(), except "terminated" events are ignored. Only use this if you want to prevent program termination, which is not recommended. This method is exactly equivalent to os.pullEventRaw() in lua.
29 | * @param filter A specific event to wait for, or null to wait for any event
30 | * @return An object array containing the name of the event that occurred, and any event parameters
31 | * @throws InterruptedException If the user shuts down or reboots the computercraft while pullEventRaw() is waiting for an event, InterruptedException will be thrown. This exception must not be caught or intercepted, or the computercraft will leak memory and end up in a broken state.
32 | * @see #pullEvent(String)
33 | */
34 | public Object[] pullEventRaw( String filter ) throws InterruptedException;
35 |
36 | /**
37 | * Yield the current coroutine with some arguments until it is resumed. This method is exactly equivalent to coroutine.yield() in lua. Use pullEvent() if you wish to wait for events.
38 | * @param arguments An object array containing the arguments to pass to coroutine.yield()
39 | * @return An object array containing the return values from coroutine.yield()
40 | * @throws InterruptedException If the user shuts down or reboots the computercraft the coroutine is suspended, InterruptedException will be thrown. This exception must not be caught or intercepted, or the computercraft will leak memory and end up in a broken state.
41 | * @see #pullEvent(String)
42 | */
43 | public Object[] yield( Object[] arguments ) throws InterruptedException;
44 | }
45 |
--------------------------------------------------------------------------------
/src/api/java/dan200/computercraft/api/lua/ILuaObject.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This file is part of the public ComputerCraft API - http://www.computercraft.info
3 | * Copyright Daniel Ratcliffe, 2011-2014. This API may be redistributed unmodified and in full only.
4 | * For help using the API, and posting your mods, visit the forums at computercraft.info.
5 | */
6 |
7 | package dan200.computercraft.api.lua;
8 |
9 | /**
10 | * An interface for representing custom objects returned by IPeripheral.callMethod() calls.
11 | * Return objects implementing this interface to expose objects with methods to lua.
12 | */
13 | public interface ILuaObject
14 | {
15 | /**
16 | * Get the names of the methods that this object implements. This works the same as IPeripheral.getMethodNames(). See that method for detailed documentation.
17 | * @see dan200.computercraft.api.peripheral.IPeripheral#getMethodNames()
18 | */
19 | public String[] getMethodNames();
20 |
21 | /**
22 | * Called when a user calls one of the methods that this object implements. This works the same as IPeripheral.callMethod(). See that method for detailed documentation.
23 | * @see dan200.computercraft.api.peripheral.IPeripheral#callMethod(dan200.computercraft.api.peripheral.IComputerAccess, ILuaContext, int, Object[])
24 | */
25 | public Object[] callMethod( ILuaContext context, int method, Object[] arguments ) throws LuaException, InterruptedException;
26 | }
27 |
--------------------------------------------------------------------------------
/src/api/java/dan200/computercraft/api/lua/LuaException.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This file is part of the public ComputerCraft API - http://www.computercraft.info
3 | * Copyright Daniel Ratcliffe, 2011-2014. This API may be redistributed unmodified and in full only.
4 | * For help using the API, and posting your mods, visit the forums at computercraft.info.
5 | */
6 |
7 | package dan200.computercraft.api.lua;
8 |
9 | /**
10 | * An exception representing an error in Lua, like that raised by the error() function
11 | */
12 | public class LuaException extends Exception
13 | {
14 | private final int m_level;
15 |
16 | public LuaException( String message )
17 | {
18 | this( message, 1 );
19 | }
20 |
21 | public LuaException( String message, int level )
22 | {
23 | super( message );
24 | m_level = level;
25 | }
26 |
27 | public int getLevel()
28 | {
29 | return m_level;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/api/java/dan200/computercraft/api/media/IMedia.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This file is part of the public ComputerCraft API - http://www.computercraft.info
3 | * Copyright Daniel Ratcliffe, 2011-2014. This API may be redistributed unmodified and in full only.
4 | * For help using the API, and posting your mods, visit the forums at computercraft.info.
5 | */
6 |
7 | package dan200.computercraft.api.media;
8 |
9 | import dan200.computercraft.api.filesystem.IMount;
10 | import net.minecraft.item.ItemStack;
11 | import net.minecraft.world.World;
12 |
13 | /**
14 | * Represents an item that can be placed in a disk drive and used by a Computer.
15 | * Implement this interface on your Item class to allow it to be used in the drive.
16 | */
17 | public interface IMedia
18 | {
19 | /**
20 | * Get a string representing the label of this item. Will be called vi disk.getLabel() in lua.
21 | * @param stack The itemstack to inspect
22 | * @return The label. ie: "Dan's Programs"
23 | */
24 | public String getLabel( ItemStack stack );
25 |
26 | /**
27 | * Set a string representing the label of this item. Will be called vi disk.setLabel() in lua.
28 | * @param stack The itemstack to modify.
29 | * @param label The string to set the label to.
30 | * @return true if the label was updated, false if the label may not be modified.
31 | */
32 | public boolean setLabel( ItemStack stack, String label );
33 |
34 | /**
35 | * If this disk represents an item with audio (like a record), get the readable name of the audio track. ie: "Jonathon Coulton - Still Alive"
36 | * @param stack The itemstack to inspect.
37 | * @return The name, or null if this item does not represent an item with audio.
38 | */
39 | public String getAudioTitle( ItemStack stack );
40 |
41 | /**
42 | * If this disk represents an item with audio (like a record), get the resource name of the audio track to play.
43 | * @param stack The itemstack to inspect.
44 | * @return The name, or null if this item does not represent an item with audio.
45 | */
46 | public String getAudioRecordName( ItemStack stack );
47 |
48 | /**
49 | * If this disk represents an item with data (like a floppy disk), get a mount representing it's contents. This will be mounted onto the filesystem of the computercraft while the media is in the disk drive.
50 | * @param stack The itemstack to inspect.
51 | * @param world The world in which the item and disk drive reside.
52 | * @return The mount, or null if this item does not represent an item with data. If the IMount returned also implements IWritableMount, it will mounted using mountWritable()
53 | * @see dan200.computercraft.api.filesystem.IMount
54 | * @see dan200.computercraft.api.filesystem.IWritableMount
55 | * @see dan200.computercraft.api.ComputerCraftAPI#createSaveDirMount(World, String, long)
56 | * @see dan200.computercraft.api.ComputerCraftAPI#createResourceMount(Class, String, String)
57 | */
58 | public IMount createDataMount( ItemStack stack, World world );
59 | }
60 |
--------------------------------------------------------------------------------
/src/api/java/dan200/computercraft/api/media/IMediaProvider.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This file is part of the public ComputerCraft API - http://www.computercraft.info
3 | * Copyright Daniel Ratcliffe, 2011-2014. This API may be redistributed unmodified and in full only.
4 | * For help using the API, and posting your mods, visit the forums at computercraft.info.
5 | */
6 |
7 | package dan200.computercraft.api.media;
8 |
9 | import net.minecraft.item.ItemStack;
10 |
11 | /**
12 | * This interface is used to provide IMedia implementations for ItemStack
13 | * @see dan200.computercraft.api.ComputerCraftAPI#registerMediaProvider(IMediaProvider)
14 | */
15 | public interface IMediaProvider
16 | {
17 | /**
18 | * Produce an IMedia implementation from an ItemStack.
19 | * @see dan200.computercraft.api.ComputerCraftAPI#registerMediaProvider(IMediaProvider)
20 | * @return an IMedia implementation, or null if the item is not something you wish to handle
21 | */
22 | public IMedia getMedia( ItemStack stack );
23 | }
24 |
--------------------------------------------------------------------------------
/src/api/java/dan200/computercraft/api/peripheral/IComputerAccess.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This file is part of the public ComputerCraft API - http://www.computercraft.info
3 | * Copyright Daniel Ratcliffe, 2011-2014. This API may be redistributed unmodified and in full only.
4 | * For help using the API, and posting your mods, visit the forums at computercraft.info.
5 | */
6 |
7 | package dan200.computercraft.api.peripheral;
8 |
9 | import dan200.computercraft.api.filesystem.IMount;
10 | import dan200.computercraft.api.filesystem.IWritableMount;
11 |
12 | /**
13 | * The interface passed to peripherals by computers or turtles, providing methods
14 | * that they can call. This should not be implemented by your classes. Do not interact
15 | * with computers except via this interface.
16 | */
17 | public interface IComputerAccess
18 | {
19 | /**
20 | * Mount a mount onto the computers' file system in a read only mode.
21 | * @param desiredLocation The location on the computercraft's file system where you would like the mount to be mounted.
22 | * @param mount The mount object to mount on the computercraft. These can be obtained by calling ComputerCraftAPI.createSaveDirMount(), ComputerCraftAPI.createResourceMount() or by creating your own objects that implement the IMount interface.
23 | * @return The location on the computercraft's file system where you the mount mounted, or null if there was already a file in the desired location. Store this value if you wish to unmount the mount later.
24 | * @see dan200.computercraft.api.ComputerCraftAPI#createSaveDirMount(World, String)
25 | * @see dan200.computercraft.api.ComputerCraftAPI#createResourceMount(Class, String, String)
26 | * @see #mountWritable(String, dan200.computercraft.api.filesystem.IWritableMount)
27 | * @see #unmount(String)
28 | * @see dan200.computercraft.api.filesystem.IMount
29 | */
30 | public String mount( String desiredLocation, IMount mount );
31 |
32 | /**
33 | * Mount a mount onto the computers' file system in a writable mode.
34 | * @param desiredLocation The location on the computercraft's file system where you would like the mount to be mounted.
35 | * @param mount The mount object to mount on the computercraft. These can be obtained by calling ComputerCraftAPI.createSaveDirMount() or by creating your own objects that implement the IWritableMount interface.
36 | * @return The location on the computercraft's file system where you the mount mounted, or null if there was already a file in the desired location. Store this value if you wish to unmount the mount later.
37 | * @see dan200.computercraft.api.ComputerCraftAPI#createSaveDirMount(World, String)
38 | * @see dan200.computercraft.api.ComputerCraftAPI#createResourceMount(Class, String, String)
39 | * @see #mount(String, IMount)
40 | * @see #unmount(String)
41 | * @see IMount
42 | */
43 | public String mountWritable( String desiredLocation, IWritableMount mount );
44 |
45 | /**
46 | * Unmounts a directory previously mounted onto the computers file system by mount() or mountWritable().
47 | * When a directory is unmounted, it will disappear from the computers file system, and the user will no longer be able to
48 | * access it. All directories mounted by a mount or mountWritable are automatically unmounted when the peripheral
49 | * is attached if they have not been explicitly unmounted.
50 | * @param location The desired location in the computers file system of the directory to unmount.
51 | * This must be the location of a directory previously mounted by mount() or mountWritable(), as
52 | * indicated by their return value.
53 | * @see #mount(String, IMount)
54 | * @see #mountWritable(String, IWritableMount)
55 | */
56 | public void unmount( String location );
57 |
58 | /**
59 | * Returns the numerical ID of this computercraft.
60 | * This is the same number obtained by calling os.getComputerID() or running the "id" program from lua,
61 | * and is guarunteed unique. This number will be positive.
62 | * @return The identifier.
63 | */
64 | public int getID();
65 |
66 | /**
67 | * Causes an event to be raised on this computercraft, which the computercraft can respond to by calling
68 | * os.pullEvent(). This can be used to notify the computercraft when things happen in the world or to
69 | * this peripheral.
70 | * @param event A string identifying the type of event that has occurred, this will be
71 | * returned as the first value from os.pullEvent(). It is recommended that you
72 | * you choose a name that is unique, and recognisable as originating from your
73 | * peripheral. eg: If your peripheral type is "button", a suitable event would be
74 | * "button_pressed".
75 | * @param arguments In addition to a name, you may pass an array of extra arguments to the event, that will
76 | * be supplied as extra return values to os.pullEvent(). Objects in the array will be converted
77 | * to lua data types in the same fashion as the return values of IPeripheral.callMethod().
78 | * You may supply null to indicate that no arguments are to be supplied.
79 | * @see dan200.computercraft.api.peripheral.IPeripheral#callMethod
80 | */
81 | public void queueEvent( String event, Object[] arguments );
82 |
83 | /**
84 | * Get a string, unique to the computercraft, by which the computercraft refers to this peripheral.
85 | * For directly attached peripherals this will be "left","right","front","back",etc, but
86 | * for peripherals attached remotely it will be different. It is good practice to supply
87 | * this string when raising events to the computercraft, so that the computercraft knows from
88 | * which peripheral the event came.
89 | * @return A string unique to the computercraft, but not globally.
90 | */
91 | public String getAttachmentName();
92 | }
93 |
--------------------------------------------------------------------------------
/src/api/java/dan200/computercraft/api/peripheral/IPeripheral.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This file is part of the public ComputerCraft API - http://www.computercraft.info
3 | * Copyright Daniel Ratcliffe, 2011-2014. This API may be redistributed unmodified and in full only.
4 | * For help using the API, and posting your mods, visit the forums at computercraft.info.
5 | */
6 |
7 | package dan200.computercraft.api.peripheral;
8 |
9 | import dan200.computercraft.api.lua.ILuaContext;
10 | import dan200.computercraft.api.lua.LuaException;
11 |
12 | /**
13 | * The interface that defines a peripheral. This should be implemented by the
14 | * TileEntity of any common that you wish to be interacted with by
15 | * computercraft or turtle.
16 | */
17 | public interface IPeripheral
18 | {
19 | /**
20 | * Should return a string that uniquely identifies this type of peripheral.
21 | * This can be queried from lua by calling peripheral.getType()
22 | * @return A string identifying the type of peripheral.
23 | */
24 | public String getType();
25 |
26 | /**
27 | * Should return an array of strings that identify the methods that this
28 | * peripheral exposes to Lua. This will be called once before each attachment,
29 | * and should not change when called multiple times.
30 | * @return An array of strings representing method names.
31 | * @see #callMethod
32 | */
33 | public String[] getMethodNames();
34 |
35 | /**
36 | * This is called when a lua program on an attached computercraft calls peripheral.call() with
37 | * one of the methods exposed by getMethodNames().
38 | *
39 | * Be aware that this will be called from the ComputerCraft Lua thread, and must be thread-safe
40 | * when interacting with minecraft objects.
41 | * @param computer The interface to the computercraft that is making the call. Remember that multiple
42 | * computers can be attached to a peripheral at once.
43 | * @param context The context of the currently running lua thread. This can be used to wait for events
44 | * or otherwise yield.
45 | * @param method An integer identifying which of the methods from getMethodNames() the computercraft
46 | * wishes to call. The integer indicates the index into the getMethodNames() table
47 | * that corresponds to the string passed into peripheral.call()
48 | * @param arguments An array of objects, representing the arguments passed into peripheral.call().
49 | * Lua values of type "string" will be represented by Object type String.
50 | * Lua values of type "number" will be represented by Object type Double.
51 | * Lua values of type "boolean" will be represented by Object type Boolean.
52 | * Lua values of any other type will be represented by a null object.
53 | * This array will be empty if no arguments are passed.
54 | * @return An array of objects, representing values you wish to return to the lua program.
55 | * Integers, Doubles, Floats, Strings, Booleans and null be converted to their corresponding lua type.
56 | * All other types will be converted to nil.
57 | * You may return null to indicate no values should be returned.
58 | * @throws Exception If you throw any exception from this function, a lua error will be raised with the
59 | * same message as your exception. Use this to throw appropriate errors if the wrong
60 | * arguments are supplied to your method.
61 | * @see #getMethodNames
62 | */
63 | public Object[] callMethod( IComputerAccess computer, ILuaContext context, int method, Object[] arguments ) throws LuaException, InterruptedException;
64 |
65 | /**
66 | * Is called when canAttachToSide has returned true, and a computercraft is attaching to the peripheral.
67 | * This will occur when a peripheral is placed next to an active computercraft, when a computercraft is turned on next to a peripheral,
68 | * or when a turtle travels into a square next to a peripheral.
69 | * Between calls to attach() and detach(), the attached computercraft can make method calls on the peripheral using peripheral.call().
70 | * This method can be used to keep track of which computers are attached to the peripheral, or to take action when attachment
71 | * occurs.
72 | *
73 | * Be aware that this will be called from the ComputerCraft Lua thread, and must be thread-safe
74 | * when interacting with minecraft objects.
75 | * @param computer The interface to the computercraft that is being attached. Remember that multiple
76 | * computers can be attached to a peripheral at once.
77 | * @see #detach
78 | */
79 | public void attach( IComputerAccess computer );
80 |
81 | /**
82 | * Is called when a computercraft is detaching from the peripheral.
83 | * This will occur when a computercraft shuts down, when the peripheral is removed while attached to computers,
84 | * or when a turtle moves away from a square attached to a peripheral.
85 | * This method can be used to keep track of which computers are attached to the peripheral, or to take action when detachment
86 | * occurs.
87 | *
88 | * Be aware that this will be called from the ComputerCraft Lua thread, and must be thread-safe
89 | * when interacting with minecraft objects.
90 | * @param computer The interface to the computercraft that is being detached. Remember that multiple
91 | * computers can be attached to a peripheral at once.
92 | * @see #detach
93 | */
94 | public void detach( IComputerAccess computer );
95 |
96 | /**
97 | * TODO: Document me
98 | */
99 | public boolean equals( IPeripheral other );
100 | }
101 |
--------------------------------------------------------------------------------
/src/api/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This file is part of the public ComputerCraft API - http://www.computercraft.info
3 | * Copyright Daniel Ratcliffe, 2011-2014. This API may be redistributed unmodified and in full only.
4 | * For help using the API, and posting your mods, visit the forums at computercraft.info.
5 | */
6 |
7 | package dan200.computercraft.api.peripheral;
8 |
9 | import net.minecraft.world.World;
10 |
11 | /**
12 | * This interface is used to create peripheral implementations for blocks
13 | * @see dan200.computercraft.api.ComputerCraftAPI#registerPeripheralProvider(IPeripheralProvider)
14 | */
15 | public interface IPeripheralProvider
16 | {
17 | /**
18 | * Produce an peripheral implementation from a block location.
19 | * @see dan200.computercraft.api.ComputerCraftAPI#registerPeripheralProvider(IPeripheralProvider)
20 | * @return a peripheral, or null if there is not a peripheral here you'd like to handle.
21 | */
22 | public IPeripheral getPeripheral( World world, int x, int y, int z, int side );
23 | }
24 |
--------------------------------------------------------------------------------
/src/api/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This file is part of the public ComputerCraft API - http://www.computercraft.info
3 | * Copyright Daniel Ratcliffe, 2011-2014. This API may be redistributed unmodified and in full only.
4 | * For help using the API, and posting your mods, visit the forums at computercraft.info.
5 | */
6 |
7 | package dan200.computercraft.api.redstone;
8 |
9 | import net.minecraft.world.World;
10 |
11 | /**
12 | * This interface is used to provide bundled redstone output for blocks
13 | * @see dan200.computercraft.api.ComputerCraftAPI#registerBundledRedstoneProvider(IBundledRedstoneProvider)
14 | */
15 | public interface IBundledRedstoneProvider
16 | {
17 | /**
18 | * Produce an bundled redstone output from a block location.
19 | * @see dan200.computercraft.api.ComputerCraftAPI#registerBundledRedstoneProvider(IBundledRedstoneProvider)
20 | * @return a number in the range 0-65535 to indicate this block is providing output, or -1 if you do not wish to handle this block
21 | */
22 | public int getBundledRedstoneOutput( World world, int x, int y, int z, int side );
23 | }
24 |
--------------------------------------------------------------------------------
/src/api/java/dan200/computercraft/api/turtle/ITurtleAccess.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This file is part of the public ComputerCraft API - http://www.computercraft.info
3 | * Copyright Daniel Ratcliffe, 2011-2014. This API may be redistributed unmodified and in full only.
4 | * For help using the API, and posting your mods, visit the forums at computercraft.info.
5 | */
6 |
7 | package dan200.computercraft.api.turtle;
8 |
9 | import dan200.computercraft.api.lua.ILuaContext;
10 | import dan200.computercraft.api.lua.LuaException;
11 | import dan200.computercraft.api.peripheral.IPeripheral;
12 | import net.minecraft.inventory.IInventory;
13 | import net.minecraft.nbt.NBTTagCompound;
14 | import net.minecraft.util.ChunkCoordinates;
15 | import net.minecraft.util.Vec3;
16 | import net.minecraft.world.World;
17 |
18 | /**
19 | * The interface passed to turtle by turtles, providing methods that they can call.
20 | * This should not be implemented by your classes. Do not interact with turtles except via this interface and ITurtleUpgrade.
21 | */
22 | public interface ITurtleAccess
23 | {
24 | /**
25 | * Returns the world in which the turtle resides.
26 | * @return the world in which the turtle resides.
27 | */
28 | public World getWorld();
29 |
30 | /**
31 | * Returns a vector containing the integer co-ordinates at which the turtle resides.
32 | * @return a vector containing the integer co-ordinates at which the turtle resides.
33 | */
34 | public ChunkCoordinates getPosition();
35 |
36 | /**
37 | * TODO: Document me
38 | */
39 | public boolean teleportTo( World world, int x, int y, int z );
40 |
41 | /**
42 | * Returns a vector containing the floating point co-ordinates at which the turtle is rendered.
43 | * This will shift when the turtle is moving.
44 | * @param f The subframe fraction
45 | * @return a vector containing the floating point co-ordinates at which the turtle resides.
46 | */
47 | public Vec3 getVisualPosition( float f );
48 |
49 | /**
50 | * TODO: Document me
51 | */
52 | public float getVisualYaw( float f );
53 |
54 | /**
55 | * Returns the world direction the turtle is currently facing.
56 | * @return the world direction the turtle is currently facing.
57 | */
58 | public int getDirection();
59 |
60 | /**
61 | * TODO: Document me
62 | */
63 | public void setDirection( int dir );
64 |
65 | /**
66 | * TODO: Document me
67 | */
68 | public int getSelectedSlot();
69 |
70 | /**
71 | * TODO: Document me
72 | */
73 | public void setSelectedSlot( int slot );
74 |
75 | /**
76 | * TODO: Document me
77 | */
78 | public IInventory getInventory();
79 |
80 | /**
81 | * TODO: Document me
82 | */
83 | public boolean isFuelNeeded();
84 |
85 | /**
86 | * TODO: Document me
87 | */
88 | public int getFuelLevel();
89 |
90 | /**
91 | * TODO: Document me
92 | */
93 | public void setFuelLevel( int fuel );
94 |
95 | /**
96 | * TODO: Document me
97 | */
98 | public int getFuelLimit();
99 |
100 | /**
101 | * Removes some fuel from the turtles fuel supply. Negative numbers can be passed in to INCREASE the fuel level of the turtle.
102 | * @return Whether the turtle was able to consume the ammount of fuel specified. Will return false if you supply a number
103 | * greater than the current fuel level of the turtle.
104 | */
105 | public boolean consumeFuel( int fuel );
106 |
107 | /**
108 | * TODO: Document me
109 | */
110 | public void addFuel( int fuel );
111 |
112 | /**
113 | * Adds a custom command to the turtles command queue. Unlike peripheral methods, these custom commands will be executed
114 | * on the main thread, so are guaranteed to be able to access Minecraft objects safely, and will be queued up
115 | * with the turtles standard movement and tool commands. An issued command will return an unique integer, which will
116 | * be supplied as a parameter to a "turtle_response" event issued to the turtle after the command has completed. Look at the
117 | * lua source code for "rom/apis/turtle" for how to build a lua wrapper around this functionality.
118 | * @param command an object which will execute the custom command when its point in the queue is reached
119 | * @return the objects the command returned when executed. you should probably return these to the player
120 | * unchanged if called from a peripheral method.
121 | * @see ITurtleCommand
122 | */
123 | public Object[] executeCommand( ILuaContext context, ITurtleCommand command ) throws LuaException, InterruptedException;
124 |
125 | /**
126 | * TODO: Document me
127 | */
128 | public void playAnimation( TurtleAnimation animation );
129 |
130 | /**
131 | * Returns the turtle on the specified side of the turtle, if there is one.
132 | * @return the turtle on the specified side of the turtle, if there is one.
133 | */
134 | public ITurtleUpgrade getUpgrade( TurtleSide side );
135 |
136 | /**
137 | * TODO: Document me
138 | */
139 | public void setUpgrade( TurtleSide side, ITurtleUpgrade upgrade );
140 |
141 | /**
142 | * Returns the peripheral created by the upgrade on the specified side of the turtle, if there is one.
143 | * @return the peripheral created by the upgrade on the specified side of the turtle, if there is one.
144 | */
145 | public IPeripheral getPeripheral( TurtleSide side );
146 |
147 | /**
148 | * TODO: Document me
149 | */
150 | public NBTTagCompound getUpgradeNBTData( TurtleSide side );
151 |
152 | /**
153 | * TODO: Document me
154 | */
155 | public void updateUpgradeNBTData( TurtleSide side );
156 | }
157 |
--------------------------------------------------------------------------------
/src/api/java/dan200/computercraft/api/turtle/ITurtleCommand.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This file is part of the public ComputerCraft API - http://www.computercraft.info
3 | * Copyright Daniel Ratcliffe, 2011-2014. This API may be redistributed unmodified and in full only.
4 | * For help using the API, and posting your mods, visit the forums at computercraft.info.
5 | */
6 |
7 | package dan200.computercraft.api.turtle;
8 |
9 | /**
10 | * An interface for objects executing custom turtle commands, used with ITurtleAccess.issueCommand
11 | * @see ITurtleAccess#executeCommand(dan200.computercraft.api.lua.ILuaContext,ITurtleCommand)
12 | */
13 | public interface ITurtleCommand
14 | {
15 | /**
16 | * Will be called by the turtle on the main thread when it is time to execute the custom command.
17 | * The handler should either perform the work of the command, and return success, or return
18 | * failure with an error message to indicate the command cannot be executed at this time.
19 | * @param turtle access to the turtle for whom the command was issued
20 | * @return TurtleCommandResult.success() or TurtleCommandResult.failure( errorMessage )
21 | * @see ITurtleAccess#executeCommand(dan200.computercraft.api.lua.ILuaContext,ITurtleCommand)
22 | * @see dan200.computercraft.api.turtle.TurtleCommandResult
23 | */
24 | public TurtleCommandResult execute( ITurtleAccess turtle );
25 | }
26 |
--------------------------------------------------------------------------------
/src/api/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This file is part of the public ComputerCraft API - http://www.computercraft.info
3 | * Copyright Daniel Ratcliffe, 2011-2014. This API may be redistributed unmodified and in full only.
4 | * For help using the API, and posting your mods, visit the forums at computercraft.info.
5 | */
6 |
7 | package dan200.computercraft.api.turtle;
8 |
9 | import dan200.computercraft.api.peripheral.IPeripheral;
10 | import net.minecraft.item.ItemStack;
11 | import net.minecraft.util.IIcon;
12 |
13 | /**
14 | * The primary interface for defining an turtle for Turtles. A turtle turtle
15 | * can either be a new tool, or a new peripheral.
16 | * @see dan200.computercraft.api.ComputerCraftAPI#registerTurtleUpgrade( dan200.computercraft.api.turtle.ITurtleUpgrade )
17 | */
18 | public interface ITurtleUpgrade
19 | {
20 | /**
21 | * Gets a unique numerical identifier representing this type of turtle turtle.
22 | * Like Minecraft common and item IDs, you should strive to make this number unique
23 | * among all turtle turtle that have been released for ComputerCraft.
24 | * The ID must be in the range 64 to 255, as the ID is stored as an 8-bit value,
25 | * and 0-64 is reserved for future use by ComputerCraft. The turtle will
26 | * fail registration if an already used ID is specified.
27 | * @see dan200.computercraft.api.ComputerCraftAPI#registerTurtleUpgrade( dan200.computercraft.api.turtle.ITurtleUpgrade )
28 | */
29 | public int getUpgradeID();
30 |
31 | /**
32 | * Return a String to describe this type of turtle in turtle item names.
33 | * Examples of built-in adjectives are "Wireless", "Mining" and "Crafty".
34 | */
35 | public String getUnlocalisedAdjective();
36 |
37 | /**
38 | * Return whether this turtle adds a tool or a peripheral to the turtle.
39 | * Currently, turtle crafting is restricted to one tool & one peripheral per turtle.
40 | * @see TurtleUpgradeType for the differences between the two.
41 | */
42 | public TurtleUpgradeType getType();
43 |
44 | /**
45 | * Return an item stack representing the type of item that a turtle must be crafted
46 | * with to create a turtle which holds this turtle.
47 | * Currently, turtle crafting is restricted to one tool & one peripheral per turtle.
48 | */
49 | public ItemStack getCraftingItem();
50 |
51 | /**
52 | * Will only be called for Peripheral turtle. Creates a peripheral for a turtle
53 | * being placed using this turtle. The peripheral created will be stored
54 | * for the lifetime of the turtle, will have update() called once-per-tick, and will be
55 | * attach'd detach'd and have methods called in the same manner as a Computer peripheral.
56 | *
57 | * @param turtle Access to the turtle that the peripheral is being created for.
58 | * @param side Which side of the turtle (left or right) that the turtle resides on.
59 | * @return The newly created peripheral. You may return null if this turtle is a Tool
60 | * and this method is not expected to be called.
61 | */
62 | public IPeripheral createPeripheral( ITurtleAccess turtle, TurtleSide side );
63 |
64 | /**
65 | * Will only be called for Tool turtle. Called when turtle.dig() or turtle.attack() is called
66 | * by the turtle, and the tool is required to do some work.
67 | * @param turtle Access to the turtle that the tool resides on.
68 | * @param side Which side of the turtle (left or right) the tool resides on.
69 | * @param verb Which action (dig or attack) the turtle is being called on to perform.
70 | * @param direction Which world direction the action should be performed in, relative to the turtles
71 | * position. This will either be up, down, or the direction the turtle is facing, depending on
72 | * whether dig, digUp or digDown was called.
73 | * @return Whether the turtle was able to perform the action, and hence whether the turtle.dig()
74 | * or turtle.attack() lua method should return true. If true is returned, the tool will perform
75 | * a swinging animation. You may return null if this turtle is a Peripheral
76 | * and this method is not expected to be called.
77 | */
78 | public TurtleCommandResult useTool( ITurtleAccess turtle, TurtleSide side, TurtleVerb verb, int direction );
79 |
80 | /**
81 | * Called to obtain the IIcon to be used when rendering a turtle peripheral. Needs to be a "common"
82 | * type IIcon for now, as there is no way to determine which texture sheet an IIcon is from by the
83 | * IIcon itself.
84 | * @param turtle Access to the turtle that the peripheral resides on.
85 | * @param side Which side of the turtle (left or right) the peripheral resides on.
86 | * @return The IIcon that you wish to be used to render your turtle peripheral.
87 | */
88 | public IIcon getIcon( ITurtleAccess turtle, TurtleSide side );
89 |
90 | /**
91 | * TODO: Document me
92 | */
93 | public void update( ITurtleAccess turtle, TurtleSide side );
94 | }
95 |
--------------------------------------------------------------------------------
/src/api/java/dan200/computercraft/api/turtle/TurtleAnimation.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This file is part of the public ComputerCraft API - http://www.computercraft.info
3 | * Copyright Daniel Ratcliffe, 2011-2014. This API may be redistributed unmodified and in full only.
4 | * For help using the API, and posting your mods, visit the forums at computercraft.info.
5 | */
6 |
7 | package dan200.computercraft.api.turtle;
8 |
9 | public enum TurtleAnimation
10 | {
11 | None,
12 | MoveForward,
13 | MoveBack,
14 | MoveUp,
15 | MoveDown,
16 | TurnLeft,
17 | TurnRight,
18 | SwingLeftTool,
19 | SwingRightTool,
20 | Wait,
21 | }
22 |
--------------------------------------------------------------------------------
/src/api/java/dan200/computercraft/api/turtle/TurtleCommandResult.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This file is part of the public ComputerCraft API - http://www.computercraft.info
3 | * Copyright Daniel Ratcliffe, 2011-2014. This API may be redistributed unmodified and in full only.
4 | * For help using the API, and posting your mods, visit the forums at computercraft.info.
5 | */
6 |
7 | package dan200.computercraft.api.turtle;
8 |
9 | public final class TurtleCommandResult
10 | {
11 | private static final TurtleCommandResult s_success = new TurtleCommandResult( true, null );
12 | private static final TurtleCommandResult s_emptyFailure = new TurtleCommandResult( false, null );
13 |
14 | public static TurtleCommandResult success()
15 | {
16 | return s_success;
17 | }
18 |
19 | public static TurtleCommandResult failure()
20 | {
21 | return failure( null );
22 | }
23 |
24 | public static TurtleCommandResult failure( String errorMessage )
25 | {
26 | if( errorMessage != null )
27 | {
28 | return new TurtleCommandResult( false, errorMessage );
29 | }
30 | else
31 | {
32 | return s_emptyFailure;
33 | }
34 | }
35 |
36 | private final boolean m_success;
37 | private final String m_errorMessage;
38 |
39 | private TurtleCommandResult( boolean success, String errorMessage )
40 | {
41 | m_success = success;
42 | m_errorMessage = errorMessage;
43 | }
44 |
45 | public boolean isSuccess()
46 | {
47 | return m_success;
48 | }
49 |
50 | public String getErrorMessage()
51 | {
52 | return m_errorMessage;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/api/java/dan200/computercraft/api/turtle/TurtleSide.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This file is part of the public ComputerCraft API - http://www.computercraft.info
3 | * Copyright Daniel Ratcliffe, 2011-2014. This API may be redistributed unmodified and in full only.
4 | * For help using the API, and posting your mods, visit the forums at computercraft.info.
5 | */
6 |
7 | package dan200.computercraft.api.turtle;
8 |
9 | /**
10 | * An enum representing the two sides of the turtle that a turtle turtle might reside.
11 | */
12 | public enum TurtleSide
13 | {
14 | /**
15 | * The turtles left side (where the pickaxe usually is on a Wireless Mining Turtle)
16 | */
17 | Left,
18 |
19 | /**
20 | * The turtles right side (where the modem usually is on a Wireless Mining Turtle)
21 | */
22 | Right,
23 | }
24 |
--------------------------------------------------------------------------------
/src/api/java/dan200/computercraft/api/turtle/TurtleUpgradeType.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This file is part of the public ComputerCraft API - http://www.computercraft.info
3 | * Copyright Daniel Ratcliffe, 2011-2014. This API may be redistributed unmodified and in full only.
4 | * For help using the API, and posting your mods, visit the forums at computercraft.info.
5 | */
6 |
7 | package dan200.computercraft.api.turtle;
8 |
9 | /**
10 | * An enum representing the two different types of turtle that an ITurtleUpgrade
11 | * implementation can add to a turtle.
12 | * @see ITurtleUpgrade
13 | */
14 | public enum TurtleUpgradeType
15 | {
16 | /**
17 | * A tool is rendered as an item on the side of the turtle, and responds to the turtle.dig()
18 | * and turtle.attack() methods (Such as pickaxe or sword on Mining and Melee turtles).
19 | */
20 | Tool,
21 |
22 | /**
23 | * A peripheral adds a special peripheral which is attached to the side of the turtle,
24 | * and can be interacted with the peripheral API (Such as the modem on Wireless Turtles).
25 | */
26 | Peripheral,
27 | }
28 |
--------------------------------------------------------------------------------
/src/api/java/dan200/computercraft/api/turtle/TurtleVerb.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This file is part of the public ComputerCraft API - http://www.computercraft.info
3 | * Copyright Daniel Ratcliffe, 2011-2014. This API may be redistributed unmodified and in full only.
4 | * For help using the API, and posting your mods, visit the forums at computercraft.info.
5 | */
6 |
7 | package dan200.computercraft.api.turtle;
8 |
9 | /**
10 | * An enum representing the two different actions that an ITurtleUpgrade of type
11 | * Tool may be called on to perform by a turtle.
12 | * @see ITurtleUpgrade
13 | * @see ITurtleUpgrade#useTool
14 | */
15 | public enum TurtleVerb
16 | {
17 | /**
18 | * The turtle called turtle.dig(), turtle.digUp() or turtle.digDown()
19 | */
20 | Dig,
21 |
22 | /**
23 | * The turtle called turtle.attack(), turtle.attackUp() or turtle.attackDown()
24 | */
25 | Attack,
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/Block/BlockRadio.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.Block;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Random;
5 |
6 | import net.minecraft.block.Block;
7 | import net.minecraft.block.ITileEntityProvider;
8 | import net.minecraft.block.material.Material;
9 | import net.minecraft.client.renderer.texture.IIconRegister;
10 | import net.minecraft.entity.EntityLivingBase;
11 | import net.minecraft.entity.item.EntityItem;
12 | import net.minecraft.entity.player.EntityPlayer;
13 | import net.minecraft.init.Blocks;
14 | import net.minecraft.inventory.IInventory;
15 | import net.minecraft.item.Item;
16 | import net.minecraft.item.ItemStack;
17 | import net.minecraft.nbt.NBTTagCompound;
18 | import net.minecraft.server.MinecraftServer;
19 | import net.minecraft.tileentity.TileEntity;
20 | import net.minecraft.util.IIcon;
21 | import net.minecraft.util.MathHelper;
22 | import net.minecraft.world.IBlockAccess;
23 | import net.minecraft.world.World;
24 | import pcl.OpenFM.OpenFM;
25 | import pcl.OpenFM.GUI.GuiRadioBase;
26 | import pcl.OpenFM.TileEntity.TileEntityRadio;
27 | import cpw.mods.fml.client.FMLClientHandler;
28 | import cpw.mods.fml.common.FMLCommonHandler;
29 | import cpw.mods.fml.relauncher.Side;
30 | import cpw.mods.fml.relauncher.SideOnly;
31 | import cpw.mods.fml.common.Optional;
32 | import dan200.computercraft.api.peripheral.IPeripheral;
33 | import dan200.computercraft.api.peripheral.IPeripheralProvider;
34 |
35 | @Optional.InterfaceList({
36 | @Optional.Interface(iface = "dan200.computercraft.api.peripheral.IPeripheralProvider", modid = "ComputerCraft"),
37 | })
38 | public class BlockRadio extends Block implements ITileEntityProvider, IPeripheralProvider {
39 |
40 | @SideOnly(Side.CLIENT)
41 | public static IIcon sideIcon;
42 | @SideOnly(Side.CLIENT)
43 | public static IIcon frontIcon;
44 | public GuiRadioBase guiRadio;
45 | private Random random;
46 |
47 | public BlockRadio()
48 | {
49 | super(Material.wood);
50 | setHardness(2.0F);
51 | setResistance(10.0F);
52 | setBlockName("OpenFM.Radio");
53 | setStepSound(Block.soundTypeWood);
54 | random = new Random();
55 | }
56 |
57 |
58 | @SideOnly(Side.CLIENT)
59 | public void registerBlockIcons(IIconRegister ir)
60 | {
61 | sideIcon = ir.registerIcon("openfm:radio_side");
62 | frontIcon = ir.registerIcon("openfm:radio_front");
63 | }
64 |
65 | @SideOnly(Side.CLIENT)
66 | public IIcon getIcon(int side, int meta)
67 | {
68 | switch (side)
69 | {
70 | case 2:
71 | if (meta == 1) {
72 | return frontIcon;
73 | }
74 | return sideIcon;
75 | case 3:
76 | if (meta == 0 || meta == 3)
77 | return frontIcon;
78 |
79 | return sideIcon;
80 | case 4:
81 | if (meta == 4){
82 | return frontIcon;
83 | }
84 | return sideIcon;
85 | case 5:
86 | if (meta == 2){
87 | return frontIcon;
88 | }
89 | return sideIcon;
90 | }
91 | return sideIcon;
92 | }
93 |
94 | @Override
95 | public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int metadata, float clickX, float clickY, float clickZ) {
96 | TileEntity tileEntity = world.getTileEntity(x, y, z);
97 | if (tileEntity == null || player.isSneaking()) {
98 | return false;
99 | }
100 | player.openGui(OpenFM.instance, 0, world, x, y, z);
101 | return true;
102 | }
103 |
104 | @Override
105 | public void breakBlock(World world, int x, int y, int z, Block block, int p_149749_6_) {
106 | TileEntityRadio t = (TileEntityRadio)world.getTileEntity(x, y, z);
107 | if(t==null)
108 | return;
109 |
110 | dropContent(t, world, t.xCoord, t.yCoord, t.zCoord);
111 | ArrayList items = new ArrayList();
112 | if (t instanceof TileEntityRadio) {
113 | if (t.stations.size() > 0) {
114 | ItemStack stack = new ItemStack(block, 1);
115 |
116 | if (!stack.hasTagCompound()) {
117 | stack.setTagCompound(new NBTTagCompound());
118 | }
119 | if(t.streamURL != null)
120 | stack.getTagCompound().setString("streamurl", t.streamURL);
121 | if(t.getScreenText() != null)
122 | stack.getTagCompound().setString("screenText", t.getScreenText());
123 | stack.getTagCompound().setInteger("screenColor", t.getScreenColor());
124 | for(int i = 0; i < t.getStationCount(); i++)
125 | {
126 | if (t.stations.get(i) != null) {
127 | stack.getTagCompound().setString("station" + i, t.stations.get(i));
128 | stack.getTagCompound().setInteger("stationCount", i + 1);
129 | }
130 | }
131 | items.add(stack);
132 | world.spawnEntityInWorld(new EntityItem(world, x, y, z, items.get(0)));
133 | world.setBlock(x, y, z, Blocks.air);
134 | }
135 | }
136 | }
137 |
138 | @Override
139 | public Item getItemDropped(int meta, Random random, int fortune) {
140 | return null;
141 | }
142 |
143 | @Override
144 | public void onBlockPlacedBy(World par1World, int par2, int par3, int par4, EntityLivingBase par5EntityLiving, ItemStack par6ItemStack) {
145 | int l = MathHelper.floor_double(par5EntityLiving.rotationYaw * 4.0F / 360.0F + 0.5D) & 0x3;
146 | par1World.setBlockMetadataWithNotify(par2, par3, par4, l + 1, 2);
147 | TileEntity te = par1World.getTileEntity(par2, par3, par4);
148 | ((TileEntityRadio) te).owner = par5EntityLiving.getUniqueID().toString();
149 | }
150 |
151 | public boolean canConnectRedstone(IBlockAccess world, int x, int y, int z, int side) {
152 | return true;
153 | }
154 |
155 | public void onNeighborBlockChange(World world, int x, int y, int z, Block block) {
156 | boolean flag = world.isBlockIndirectlyGettingPowered(x, y, z);
157 | try {
158 | Side side = FMLCommonHandler.instance().getEffectiveSide();
159 | if (block.canProvidePower()) {
160 | TileEntity tileEntity;
161 | if (side == Side.SERVER) {
162 | tileEntity = MinecraftServer.getServer().getEntityWorld().getTileEntity(x, y, z);
163 | } else {
164 | tileEntity = FMLClientHandler.instance().getClient().theWorld.getTileEntity(x, y, z);
165 | }
166 | ((TileEntityRadio)tileEntity).setRedstoneInput(flag);
167 | }
168 | }
169 | catch (Exception localException) { }
170 | }
171 |
172 | public void dropContent(IInventory chest, World world, int xCoord, int yCoord, int zCoord) {
173 | if (chest == null)
174 | return;
175 |
176 | for (int i1 = 0; i1 < chest.getSizeInventory(); ++i1) {
177 | ItemStack itemstack = chest.getStackInSlot(i1);
178 |
179 | if (itemstack != null) {
180 | float offsetX = random.nextFloat() * 0.8F + 0.1F;
181 | float offsetY = random.nextFloat() * 0.8F + 0.1F;
182 | float offsetZ = random.nextFloat() * 0.8F + 0.1F;
183 | EntityItem entityitem;
184 |
185 | for (; itemstack.stackSize > 0; world.spawnEntityInWorld(entityitem)) {
186 | int stackSize = random.nextInt(21) + 10;
187 | if (stackSize > itemstack.stackSize)
188 | stackSize = itemstack.stackSize;
189 |
190 | itemstack.stackSize -= stackSize;
191 | entityitem = new EntityItem(world, (double)((float)xCoord + offsetX), (double)((float)yCoord + offsetY), (double)((float)zCoord + offsetZ), new ItemStack(itemstack.getItem(), stackSize, itemstack.getItemDamage()));
192 |
193 | float velocity = 0.05F;
194 | entityitem.motionX = (double)((float)random.nextGaussian() * velocity);
195 | entityitem.motionY = (double)((float)random.nextGaussian() * velocity + 0.2F);
196 | entityitem.motionZ = (double)((float)random.nextGaussian() * velocity);
197 |
198 | if (itemstack.hasTagCompound())
199 | entityitem.getEntityItem().setTagCompound((NBTTagCompound)itemstack.getTagCompound().copy());
200 | }
201 | }
202 | }
203 | }
204 |
205 | public boolean shouldCheckWeakPower(IBlockAccess world, int x, int y, int z, int side) {
206 | return true;
207 | }
208 |
209 | public TileEntity createNewTileEntity(World world, int meta) {
210 | return new TileEntityRadio(world);
211 | }
212 |
213 |
214 | // IPeripheralProvider
215 | @Optional.Method(modid = "ComputerCraft")
216 | @Override
217 | public IPeripheral getPeripheral(World world, int x, int y, int z, int side) {
218 | TileEntity te = world.getTileEntity(x, y, z);
219 |
220 | if(te instanceof TileEntityRadio)
221 | return (IPeripheral)te;
222 |
223 | return null;
224 | }
225 | }
226 |
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/Block/BlockSpeaker.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.Block;
2 |
3 | import net.minecraft.block.Block;
4 | import net.minecraft.block.ITileEntityProvider;
5 | import net.minecraft.block.material.Material;
6 | import net.minecraft.client.renderer.texture.IIconRegister;
7 | import net.minecraft.entity.EntityLivingBase;
8 | import net.minecraft.item.ItemStack;
9 | import net.minecraft.tileentity.TileEntity;
10 | import net.minecraft.util.IIcon;
11 | import net.minecraft.util.MathHelper;
12 | import net.minecraft.world.World;
13 | import pcl.OpenFM.TileEntity.TileEntitySpeaker;
14 | import cpw.mods.fml.relauncher.Side;
15 | import cpw.mods.fml.relauncher.SideOnly;
16 |
17 | public class BlockSpeaker extends Block implements ITileEntityProvider {
18 |
19 | @SideOnly(Side.CLIENT)
20 | public static IIcon sideIcon;
21 | @SideOnly(Side.CLIENT)
22 | public static IIcon rearIcon;
23 |
24 | public BlockSpeaker() {
25 | super(Material.wood);
26 | setHardness(2.0F);
27 | setResistance(10.0F);
28 | setBlockName("OpenFM.Speaker");
29 | setStepSound(Block.soundTypeWood);
30 | }
31 |
32 | @SideOnly(Side.CLIENT)
33 | public void registerBlockIcons(IIconRegister ir) {
34 | sideIcon = ir.registerIcon("openfm:speaker_side");
35 | rearIcon = ir.registerIcon("openfm:speaker_rear");
36 | }
37 |
38 | @SideOnly(Side.CLIENT)
39 | public IIcon getIcon(int side, int meta) {
40 |
41 | switch (side) {
42 | case 2:
43 | if (meta == 1) {
44 | return rearIcon;
45 | }
46 | return sideIcon;
47 | case 3:
48 | if (meta == 0 || meta == 3) {
49 | return rearIcon;
50 | }
51 | return sideIcon;
52 | case 4:
53 | if (meta == 4) {
54 | return rearIcon;
55 | }
56 | return sideIcon;
57 | case 5:
58 | if (meta == 2) {
59 | return rearIcon;
60 | }
61 | return sideIcon;
62 | }
63 | return sideIcon;
64 | }
65 |
66 | public void onBlockPlacedBy(World world, int x, int y, int z, EntityLivingBase player, ItemStack itemStack) {
67 | int dir = MathHelper.floor_double(player.rotationYaw * 4.0F / 360.0F + 0.5D) & 0x3;
68 | world.setBlockMetadataWithNotify(x, y, z, dir + 1, 2);
69 | }
70 |
71 | public TileEntity createNewTileEntity(World world, int metadata) {
72 | return new TileEntitySpeaker();
73 | }
74 | }
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/BuildInfo.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM;
2 |
3 | /**
4 | * This file is automatically updated by Jenkins as part of the CI build script
5 | * in Ant. Don't put any pre-set values here.
6 | *
7 | * @author AfterLifeLochie, stolen from LanteaCraft, another fine PC-Logix Minecraft mod.
8 | */
9 | public class BuildInfo {
10 | public static final String modName = "OpenFM";
11 | public static final String modID = "openfm";
12 |
13 | public static final String versionNumber = "@VERSION@";
14 | public static final String buildNumber = "@BUILD@";
15 |
16 | public static int getBuildNumber() {
17 | if (buildNumber.equals("@" + "BUILD" + "@"))
18 | return 0;
19 | return Integer.parseInt(buildNumber);
20 | }
21 |
22 | public static boolean isDevelopmentEnvironment() {
23 | return getBuildNumber() == 0;
24 | }
25 | }
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/ClientProxy.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM;
2 |
3 | import cpw.mods.fml.client.registry.ClientRegistry;
4 | import pcl.OpenFM.TileEntity.RadioRenderer;
5 | import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
6 |
7 | public class ClientProxy extends CommonProxy {
8 |
9 | public void registerRenderers() {
10 | TileEntitySpecialRenderer radioRenderer = new RadioRenderer();
11 | ClientRegistry.bindTileEntitySpecialRenderer(pcl.OpenFM.TileEntity.TileEntityRadio.class, radioRenderer);
12 | OpenFM.logger.info("Registering TESR");
13 | }
14 |
15 | public void initTileEntities() {}
16 | }
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/CommonProxy.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM;
2 |
3 | public class CommonProxy{
4 | public void registerRenderers() {}
5 |
6 | public void initTileEntities() {}
7 |
8 | }
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/ConnectionHandler.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM;
2 |
3 | public class ConnectionHandler {}
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/ContentRegistry.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM;
2 |
3 | import net.minecraft.block.Block;
4 | import net.minecraft.creativetab.CreativeTabs;
5 | import net.minecraft.init.Blocks;
6 | import net.minecraft.init.Items;
7 | import net.minecraft.item.Item;
8 | import net.minecraft.item.ItemStack;
9 | import net.minecraft.util.StatCollector;
10 | import net.minecraft.world.World;
11 | import net.minecraftforge.common.MinecraftForge;
12 | import pcl.OpenFM.Block.BlockRadio;
13 | import pcl.OpenFM.Block.BlockSpeaker;
14 | import pcl.OpenFM.Handler.OFMBreakEvent;
15 | import pcl.OpenFM.Items.ItemBlockRadio;
16 | import pcl.OpenFM.Items.ItemMemoryCard;
17 | import pcl.OpenFM.Items.ItemTuner;
18 | import pcl.OpenFM.TileEntity.TileEntityRadio;
19 | import pcl.OpenFM.TileEntity.TileEntitySpeaker;
20 | import cpw.mods.fml.common.registry.GameRegistry;
21 | import cpw.mods.fml.relauncher.Side;
22 | import cpw.mods.fml.relauncher.SideOnly;
23 | import cpw.mods.fml.common.Loader;
24 | import dan200.computercraft.api.ComputerCraftAPI;
25 | import dan200.computercraft.api.peripheral.IPeripheralProvider;
26 |
27 | public class ContentRegistry {
28 |
29 |
30 | // Blocks
31 | public static Block blockRadio;
32 | public static Block blockSpeaker;
33 |
34 | // Items
35 | public static Item itemRadioTuner;
36 | public static Item itemMemoryCard;
37 |
38 | // Tabs
39 | public static CreativeTabs creativeTab;
40 |
41 | // Called on mod init()
42 | public static void init() {
43 | registerTabs();
44 | registerBlocks();
45 | registerItems();
46 | registerEvents();
47 | if (Loader.isModLoaded("ComputerCraft")) {
48 | ComputerCraftAPI.registerPeripheralProvider((IPeripheralProvider) blockRadio);
49 | }
50 | }
51 |
52 | public static void registerBlocks() {
53 |
54 | blockRadio = new BlockRadio();
55 | GameRegistry.registerBlock(blockRadio, ItemBlockRadio.class, "Radio");
56 | GameRegistry.registerTileEntity(TileEntityRadio.class, "OpenFMRadio");
57 | GameRegistry.addRecipe(new ItemStack(blockRadio), " y", "xyx", "xzx",
58 | 'x', new ItemStack(Blocks.planks),
59 | 'y', new ItemStack(Items.iron_ingot),
60 | 'z', new ItemStack(Items.diamond));
61 | blockRadio.setCreativeTab(creativeTab);
62 |
63 | blockSpeaker = new BlockSpeaker();
64 | GameRegistry.registerBlock(blockSpeaker, "Speaker");
65 | GameRegistry.registerTileEntity(TileEntitySpeaker.class, "OpenFMSpeaker");
66 | GameRegistry.addRecipe(new ItemStack(blockSpeaker), "xxx", "xyx", "xzx",
67 | 'x', new ItemStack(Blocks.planks),
68 | 'y', new ItemStack(Items.iron_ingot),
69 | 'z', new ItemStack(Items.redstone));
70 | blockSpeaker.setCreativeTab(creativeTab);
71 | }
72 |
73 | public static void registerItems() {
74 |
75 | itemRadioTuner = new ItemTuner();
76 | GameRegistry.registerItem(itemRadioTuner, "RadioTuner");
77 | itemRadioTuner.setCreativeTab(creativeTab);
78 | GameRegistry.addRecipe(new ItemStack(itemRadioTuner), " x", " y", " z",
79 | 'x', new ItemStack(Items.redstone),
80 | 'y', new ItemStack(Items.redstone),
81 | 'z', new ItemStack(Items.stick));
82 |
83 | itemMemoryCard = new ItemMemoryCard();
84 | GameRegistry.registerItem(itemMemoryCard, "MemoryCard");
85 | itemMemoryCard.setCreativeTab(creativeTab);
86 | GameRegistry.addRecipe(new ItemStack(itemMemoryCard), " x", " y", " z",
87 | 'x', new ItemStack(Items.redstone),
88 | 'y', new ItemStack(Items.redstone),
89 | 'z', new ItemStack(Items.paper));
90 |
91 | }
92 |
93 | public static void registerEvents() {
94 | MinecraftForge.EVENT_BUS.register(new OFMBreakEvent());
95 | }
96 |
97 | public static void registerTabs() {
98 |
99 | creativeTab = new CreativeTabs("tabOpenFM") {
100 | @SideOnly(Side.CLIENT)
101 | public Item getTabIconItem() {
102 | return Item.getItemFromBlock(blockRadio);
103 | }
104 |
105 | @SideOnly(Side.CLIENT)
106 | public String getTranslatedTabLabel() {
107 | return StatCollector.translateToLocal("itemGroup.OpenFM.tabOpenFM");
108 | }
109 | };
110 | }
111 |
112 | public static boolean checkBlock(World w, int x, int y, int z) {
113 | return (w.getBlock(x, y, z) instanceof BlockRadio);
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/GUI/GuiRadio.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.GUI;
2 |
3 | import java.util.Arrays;
4 | import java.util.List;
5 |
6 | import com.squareup.okhttp.HttpUrl;
7 |
8 | import cpw.mods.fml.relauncher.Side;
9 | import cpw.mods.fml.relauncher.SideOnly;
10 | import net.minecraft.client.Minecraft;
11 | import net.minecraft.entity.player.InventoryPlayer;
12 | import net.minecraft.util.StatCollector;
13 | import pcl.OpenFM.OFMConfiguration;
14 | import pcl.OpenFM.TileEntity.TileEntityRadio;
15 | import pcl.OpenFM.network.PacketHandler;
16 | import pcl.OpenFM.network.message.*;
17 |
18 | public class GuiRadio extends GuiRadioBase {
19 | private OFMGuiButton playBtn;
20 | protected OFMGuiTextField streamTextBox;
21 | protected OFMGuiTextField volumeBox;
22 | protected OFMGuiTextField colorBox;
23 | private OFMGuiButton redstoneBtn;
24 | private OFMGuiButton lockedBtn;
25 | private OFMGuiTextField screenTextBox;
26 | private OFMGuiButton updateColor;
27 | private OFMGuiButton updateText;
28 | private OFMGuiButton saveToMemoryCard;
29 | private OFMGuiButton loadFromMemoryCard;
30 |
31 | public GuiRadio(InventoryPlayer inventoryPlayer, TileEntityRadio TERadio) {
32 | super(inventoryPlayer, TERadio);
33 | }
34 |
35 | @Override
36 | @SuppressWarnings("unchecked")
37 | public void initGui() {
38 | super.initGui();
39 |
40 | org.lwjgl.input.Keyboard.enableRepeatEvents(true);
41 |
42 | this.OFMbuttonList.clear();
43 |
44 | this.playBtn = new OFMGuiButton(0, this.width / 2 - 12, this.height / 2 + 28 - 5 - 45, 24, 24, 0, 0, "", OFMGuiButton.guiLocation); //Play
45 | this.OFMbuttonList.add(this.playBtn);
46 |
47 | this.OFMbuttonList.add(new OFMGuiButton(1, this.width / 2 + 12, this.height / 2 + 3 - 5 - 45, 10, 10, 58, 24, "", OFMGuiButton.guiLocation)); //VolDown
48 | this.OFMbuttonList.add(new OFMGuiButton(2, this.width / 2 - 22, this.height / 2 + 3 - 5 - 45, 10, 10, 48, 24, "", OFMGuiButton.guiLocation)); //VolUp
49 |
50 | this.OFMbuttonList.add(new OFMGuiButton(3, this.width / 2 - 107, this.height / 2 + 15 - 5 - 45, 6, 12, 75, 24, "", OFMGuiButton.guiLocation)); //Scroll Left
51 | this.OFMbuttonList.add(new OFMGuiButton(4, this.width / 2 + 101, this.height / 2 + 15 - 5 - 45, 6, 12, 81, 24, "", OFMGuiButton.guiLocation)); //Scroll Right
52 |
53 | this.OFMbuttonList.add(new OFMGuiButton(5, this.width / 2 - 12 - 50, this.height / 2 + 31 - 5 - 45, 48, 8, 48, 0, "", OFMGuiButton.guiLocation)); //Clear
54 | this.OFMbuttonList.add(new OFMGuiButton(6, this.width / 2 - 12 - 51, this.height / 2 + 41 - 5 - 45, 49, 8, 96, 1, "", OFMGuiButton.guiLocation)); //Paste
55 |
56 | this.OFMbuttonList.add(new OFMGuiButton(7, this.width / 2 + 12 + 2, this.height / 2 + 33 - 5 - 45, 42, 6, 145, 0, "", OFMGuiButton.guiLocation)); //Save
57 | this.OFMbuttonList.add(new OFMGuiButton(8, this.width / 2 + 12 + 2, this.height / 2 + 40 - 5 - 45, 54, 8, 187, 0, "", OFMGuiButton.guiLocation)); //Delete
58 |
59 | this.OFMbuttonList.add(new OFMGuiButton(9, this.width / 2 + 100, this.height / 2 + 3 - 5 - 45, 7, 8, 68, 24, "", OFMGuiButton.guiLocation)); //Close
60 |
61 | if (!this.redstoneButtonState) {
62 | this.redstoneBtn = new OFMGuiButton(10, this.width / 2 + 100 - 13, this.height / 2 + 3 - 5 - 45, 8, 8, 87, 24, "", OFMGuiButton.guiLocation); //Redstone
63 | } else {
64 | this.redstoneBtn = new OFMGuiButton(10, this.width / 2 + 100 - 13, this.height / 2 + 3 - 5 - 45, 8, 8, 95, 24, "", OFMGuiButton.guiLocation); //Redstone
65 | }
66 |
67 | if (!this.lockedButtonState) {
68 | this.lockedBtn = new OFMGuiButton(11, this.width / 2 + 100 - 4, this.height / 2 + 30 - 45, 12, 16, 115, 24, "", OFMGuiButton.guiLocation); //Locked
69 | } else {
70 | this.lockedBtn = new OFMGuiButton(11, this.width / 2 + 100 - 4, this.height / 2 + 30 - 45, 12, 16, 103, 24, "", OFMGuiButton.guiLocation); //Locked
71 | }
72 |
73 | if (this.radio.getWorldObj().provider.dimensionId == 0) {
74 | this.OFMbuttonList.add(this.redstoneBtn);
75 | }
76 |
77 | this.OFMbuttonList.add(this.lockedBtn);
78 |
79 | this.updateColor = new OFMGuiButton(12, 0, 0, 0, 0, 0, 0, "", OFMGuiButton.guiLocation); //Update Color
80 | this.OFMbuttonList.add(this.updateColor);
81 | this.updateText = new OFMGuiButton(13, 0, 0, 0, 0, 0, 0, "", OFMGuiButton.guiLocation); //Update Text
82 | this.OFMbuttonList.add(this.updateText);
83 |
84 | this.streamTextBox = new OFMGuiTextField(this.fontRendererObj, this.width / 2 - 100, this.height / 2 - 5 + 17 - 45, 200, 20);
85 | this.streamTextBox.setMaxStringLength(1000);
86 |
87 | if (!(this.radio.streamURL == null) && !this.radio.streamURL.equals("")) {
88 | this.streamTextBox.setText(this.radio.streamURL);
89 | } else {
90 | this.streamTextBox.setText(OFMConfiguration.defaultURL);
91 | }
92 |
93 | this.volumeBox = new OFMGuiTextField(this.fontRendererObj, this.width / 2 - 6, this.height / 2 - 5 + 4 - 45, 50, 20);
94 | this.volumeBox.setMaxStringLength(2);
95 |
96 | this.colorBox = new OFMGuiTextField(this.fontRendererObj, this.width / 2 - 97, this.height / 2 - 5 + 72 - 45, 200, 20);
97 | this.colorBox.setText(toHexString(this.radio.getScreenColor()));
98 | this.colorBox.setTextColor(this.radio.getScreenColor());
99 | this.colorBox.setMaxStringLength(6);
100 |
101 | this.screenTextBox = new OFMGuiTextField(this.fontRendererObj, this.width / 2 - 17, this.height / 2 - 5 + 72 - 45, 200, 20);
102 | this.screenTextBox.setText(this.radio.getScreenText());
103 | this.screenTextBox.setTextColor(this.radio.getScreenColor());
104 |
105 |
106 | this.saveToMemoryCard = new OFMGuiButton(15, this.width / 2 - 12 - 83, this.height / 2 + 31 - 5 - 40, 8, 8, 127, 24, "", OFMGuiButton.guiLocation); //Update Color
107 | this.OFMbuttonList.add(this.saveToMemoryCard);
108 | this.loadFromMemoryCard = new OFMGuiButton(16, this.width / 2 - 12 - 83, this.height / 2 + 41 - 5 - 40, 8, 8, 135, 24, "", OFMGuiButton.guiLocation); //Update Text
109 | this.OFMbuttonList.add(this.loadFromMemoryCard);
110 |
111 |
112 | }
113 |
114 | public static String toHexString(int decimal) {
115 | return String.format("%06X", (0xFFFFFF & decimal));
116 | }
117 |
118 | @Override
119 | @SuppressWarnings("unchecked")
120 | public void updateScreen() {
121 | super.updateScreen();
122 |
123 | this.streamTextBox.updateCursorCounter();
124 | this.volumeBox.updateCursorCounter();
125 | this.colorBox.updateCursorCounter();
126 |
127 | if (this.radio.isInvalid()) {
128 | this.mc.displayGuiScreen((net.minecraft.client.gui.GuiScreen)null);
129 | this.mc.setIngameFocus();
130 | }
131 |
132 | this.volumeBox.setText(" " + (int)(this.radio.getVolume() * 10.0F));
133 |
134 | if ((this.radio.isPlaying()) && (!this.playButtonPlayingState)) {
135 | this.playButtonPlayingState = true;
136 | this.OFMbuttonList.remove(this.playBtn);
137 | this.playBtn = new OFMGuiButton(0, this.width / 2 - 12, this.height / 2 + 28 - 5 - 45, 24, 24, 24, 0, "", OFMGuiButton.guiLocation);
138 | this.OFMbuttonList.add(this.playBtn);
139 | }
140 |
141 | if ((!this.radio.isPlaying()) && (this.playButtonPlayingState)) {
142 | this.playButtonPlayingState = false;
143 | this.OFMbuttonList.remove(this.playBtn);
144 | this.playBtn = new OFMGuiButton(0, this.width / 2 - 12, this.height / 2 + 28 - 5 - 45, 24, 24, 0, 0, "", OFMGuiButton.guiLocation);
145 | this.OFMbuttonList.add(this.playBtn);
146 | }
147 |
148 | if ((this.radio.isListeningToRedstoneInput() & !this.redstoneButtonState)) {
149 | this.redstoneButtonState = true;
150 | this.OFMbuttonList.remove(this.redstoneBtn);
151 | this.redstoneBtn = new OFMGuiButton(10, this.width / 2 + 100 - 13, this.height / 2 + 3 - 5 - 45, 8, 8, 95, 24, "", OFMGuiButton.guiLocation);
152 | this.OFMbuttonList.add(this.redstoneBtn);
153 | }
154 |
155 | if ((!this.radio.isListeningToRedstoneInput() & this.redstoneButtonState)) {
156 | this.redstoneButtonState = false;
157 | this.OFMbuttonList.remove(this.redstoneBtn);
158 | this.redstoneBtn = new OFMGuiButton(10, this.width / 2 + 100 - 13, this.height / 2 + 3 - 5 - 45, 8, 8, 87, 24, "", OFMGuiButton.guiLocation);
159 | this.OFMbuttonList.add(this.redstoneBtn);
160 | }
161 |
162 | if ((this.radio.isLocked & !this.lockedButtonState)) {
163 | this.lockedButtonState = true;
164 | this.OFMbuttonList.remove(this.lockedBtn);
165 | this.lockedBtn = new OFMGuiButton(11, this.width / 2 + 100 - 4, this.height / 2 + 30 - 45, 12, 16, 103, 24, "", OFMGuiButton.guiLocation);
166 | this.OFMbuttonList.add(this.lockedBtn);
167 | }
168 |
169 | if ((!this.radio.isLocked & this.lockedButtonState)) {
170 | this.lockedButtonState = false;
171 | this.OFMbuttonList.remove(this.lockedBtn);
172 | this.lockedBtn = new OFMGuiButton(11, this.width / 2 + 100 - 4, this.height / 2 + 30 - 45, 12, 16, 115, 24, "", OFMGuiButton.guiLocation);
173 | this.OFMbuttonList.add(this.lockedBtn);
174 | }
175 | }
176 |
177 | @Override
178 | @SideOnly(Side.CLIENT)
179 | public void drawScreen(int par1, int par2, float par3) {
180 | super.drawScreen(par1, par2, par3);
181 |
182 | this.streamTextBox.drawTextBox();
183 | this.volumeBox.drawTextBox();
184 | this.colorBox.drawTextBox();
185 | this.screenTextBox.drawTextBox();
186 |
187 | for (int k = 0; k < this.OFMbuttonList.size(); k++) {
188 | OFMGuiButton btn = (OFMGuiButton)this.OFMbuttonList.get(k);
189 | if (btn.func_146115_a()) { // Tells you if the button is hovered by mouse
190 | if (btn.id == 0) {
191 | String hover;
192 | if (!this.radio.isPlaying()) {
193 | hover = StatCollector.translateToLocal("gui.string.OpenFM.PlayButton");
194 | } else {
195 | hover = StatCollector.translateToLocal("gui.string.OpenFM.StopButton");
196 | }
197 | String[] desc = { hover };
198 | @SuppressWarnings("rawtypes")
199 | List temp = Arrays.asList(desc);
200 | drawHoveringText(temp, par1, par2, fontRendererObj);
201 | } else if (btn.id == 1) {
202 | String[] desc = { StatCollector.translateToLocal("gui.string.OpenFM.VolumeUp") };
203 | @SuppressWarnings("rawtypes")
204 | List temp = Arrays.asList(desc);
205 | drawHoveringText(temp, par1, par2, fontRendererObj);
206 | } else if (btn.id == 2) {
207 | String[] desc = { StatCollector.translateToLocal("gui.string.OpenFM.VolumeDown") };
208 | @SuppressWarnings("rawtypes")
209 | List temp = Arrays.asList(desc);
210 | drawHoveringText(temp, par1, par2, fontRendererObj);
211 | } else if (btn.id == 3) {
212 | String[] desc = { StatCollector.translateToLocal("gui.string.OpenFM.ScrollLeft") };
213 | @SuppressWarnings("rawtypes")
214 | List temp = Arrays.asList(desc);
215 | drawHoveringText(temp, par1, par2, fontRendererObj);
216 | } else if (btn.id == 4) {
217 | String[] desc = { StatCollector.translateToLocal("gui.string.OpenFM.ScrollRight") };
218 | @SuppressWarnings("rawtypes")
219 | List temp = Arrays.asList(desc);
220 | drawHoveringText(temp, par1, par2, fontRendererObj);
221 | } else if (btn.id == 5) {
222 | String[] desc = { StatCollector.translateToLocal("gui.string.OpenFM.Clear") };
223 | @SuppressWarnings("rawtypes")
224 | List temp = Arrays.asList(desc);
225 | drawHoveringText(temp, par1, par2, fontRendererObj);
226 | } else if (btn.id == 6) {
227 | String[] desc = { StatCollector.translateToLocal("gui.string.OpenFM.Paste") };
228 | @SuppressWarnings("rawtypes")
229 | List temp = Arrays.asList(desc);
230 | drawHoveringText(temp, par1, par2, fontRendererObj);
231 | } else if (btn.id == 7) {
232 | String[] desc = { StatCollector.translateToLocal("gui.string.OpenFM.Save") };
233 | @SuppressWarnings("rawtypes")
234 | List temp = Arrays.asList(desc);
235 | drawHoveringText(temp, par1, par2, fontRendererObj);
236 | } else if (btn.id == 8) {
237 | String[] desc = { StatCollector.translateToLocal("gui.string.OpenFM.Delete") };
238 | @SuppressWarnings("rawtypes")
239 | List temp = Arrays.asList(desc);
240 | drawHoveringText(temp, par1, par2, fontRendererObj);
241 | } else if (btn.id == 9) {
242 | String[] desc = { StatCollector.translateToLocal("gui.string.OpenFM.Close") };
243 | @SuppressWarnings("rawtypes")
244 | List temp = Arrays.asList(desc);
245 | drawHoveringText(temp, par1, par2, fontRendererObj);
246 | } else if (btn.id == 10) {
247 | String hover;
248 | if (!this.radio.isListeningToRedstoneInput()) {
249 | hover = StatCollector.translateToLocal("gui.string.OpenFM.RedstoneOn");
250 | } else {
251 | hover = StatCollector.translateToLocal("gui.string.OpenFM.RedstoneOff");
252 | }
253 | String[] desc = { hover };
254 | @SuppressWarnings("rawtypes")
255 | List temp = Arrays.asList(desc);
256 | drawHoveringText(temp, par1, par2, fontRendererObj);
257 | } else if (btn.id == 11) {
258 | String hover;
259 | if (!this.radio.isLocked) {
260 | hover = StatCollector.translateToLocal("gui.string.OpenFM.Lock");
261 | } else {
262 | hover = StatCollector.translateToLocal("gui.string.OpenFM.Unlock");
263 | }
264 | String[] desc = { hover };
265 | @SuppressWarnings("rawtypes")
266 | List temp = Arrays.asList(desc);
267 | drawHoveringText(temp, par1, par2, fontRendererObj);
268 | } else if (btn.id == 15) {
269 | String[] desc = { StatCollector.translateToLocal("gui.string.OpenFM.SaveToCard") };
270 | @SuppressWarnings("rawtypes")
271 | List temp = Arrays.asList(desc);
272 | drawHoveringText(temp, par1, par2, fontRendererObj);
273 | } else if (btn.id == 16) {
274 | String[] desc = { StatCollector.translateToLocal("gui.string.OpenFM.LoadFromCard") };
275 | @SuppressWarnings("rawtypes")
276 | List temp = Arrays.asList(desc);
277 | drawHoveringText(temp, par1, par2, fontRendererObj);
278 | }
279 | }
280 | }
281 | }
282 |
283 | @Override
284 | public void drawDefaultBackground() {}
285 |
286 | @Override
287 | @SideOnly(Side.CLIENT)
288 | protected void actionPerformed(int buttonID) {
289 | if (buttonID == 0) { //Play button
290 | if(this.streamTextBox.getText() != null && !this.streamTextBox.getText().isEmpty()) {
291 | if (this.streamTextBox.getText().toLowerCase().endsWith(".m3u")) {
292 | this.radio.streamURL = takeFirstEntryFromM3U(this.streamTextBox.getText());
293 | } else if (this.streamTextBox.getText().toLowerCase().endsWith(".pls")) {
294 | this.radio.streamURL = parsePls(this.streamTextBox.getText());
295 | } else {
296 | this.radio.streamURL = this.streamTextBox.getText();
297 | }
298 | if (this.radio.isPlaying()) {
299 | PacketHandler.INSTANCE.sendToServer(new MessageRadioPlaying(this.radio, !this.radio.isPlaying()).wrap());
300 | PacketHandler.INSTANCE.sendToServer(new MessageRadioStreamURL(this.radio, this.radio.streamURL).wrap());
301 | } else if (HttpUrl.parse(this.radio.streamURL) != null) {
302 | PacketHandler.INSTANCE.sendToServer(new MessageRadioStreamURL(this.radio, this.radio.streamURL).wrap());
303 | PacketHandler.INSTANCE.sendToServer(new MessageRadioPlaying(this.radio, !this.radio.isPlaying()).wrap());
304 | }
305 | }
306 | }
307 | if (buttonID == 1) { //VolUp
308 | this.saving = false;
309 | float v = (float)(this.radio.getVolume() + 0.1D);
310 | if ((v > 0.0F) && (v <= 1.0F)) {
311 | PacketHandler.INSTANCE.sendToServer(new MessageRadioVolume(this.radio, v).wrap());
312 | }
313 | } if (buttonID == 2) { //VolDown
314 | this.saving = false;
315 | float v = (float)(this.radio.getVolume() - 0.1D);
316 | if ((v > 0.0F) && (v <= 1.0F)) {
317 | PacketHandler.INSTANCE.sendToServer(new MessageRadioVolume(this.radio, v).wrap());
318 | }
319 | } if (buttonID == 3) { //Scroll left
320 | this.streamTextBox.setText(this.radio.getPrevious(this.streamTextBox.getText()));
321 | } if (buttonID == 4) { //Scroll Right
322 | this.streamTextBox.setText(this.radio.getNext(this.streamTextBox.getText()));
323 | } if (buttonID == 5) { //Clear
324 | this.saving = false;
325 | this.streamTextBox.setText("");
326 | this.streamTextBox.setCursorPosition(0);
327 | } if (buttonID == 6) { //Paste
328 | java.awt.Toolkit toolkit = java.awt.Toolkit.getDefaultToolkit();
329 | java.awt.datatransfer.Clipboard clipboard = toolkit.getSystemClipboard();
330 | try {
331 | String result = (String)clipboard.getData(java.awt.datatransfer.DataFlavor.stringFlavor);
332 | this.streamTextBox.setText(result);
333 | }
334 | catch (Exception localException) {}
335 | } if (buttonID == 7) { //Save
336 | if(this.streamTextBox.getText() != null && !this.streamTextBox.getText().isEmpty()) {
337 | this.radio.addStation(this.streamTextBox.getText());
338 | PacketHandler.INSTANCE.sendToServer(new MessageRadioAddStation(this.radio, this.streamTextBox.getText()).wrap());
339 | }
340 | } if (buttonID == 8) { //Delete
341 | if(this.streamTextBox.getText() != null && !this.streamTextBox.getText().isEmpty()) {
342 | this.radio.delStation(this.streamTextBox.getText());
343 | PacketHandler.INSTANCE.sendToServer(new MessageRadioDelStation(this.radio, this.streamTextBox.getText()).wrap());
344 | }
345 | } if (buttonID == 9) { //Close
346 | Minecraft.getMinecraft().displayGuiScreen(null);
347 | Minecraft.getMinecraft().setIngameFocus();
348 | }
349 | if (buttonID == 10) { //Redstone
350 | PacketHandler.INSTANCE.sendToServer(new MessageRadioRedstone(this.radio, !this.redstoneButtonState).wrap());
351 | } if (buttonID == 11) { //Lock
352 | PacketHandler.INSTANCE.sendToServer(new MessageRadioLocked(this.radio, !this.lockedButtonState).wrap());
353 | } if (buttonID == 13) { //Screen Color
354 | PacketHandler.INSTANCE.sendToServer(new MessageRadioScreenColor(this.radio, Integer.parseInt(this.colorBox.getText(), 16)).wrap());
355 | }
356 |
357 | if (buttonID == 14) { //Screen Text
358 | PacketHandler.INSTANCE.sendToServer(new MessageRadioScreenText(this.radio, this.screenTextBox.getText()).wrap());
359 | }
360 | if (buttonID == 16) { //Read from card
361 | //PacketHandler.INSTANCE.sendToServer(new MessageRadioReadCard(this.radio).wrap());
362 | if (this.radio.RadioItemStack[0] != null && this.radio.RadioItemStack[0].hasTagCompound()) {
363 | this.screenTextBox.setText(this.radio.RadioItemStack[0].getTagCompound().getString("screenText"));
364 | this.colorBox.setText(toHexString(this.radio.RadioItemStack[0].getTagCompound().getInteger("screenColor")));
365 | this.streamTextBox.setText(this.radio.RadioItemStack[0].getTagCompound().getString("streamURL"));
366 | actionPerformed(0);
367 | actionPerformed(13);
368 | actionPerformed(14);
369 | }
370 | }
371 | if (buttonID == 15) { //Write to card
372 | if(this.radio.RadioItemStack[0] != null) {
373 | PacketHandler.INSTANCE.sendToServer(new MessageRadioWriteCard(this.radio).wrap());
374 | }
375 | }
376 | }
377 |
378 | @Override
379 | protected void mouseClicked(int par1, int par2, int par3) {
380 | super.mouseClicked(par1, par2, par3);
381 | if (betweenExclusive(par1, this.width / 2 - 100, this.width / 2 - 100 + 198) && betweenExclusive(par2, this.height / 2 - 5 + 17 - 45, this.height / 2 - 5 + 17 + 8 - 45)) {
382 | this.streamTextBox.mouseClicked(par1, par2, par3);
383 | this.colorBox.setFocused(false);
384 | this.screenTextBox.setFocused(false);
385 | } else if (betweenExclusive(par1, this.width / 2 - 97, this.width / 2 - 97 + 61) && betweenExclusive(par2, this.height / 2 - 5 + 72 - 45, this.height / 2 - 5 + 72 + 10 - 45)) {
386 | this.colorBox.mouseClicked(par1, par2, par3);
387 | this.screenTextBox.setFocused(false);
388 | this.streamTextBox.setFocused(false);
389 | } else if (betweenExclusive(par1, this.width / 2 - 17, this.width / 2 - 17 + 124) && betweenExclusive(par2, this.height / 2 - 5 + 72 - 45, this.height / 2 - 5 + 72 + 10 - 45)) {
390 | this.screenTextBox.mouseClicked(par1, par2, par3);
391 | this.streamTextBox.setFocused(false);
392 | this.colorBox.setFocused(false);
393 | } else {
394 | this.streamTextBox.setFocused(false);
395 | this.colorBox.setFocused(false);
396 | this.screenTextBox.setFocused(false);
397 |
398 | //actionPerformed(13);
399 | this.colorBox.setTextColor(Integer.parseInt(this.colorBox.getText(), 16));
400 | this.screenTextBox.setTextColor(Integer.parseInt(this.colorBox.getText(), 16));
401 | //actionPerformed(14);
402 | }
403 | }
404 |
405 | @Override
406 | protected void keyTyped(char par1, int par2) {
407 | if (this.streamTextBox.isFocused()) {
408 | this.streamTextBox.textboxKeyTyped(par1, par2);
409 |
410 | if (par1 == '\r')
411 | {
412 | actionPerformed(0);
413 | }
414 | } else if (this.colorBox.isFocused()) {
415 | boolean isHex = Character.toString(par1).matches("[0-9A-F]+");
416 | if (isHex || par1 == '\b' || par2 == 205 || par2 == 203 || par2 == 211) {
417 | this.colorBox.textboxKeyTyped(par1, par2);
418 | }
419 |
420 | if (par1 == '\r')
421 | {
422 | actionPerformed(13);
423 | this.colorBox.setTextColor(Integer.parseInt(this.colorBox.getText(), 16));
424 | this.screenTextBox.setTextColor(Integer.parseInt(this.colorBox.getText(), 16));
425 | }
426 | } else if (this.screenTextBox.isFocused()) {
427 | this.screenTextBox.textboxKeyTyped(par1, par2);
428 | if (par1 == '\r')
429 | {
430 | actionPerformed(14);
431 | }
432 | }
433 | if(!( par2 == mc.gameSettings.keyBindInventory.getKeyCode() && this.screenTextBox.isFocused() || this.streamTextBox.isFocused() || this.colorBox.isFocused())) super.keyTyped(par1, par2);
434 | }
435 |
436 | public static boolean betweenExclusive(int x, int min, int max)
437 | {
438 | return x>min && x= this.xPosition) && (posY >= this.yPosition) && (posX < this.xPosition + this.width) && (posY < this.yPosition + this.height));
73 | int k = getHoverState(this.field_146123_n);
74 | GL11.glEnable(3042);
75 | OpenGlHelper.glBlendFunc(770, 771, 1, 0);
76 | GL11.glBlendFunc(770, 771);
77 | drawTexturedModalRect(this.xPosition, this.yPosition, this.offx, this.offy + k * Math.round(this.height / 2), this.width, this.height);
78 | mouseDragged(minecraft, posX, posY);
79 | int l = 14737632;
80 |
81 | if (this.packedFGColour != 0)
82 | {
83 | l = this.packedFGColour;
84 | }
85 | else if (!this.enabled)
86 | {
87 | l = 10526880;
88 | }
89 | else if (this.field_146123_n)
90 | {
91 | l = 16777120;
92 | }
93 |
94 | drawCenteredString(fontrenderer, this.displayString, this.xPosition + this.width / 2, this.yPosition + (this.height - 8) / 2, l);
95 | }
96 | }
97 | }
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/GUI/OFMGuiFactory.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.GUI;
2 |
3 |
4 | import cpw.mods.fml.client.IModGuiFactory;
5 | import net.minecraft.client.Minecraft;
6 | import net.minecraft.client.gui.GuiScreen;
7 |
8 | import java.util.Set;
9 |
10 | public class OFMGuiFactory implements IModGuiFactory {
11 | @Override
12 | public void initialize(Minecraft minecraftInstance) {
13 |
14 | }
15 |
16 | @Override
17 | public Class extends GuiScreen> mainConfigGuiClass() {
18 | return OFMConfigGUI.class;
19 | }
20 |
21 | @Override
22 | public Set runtimeGuiCategories() {
23 | return null;
24 | }
25 |
26 | @Override
27 | public RuntimeOptionGuiHandler getHandlerFor(RuntimeOptionCategoryElement element) {
28 | return null;
29 | }
30 | }
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/GUI/OFMGuiHandler.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | */
4 | package pcl.OpenFM.GUI;
5 |
6 | import pcl.OpenFM.TileEntity.RadioContainer;
7 | import pcl.OpenFM.TileEntity.TileEntityRadio;
8 | import cpw.mods.fml.common.network.IGuiHandler;
9 | import net.minecraft.entity.player.EntityPlayer;
10 | import net.minecraft.tileentity.TileEntity;
11 | import net.minecraft.world.World;
12 | /**
13 | * @author Caitlyn
14 | *
15 | */
16 | public class OFMGuiHandler implements IGuiHandler {
17 |
18 | @Override
19 | public Object getServerGuiElement(int id, EntityPlayer player, World world, int x, int y, int z) {
20 | if (id == 0) {
21 | TileEntity tileEntity = world.getTileEntity(x, y, z);
22 | if (tileEntity instanceof TileEntityRadio) {
23 | return new RadioContainer(player.inventory, (TileEntityRadio) tileEntity);
24 | }
25 | }
26 | return null;
27 | }
28 |
29 | @Override
30 | public Object getClientGuiElement(int id, EntityPlayer player, World world, int x, int y, int z) {
31 | if (id == 0) {
32 | TileEntity tileEntity = world.getTileEntity(x, y, z);
33 | if (tileEntity instanceof TileEntityRadio) {
34 | return new GuiRadio(player.inventory, (TileEntityRadio) tileEntity);
35 | }
36 | }
37 | return null;
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/GUI/OFMGuiTextField.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.GUI;
2 |
3 | import net.minecraft.client.gui.FontRenderer;
4 | import net.minecraft.client.gui.GuiTextField;
5 | import cpw.mods.fml.relauncher.Side;
6 | import cpw.mods.fml.relauncher.SideOnly;
7 |
8 |
9 | @SideOnly(Side.CLIENT)
10 | public class OFMGuiTextField extends GuiTextField {
11 | public OFMGuiTextField(FontRenderer par1FontRenderer, int par2, int par3, int par4, int par5)
12 | {
13 | super(par1FontRenderer, par2, par3, par4, par5);
14 | removeBackground(par1FontRenderer, par2, par3, par4, par5);
15 | }
16 |
17 | public GuiTextField removeBackground(FontRenderer par1FontRenderer, int par2, int par3, int par4, int par5) {
18 | setEnableBackgroundDrawing(false);
19 | return this;
20 | }
21 | }
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/Handler/CardSlot.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | */
4 | package pcl.OpenFM.Handler;
5 |
6 | import pcl.OpenFM.Items.ItemMemoryCard;
7 | import net.minecraft.inventory.IInventory;
8 | import net.minecraft.inventory.Slot;
9 | import net.minecraft.item.ItemStack;
10 |
11 | /**
12 | * @author Caitlyn
13 | *
14 | */
15 | public class CardSlot extends Slot {
16 |
17 | public CardSlot(IInventory par1iInventory, int par2, int par3, int par4) {
18 | super(par1iInventory, par2, par3, par4);
19 | }
20 |
21 | @Override
22 | public boolean isItemValid(ItemStack itemstack) {
23 | if (itemstack.getItem() instanceof ItemMemoryCard) {
24 | if (itemstack.stackTagCompound == null) {
25 | return true;
26 | } else {
27 | return false;
28 | }
29 | }
30 | return false;
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/Handler/ChatMessage.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.Handler;
2 |
3 | import pcl.OpenFM.OpenFM;
4 |
5 | public class ChatMessage {
6 |
7 | public static void writeline(String message) {
8 | OpenFM.logger.info(message);
9 | }
10 |
11 | public static void writeError(Exception e) {
12 | OpenFM.logger.error(e);
13 | OpenFM.logger.error("Please report to http://github.com/PC-Logix/OpenFM/");
14 | }
15 | }
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/Handler/ClientEvent.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.Handler;
2 |
3 | import net.minecraftforge.event.world.WorldEvent;
4 | import pcl.OpenFM.OpenFM;
5 | import cpw.mods.fml.common.eventhandler.SubscribeEvent;
6 | import cpw.mods.fml.relauncher.Side;
7 | import cpw.mods.fml.relauncher.SideOnly;
8 |
9 | public class ClientEvent
10 | {
11 | @SideOnly(Side.CLIENT)
12 | @SubscribeEvent
13 | public void worldUnload(WorldEvent.Unload world)
14 | {
15 | ChatMessage.writeline("Stopping all currently running radio streams.");
16 | OpenFM.killAllStreams();
17 | }
18 | }
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/Handler/OFMBreakEvent.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.Handler;
2 |
3 | import net.minecraft.entity.player.EntityPlayer;
4 | import net.minecraft.entity.player.EntityPlayerMP;
5 | import net.minecraft.server.MinecraftServer;
6 | import net.minecraft.tileentity.TileEntity;
7 | import net.minecraftforge.event.world.BlockEvent.BreakEvent;
8 | import pcl.OpenFM.OpenFM;
9 | import pcl.OpenFM.TileEntity.TileEntityRadio;
10 | import cpw.mods.fml.common.eventhandler.EventPriority;
11 | import cpw.mods.fml.common.eventhandler.SubscribeEvent;
12 |
13 | public class OFMBreakEvent {
14 |
15 | public OFMBreakEvent() {
16 | OpenFM.logger.info("Registering BreakEvent");
17 | }
18 |
19 | public static boolean IsOp(EntityPlayer player) {
20 | return MinecraftServer.getServer().getConfigurationManager().func_152596_g(player.getGameProfile());
21 | }
22 |
23 | @SubscribeEvent(priority=EventPriority.NORMAL)
24 | public void onBlockBreak(BreakEvent event) {
25 | if (event.getPlayer() instanceof EntityPlayerMP) {
26 | if (!IsOp(event.getPlayer())) {
27 | TileEntity TE = event.world.getTileEntity(event.x, event.y, event.z);
28 | if(TE instanceof TileEntityRadio){
29 | TileEntityRadio xEntity = (TileEntityRadio) TE;
30 | if(xEntity.owner!=null){
31 | if(!xEntity.owner.equals(event.getPlayer().getUniqueID().toString()) && xEntity.isLocked) {
32 | if(!xEntity.owner.isEmpty()) {
33 | event.setCanceled(true);
34 | }
35 | }
36 | }
37 | }
38 | } else {
39 | TileEntity TE = event.world.getTileEntity(event.x, event.y, event.z);
40 | if(TE instanceof TileEntityRadio){
41 | OpenFM.logger.info("Op is breaking a radio at X:" + event.x + " Y: " + event.y + " Z: " + event.z);
42 | }
43 | }
44 | }
45 | }
46 | }
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/Handler/ServerEvent.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.Handler;
2 |
3 | import net.minecraft.entity.player.EntityPlayerMP;
4 | import cpw.mods.fml.common.eventhandler.SubscribeEvent;
5 | import cpw.mods.fml.common.gameevent.PlayerEvent;
6 | import cpw.mods.fml.relauncher.Side;
7 | import cpw.mods.fml.relauncher.SideOnly;
8 |
9 | public class ServerEvent
10 | {
11 | @SideOnly(Side.SERVER)
12 | @SubscribeEvent
13 | public void userLoggedIn(PlayerEvent.PlayerLoggedInEvent event)
14 | {
15 | if ((event.player instanceof EntityPlayerMP)) {}
16 | }
17 | }
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/Items/ItemBlockRadio.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.Items;
2 |
3 | import pcl.OpenFM.TileEntity.TileEntityRadio;
4 | import net.minecraft.block.Block;
5 | import net.minecraft.entity.player.EntityPlayer;
6 | import net.minecraft.item.ItemBlock;
7 | import net.minecraft.item.ItemStack;
8 | import net.minecraft.world.World;
9 |
10 | public class ItemBlockRadio extends ItemBlock {
11 |
12 | public ItemBlockRadio(Block p_i45328_1_) {
13 | super(p_i45328_1_);
14 | // TODO Auto-generated constructor stub
15 | }
16 |
17 | @Override
18 | public boolean placeBlockAt(ItemStack stack, EntityPlayer player, World world, int x, int y, int z, int side, float hitX, float hitY, float hitZ, int metadata)
19 | {
20 | if(super.placeBlockAt(stack, player, world, x, y, z, side, hitX, hitY, hitZ, metadata))
21 | {
22 | TileEntityRadio tileEntity = (TileEntityRadio) world.getTileEntity(x, y, z);
23 | if (stack.hasTagCompound()) {
24 | tileEntity.streamURL = stack.getTagCompound().getString("streamurl");
25 | tileEntity.owner = player.getUniqueID().toString();
26 | tileEntity.setStationCount(stack.getTagCompound().getInteger("stationCount"));
27 | for(int i = 0; i < stack.getTagCompound().getInteger("stationCount"); i++)
28 | {
29 | tileEntity.stations.add(stack.getTagCompound().getString("station" + i));
30 | }
31 | }
32 | }
33 | return true;
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/Items/ItemMemoryCard.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | */
4 | package pcl.OpenFM.Items;
5 |
6 | import net.minecraft.item.Item;
7 |
8 | /**
9 | * @author Caitlyn
10 | *
11 | */
12 | public class ItemMemoryCard extends Item {
13 | public ItemMemoryCard() {
14 | setMaxStackSize(1);
15 | setUnlocalizedName("OpenFM.MemoryCard");
16 | setTextureName("openfm:ItemMemoryCard");
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/Items/ItemTuner.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.Items;
2 |
3 | import net.minecraft.entity.player.EntityPlayer;
4 | import net.minecraft.item.Item;
5 | import net.minecraft.item.ItemStack;
6 | import net.minecraft.util.ChatComponentTranslation;
7 | import net.minecraft.world.World;
8 | import pcl.OpenFM.Block.BlockRadio;
9 | import pcl.OpenFM.Block.BlockSpeaker;
10 | import pcl.OpenFM.TileEntity.TileEntityRadio;
11 | import pcl.OpenFM.misc.Speaker;
12 | import pcl.OpenFM.network.PacketHandler;
13 | import pcl.OpenFM.network.message.MessageRadioAddSpeaker;
14 | import cpw.mods.fml.common.FMLCommonHandler;
15 | import cpw.mods.fml.relauncher.Side;
16 |
17 | import java.util.HashMap;
18 |
19 | public class ItemTuner extends Item {
20 |
21 | public static HashMap boundSpeakers = new HashMap();
22 |
23 | public ItemTuner() {
24 | setMaxStackSize(1);
25 | setUnlocalizedName("OpenFM.Tuner");
26 | setTextureName("openfm:ItemTuner");
27 | }
28 |
29 | public boolean onItemUseFirst(ItemStack stack, EntityPlayer player, World world, int x, int y, int z, int hitSide, float hitX, float hitY, float hitZ) {
30 | Side side = FMLCommonHandler.instance().getEffectiveSide();
31 |
32 | // Item can only be used by client.
33 | if (side != Side.SERVER) {
34 |
35 | // If clicked block is a speaker, keep a reference to it.
36 | if ((world.getBlock(x, y, z) instanceof BlockSpeaker)) {
37 |
38 | // TODO: one speaker should only be able to be linked to exactly one radio.
39 | boundSpeakers.put(stack, new Speaker(x, y, z, world));
40 | player.addChatMessage(new ChatComponentTranslation("msg.OpenFM.selected_speaker"));
41 |
42 | } else if ((world.getBlock(x, y, z) instanceof BlockRadio)) {
43 |
44 | // Else, it it's a radio, try to link it to the speaker.
45 | if (boundSpeakers.get(stack) != null) {
46 | Speaker speaker = boundSpeakers.get(stack);
47 | TileEntityRadio radio = (TileEntityRadio) player.getEntityWorld().getTileEntity(x, y, z);
48 |
49 | // Check if the speaker can be added to the radio.
50 | int canAdd = radio.canAddSpeaker(player.getEntityWorld(), speaker.x, speaker.y, speaker.z);
51 | if (canAdd == 0) {
52 | // It can, so send a packet.
53 | player.addChatMessage(new ChatComponentTranslation("msg.OpenFM.added_speaker"));
54 | PacketHandler.INSTANCE.sendToServer(new MessageRadioAddSpeaker(radio, speaker).wrap());
55 | } else if (canAdd == 1) {
56 | // Too many speakers linked.
57 | player.addChatMessage(new ChatComponentTranslation("msg.OpenFM.failed_adding_speaker_limit"));
58 | } else if (canAdd == 2) {
59 | // Speaker is already linked.
60 | player.addChatMessage(new ChatComponentTranslation("msg.OpenFM.failed_adding_speaker_exists"));
61 | }
62 |
63 | } else {
64 | // Apparently no speaker is bound.
65 | player.addChatMessage(new ChatComponentTranslation("msg.OpenFM.failed_adding_speaker_not_selected"));
66 | }
67 | }
68 |
69 | }
70 | return true;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/OFMConfiguration.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM;
2 |
3 | import java.io.File;
4 |
5 | import net.minecraftforge.common.config.ConfigCategory;
6 | import net.minecraftforge.common.config.Configuration;
7 |
8 | public class OFMConfiguration {
9 |
10 | // All config values
11 | public static String defaultURL = "StreamURL";
12 | public static boolean enableMUD = true;
13 | public static boolean enableStreams = true;
14 | public static Integer maxSpeakers = 10;
15 | public static Configuration config;
16 |
17 | // Called by OpenFM preInit()
18 | public static void init(File configFile) {
19 |
20 | config = new Configuration(configFile);
21 |
22 | try {
23 | config.load();
24 | defaultURL = config.get("general", "defaultURL", defaultURL, "The default stream of the player.").getString();
25 | enableMUD = config.get("general", "enableMUD", enableMUD, "Automatically check for mod updates.").getBoolean();
26 | enableStreams = config.get("general", "enableStreams", enableStreams, "Should we try to play streams at all? If false streams will not work in game. (Client side only)").getBoolean();
27 | maxSpeakers = config.get("general", "maxSpeakers", maxSpeakers, "Maximum speakers that can be attached to a radio, higher numbers may cause performance issues").getInt(10);
28 | } catch(Exception e) {
29 | OpenFM.logger.error("OpenFM encountered a problem with loading the config file.");
30 | } finally {
31 | if (config.hasChanged()) {
32 | config.save();
33 | }
34 | }
35 | }
36 |
37 | public static void sync() {
38 | if (config.hasChanged()) {
39 | config.save();
40 | }
41 | }
42 |
43 | public static ConfigCategory getCategory(String name) {
44 | // TODO Auto-generated method stub
45 | return config.getCategory(name.toLowerCase()).setLanguageKey(name.toLowerCase().replace(" ", ""));
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/OpenFM.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM;
2 |
3 | import java.io.File;
4 | import java.net.URL;
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | import org.apache.logging.log4j.LogManager;
9 | import org.apache.logging.log4j.Logger;
10 |
11 | import net.minecraft.client.gui.GuiIngameMenu;
12 | import net.minecraftforge.client.event.GuiOpenEvent;
13 | import net.minecraftforge.common.MinecraftForge;
14 | import net.minecraftforge.common.config.Configuration;
15 | import pcl.OpenFM.GUI.OFMGuiHandler;
16 | import pcl.OpenFM.Handler.ClientEvent;
17 | import pcl.OpenFM.Handler.ServerEvent;
18 | import pcl.OpenFM.network.PacketHandler;
19 | import pcl.OpenFM.player.PlayerDispatcher;
20 | import cpw.mods.fml.client.GuiIngameModOptions;
21 | import cpw.mods.fml.client.GuiModList;
22 | import cpw.mods.fml.client.event.ConfigChangedEvent;
23 | import cpw.mods.fml.common.FMLCommonHandler;
24 | import cpw.mods.fml.common.Mod;
25 | import cpw.mods.fml.common.ModContainer;
26 | import cpw.mods.fml.common.SidedProxy;
27 | import cpw.mods.fml.common.event.FMLInitializationEvent;
28 | import cpw.mods.fml.common.event.FMLPreInitializationEvent;
29 | import cpw.mods.fml.common.eventhandler.EventPriority;
30 | import cpw.mods.fml.common.eventhandler.SubscribeEvent;
31 | import cpw.mods.fml.common.network.NetworkRegistry;
32 | import cpw.mods.fml.relauncher.Side;
33 | import cpw.mods.fml.relauncher.SideOnly;
34 |
35 | @Mod(modid=BuildInfo.modID, name=BuildInfo.modName, version=BuildInfo.versionNumber + "." + BuildInfo.buildNumber, dependencies = "", guiFactory = "pcl.OpenFM.GUI.OFMGuiFactory")
36 | public class OpenFM {
37 | public static final String MODID = "openfm";
38 | @Mod.Instance(BuildInfo.modID)
39 | public static OpenFM instance;
40 | @SidedProxy(clientSide="pcl.OpenFM.ClientProxy", serverSide="pcl.OpenFM.CommonProxy")
41 | public static CommonProxy proxy;
42 | public static List playerList = new ArrayList();
43 | public Configuration config;
44 | public static final Logger logger = LogManager.getFormatterLogger(BuildInfo.modID);
45 | public static File configFile;
46 | @Mod.EventHandler
47 | public void preInit(FMLPreInitializationEvent event) {
48 | PacketHandler.init();
49 |
50 | // Load config
51 | configFile = new File(event.getModConfigurationDirectory() + "/openfm/openfm.cfg");
52 | OFMConfiguration.init(configFile);
53 |
54 | // Check for Mod Update Detector
55 | if (event.getSourceFile().getName().endsWith(".jar") && event.getSide().isClient() && OFMConfiguration.enableMUD) {
56 | logger.info("Registering mod with OpenUpdater.");
57 | try {
58 | Class.forName("pcl.mud.OpenUpdater").getDeclaredMethod("registerMod", ModContainer.class, URL.class, URL.class).invoke(null, FMLCommonHandler.instance().findContainerFor(this),
59 | new URL("http://PC-Logix.com/OpenFM/get_latest_build.php?mcver=1.7.10"),
60 | new URL("http://PC-Logix.com/OpenFM/changelog.php?mcver=1.7.10"));
61 | } catch (Throwable e) {
62 | logger.info("OpenUpdater is not installed, not registering.");
63 | }
64 | }
65 | }
66 |
67 | @SideOnly(Side.CLIENT)
68 | @SubscribeEvent(priority=EventPriority.NORMAL, receiveCanceled=true)
69 | public void onEvent(GuiOpenEvent event) {
70 | if (event.gui instanceof GuiIngameModOptions) {
71 | event.gui = new GuiModList(new GuiIngameMenu());
72 | }
73 | }
74 |
75 | @Mod.EventHandler
76 | public void init(FMLInitializationEvent evt) {
77 | NetworkRegistry.INSTANCE.registerGuiHandler(this, new OFMGuiHandler());
78 | MinecraftForge.EVENT_BUS.register(new ClientEvent());
79 | FMLCommonHandler.instance().bus().register(new ClientEvent());
80 | MinecraftForge.EVENT_BUS.register(new ServerEvent());
81 | FMLCommonHandler.instance().bus().register(new ServerEvent());
82 | FMLCommonHandler.instance().bus().register(instance);
83 | MinecraftForge.EVENT_BUS.register(instance);
84 | ContentRegistry.init();
85 | proxy.initTileEntities();
86 | proxy.registerRenderers();
87 | }
88 |
89 | @SubscribeEvent
90 | public void onConfigChanged(ConfigChangedEvent.OnConfigChangedEvent eventArgs) {
91 | if(eventArgs.modID.equals(BuildInfo.modID)){
92 | OFMConfiguration.sync();
93 | }
94 | }
95 |
96 | public static void killAllStreams() {
97 | if (playerList != null) {
98 | for (PlayerDispatcher p : playerList) {
99 | p.stop();
100 | }
101 | }
102 | }
103 | }
104 |
105 |
106 |
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/TileEntity/MemoryCardSlot.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | */
4 | package pcl.OpenFM.TileEntity;
5 |
6 | import net.minecraft.entity.player.EntityPlayer;
7 | import net.minecraft.inventory.IInventory;
8 | import net.minecraft.inventory.Slot;
9 | import net.minecraft.item.ItemStack;
10 |
11 | import pcl.OpenFM.Items.ItemMemoryCard;
12 |
13 | /**
14 | * @author Caitlyn
15 | *
16 | */
17 | public class MemoryCardSlot extends Slot {
18 | public MemoryCardSlot(IInventory par1iInventory, int par2, int par3, int par4) {
19 | super(par1iInventory, par2, par3, par4);
20 | }
21 | public boolean isItemValid(ItemStack itemstack) {
22 | if (itemstack.getItem() instanceof ItemMemoryCard) {
23 | return true;
24 | }
25 | return false;
26 | }
27 | /**
28 | * Called when the player picks up an item from an inventory slot
29 | */
30 | public void onPickupFromSlot(EntityPlayer par1EntityPlayer, ItemStack par2ItemStack)
31 | {
32 | this.onCrafting(par2ItemStack);
33 | super.onPickupFromSlot(par1EntityPlayer, par2ItemStack);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/TileEntity/RadioContainer.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | */
4 | package pcl.OpenFM.TileEntity;
5 |
6 | import net.minecraft.entity.player.EntityPlayer;
7 | import net.minecraft.entity.player.InventoryPlayer;
8 | import net.minecraft.inventory.Container;
9 | import net.minecraft.inventory.Slot;
10 | import net.minecraft.item.ItemStack;
11 | /**
12 | * @author Caitlyn
13 | *
14 | */
15 | public class RadioContainer extends Container {
16 | public TileEntityRadio tileEntity;
17 |
18 | private final int HOTBAR_SLOT_COUNT = 9;
19 | private final int PLAYER_INVENTORY_ROW_COUNT = 3;
20 | private final int PLAYER_INVENTORY_COLUMN_COUNT = 9;
21 | @SuppressWarnings("unused")
22 | private final int PLAYER_INVENTORY_SLOT_COUNT = PLAYER_INVENTORY_COLUMN_COUNT * PLAYER_INVENTORY_ROW_COUNT;
23 | private final int TE_INVENTORY_SLOT_COUNT = 1;
24 |
25 | public RadioContainer(InventoryPlayer inventory, TileEntityRadio te) {
26 | tileEntity = te;
27 | final int SLOT_X_SPACING = 18;
28 | final int HOTBAR_XPOS = 9;
29 | final int HOTBAR_YPOS = 15;
30 | // Add the players hotbar to the gui - the [xpos, ypos] location of each item
31 | for (int x = 0; x < HOTBAR_SLOT_COUNT; x++) {
32 | int slotNumber = x;
33 | addSlotToContainer(new Slot(inventory, slotNumber, HOTBAR_XPOS + SLOT_X_SPACING * x, HOTBAR_YPOS));
34 | }
35 |
36 | if (TE_INVENTORY_SLOT_COUNT != te.getSizeInventory()) {
37 | System.err.println("Mismatched slot count in RadioContainer(" + TE_INVENTORY_SLOT_COUNT + ") and TileInventory (" + te.getSizeInventory()+")");
38 | }
39 | final int TILE_INVENTORY_XPOS = 5;
40 | final int TILE_INVENTORY_YPOS = 70;
41 | // Add the tile inventory container to the gui
42 | for (int x = 0; x < TE_INVENTORY_SLOT_COUNT; x++) {
43 | int slotNumber = x;
44 | addSlotToContainer(new MemoryCardSlot(tileEntity, slotNumber, TILE_INVENTORY_XPOS + SLOT_X_SPACING * x, TILE_INVENTORY_YPOS));
45 | }
46 | }
47 |
48 | /* (non-Javadoc)
49 | * @see net.minecraft.inventory.Container#canInteractWith(net.minecraft.entity.player.EntityPlayer)
50 | */
51 | @Override
52 | public boolean canInteractWith(EntityPlayer player) {
53 | return tileEntity.isUseableByPlayer(player);
54 | }
55 |
56 | @Override
57 | public ItemStack transferStackInSlot(EntityPlayer player, int slot) {
58 | ItemStack stack = null;
59 | Slot slotObject = (Slot) inventorySlots.get(slot);
60 |
61 | //null checks and checks if the item can be stacked (maxStackSize > 1)
62 | if (slotObject != null && slotObject.getHasStack()) {
63 | ItemStack stackInSlot = slotObject.getStack();
64 | stack = stackInSlot.copy();
65 |
66 | //merges the item into player inventory since its in the tileEntity
67 | if (slot < tileEntity.getSizeInventory()) {
68 | if (!this.mergeItemStack(stackInSlot, tileEntity.getSizeInventory(), 36+tileEntity.getSizeInventory(), true)) {
69 | return null;
70 | }
71 | }
72 | //places it into the tileEntity is possible since its in the player inventory
73 | else if (!this.mergeItemStack(stackInSlot, 0, tileEntity.getSizeInventory(), false)) {
74 | return null;
75 | }
76 |
77 | if (stackInSlot.stackSize == 0) {
78 | slotObject.putStack(null);
79 | } else {
80 | slotObject.onSlotChanged();
81 | }
82 |
83 | if (stackInSlot.stackSize == stack.stackSize) {
84 | return null;
85 | }
86 | slotObject.onPickupFromSlot(player, stackInSlot);
87 | }
88 | return stack;
89 | }
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/TileEntity/RadioRenderer.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.TileEntity;
2 |
3 | import net.minecraft.client.gui.FontRenderer;
4 | import net.minecraft.client.renderer.OpenGlHelper;
5 | import net.minecraft.client.renderer.entity.RenderManager;
6 | import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
7 | import net.minecraft.tileentity.TileEntity;
8 |
9 | import org.lwjgl.opengl.GL11;
10 |
11 | public class RadioRenderer extends TileEntitySpecialRenderer {
12 |
13 | public Integer ticks = 0;
14 | public String text = null;
15 | String output = "";
16 | int count = 0;
17 | @Override
18 | public void renderTileEntityAt(TileEntity tileEntity, double x, double y, double z, float f) {
19 | TileEntityRadio radio = (TileEntityRadio) tileEntity;
20 |
21 | float light = tileEntity.getWorldObj().getLightBrightnessForSkyBlocks(tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord, 15);
22 | OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, light, light);
23 |
24 | RenderManager renderMan = RenderManager.instance;
25 |
26 | GL11.glPushMatrix();
27 |
28 | int dir = tileEntity.getBlockMetadata();
29 | GL11.glNormal3f(0, 1, 0);
30 | if (dir == 1) {
31 | GL11.glTranslatef((float)x +.501F, (float)y + .72F, (float)z - .01F);
32 | GL11.glRotatef(0F, 0F, 1F, 0F);
33 | } else if (dir == 2) {
34 | GL11.glTranslatef((float)x + 1.01f, (float)y + .72F, (float)z + .5F);
35 | GL11.glRotatef(270F, 0F, 1F, 0F);
36 | } else if (dir == 3) {
37 | GL11.glTranslatef((float)x + .5f, (float)y + .72F, (float)z + 1.01F);
38 | GL11.glRotatef(180F, 0F, 1F, 0F);
39 | } else if (dir == 4) {
40 | GL11.glTranslatef((float)x - .01f, (float)y + .72F, (float)z + .5f);
41 | GL11.glRotatef(90, 0F, 1F, 0F);
42 | }
43 |
44 | GL11.glScalef(-0.016666668F, -0.016666668F, 0.016666668F);
45 | GL11.glDisable(GL11.GL_LIGHTING);
46 | GL11.glEnable(GL11.GL_BLEND);
47 | GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
48 | ++this.ticks;
49 | if (this.ticks > 20) {
50 | if (radio.getScreenText().length() > 6) {
51 | output = scrollText(radio.getScreenText());
52 | } else {
53 | output = radio.getScreenText();
54 | }
55 | }
56 | renderMan.getFontRenderer().drawString(output, -37 / 2, 0, radio.getScreenColor());
57 | GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
58 | GL11.glEnable(GL11.GL_LIGHTING);
59 | GL11.glPopMatrix();
60 | }
61 |
62 | public String scrollText(String text) {
63 | FontRenderer fontRenderer = RenderManager.instance.getFontRenderer();
64 | text = " " + text + " ";
65 | if (text.length() > count + 6) {
66 | output = text.substring(count, count + 6);
67 | if (fontRenderer.getStringWidth(output) / 6 < 5) {
68 | output = text.substring(count, count + 7);
69 | }
70 | count++;
71 | this.ticks = 0;
72 | if (count > text.length()) {
73 | count = 0;
74 | }
75 | } else {
76 | count = 0;
77 | }
78 | return output;
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/TileEntity/TileEntitySpeaker.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.TileEntity;
2 |
3 | import cpw.mods.fml.common.Optional;
4 | import li.cil.oc.api.Network;
5 | import li.cil.oc.api.network.Environment;
6 | import li.cil.oc.api.network.Message;
7 | import li.cil.oc.api.network.Node;
8 | import li.cil.oc.api.network.Visibility;
9 | import net.minecraft.nbt.NBTTagCompound;
10 | import net.minecraft.tileentity.TileEntity;
11 |
12 | @Optional.InterfaceList(value={
13 | @Optional.Interface(iface = "li.cil.oc.api.network.Environment", modid = "OpenComputers")
14 | })
15 | public class TileEntitySpeaker extends TileEntity implements Environment {
16 |
17 | protected Node node;
18 |
19 | @Optional.Method(modid = "OpenComputers")
20 | @Override
21 | public Node node() {
22 | if (node == null) node = Network.newNode(this, Visibility.Network).create();
23 | return node;
24 | }
25 |
26 | @Optional.Method(modid = "OpenComputers")
27 | @Override
28 | public void onChunkUnload() {
29 | super.onChunkUnload();
30 | if (node != null)
31 | node.remove();
32 | }
33 |
34 | @Optional.Method(modid = "OpenComputers")
35 | @Override
36 | public void invalidate() {
37 | super.invalidate();
38 | if (node != null)
39 | node.remove();
40 | }
41 |
42 | @Optional.Method(modid = "OpenComputers")
43 | @Override
44 | public void onConnect(final Node node) {
45 | // TODO Auto-generated method stub
46 | }
47 |
48 | @Optional.Method(modid = "OpenComputers")
49 | @Override
50 | public void onMessage(Message message) {
51 | // TODO Auto-generated method stub
52 | }
53 |
54 | @Optional.Method(modid = "OpenComputers")
55 | @Override
56 | public void onDisconnect(Node node) {
57 | // TODO Auto-generated method stub
58 |
59 | }
60 |
61 | @Optional.Method(modid = "OpenComputers")
62 | @Override
63 | public void readFromNBT(NBTTagCompound nbt) {
64 | super.readFromNBT(nbt);
65 | if (node != null && node.host() == this) {
66 | node.load(nbt.getCompoundTag("oc:node"));
67 | }
68 | }
69 |
70 | @Optional.Method(modid = "OpenComputers")
71 | @Override
72 | public void writeToNBT(NBTTagCompound nbt) {
73 | super.writeToNBT(nbt);
74 | if (node != null && node.host() == this) {
75 | final NBTTagCompound nodeNbt = new NBTTagCompound();
76 | node.save(nodeNbt);
77 | nbt.setTag("oc:node", nodeNbt);
78 | }
79 | }
80 |
81 | @Optional.Method(modid = "OpenComputers")
82 | @Override
83 | public void updateEntity() {
84 | super.updateEntity();
85 | if (node != null && node.network() == null) {
86 | Network.joinOrCreateNetwork(this);
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/misc/DepLoader.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.misc;
2 |
3 |
4 | import java.io.File;
5 | import java.io.FileOutputStream;
6 | import java.io.IOException;
7 | import java.io.InputStream;
8 | import java.util.Enumeration;
9 | import java.util.Map;
10 | import java.util.jar.JarEntry;
11 | import java.util.jar.JarFile;
12 | import java.net.URISyntaxException;
13 | import java.nio.file.Path;
14 | import java.nio.file.Paths;
15 |
16 | import pcl.OpenFM.BuildInfo;
17 | import cpw.mods.fml.relauncher.IFMLCallHook;
18 | import cpw.mods.fml.relauncher.IFMLLoadingPlugin;
19 |
20 | public class DepLoader implements IFMLLoadingPlugin, IFMLCallHook {
21 | public void load() throws IOException, URISyntaxException {
22 | System.out.println("Starting OpenFM DepLoader!");
23 | File f = new File("mods"+File.separator);
24 | f.mkdirs();
25 | final String path = "assets/openfm/deps";
26 | final File jarFile = new File(getClass().getProtectionDomain().getCodeSource().getLocation().toURI().getPath());
27 | if(jarFile.isFile()) { // Run with JAR file
28 | JarFile jar = null;
29 | jar = new JarFile(jarFile);
30 | final Enumeration entries = jar.entries(); //gives ALL entries in jar
31 | while(entries.hasMoreElements()) {
32 | final String name = entries.nextElement().getName();
33 | if (name.startsWith(path + "/") && name.endsWith(".jar")) { //filter according to the path
34 | InputStream jarStream = getClass().getClassLoader().getResourceAsStream(name);
35 | Path p = Paths.get(name);
36 | String file = p.getFileName().toString();
37 | System.out.println("Extracting file: " + file);
38 | try (FileOutputStream fos = new FileOutputStream(f + File.separator + file);){
39 | byte[] buf = new byte[2048];
40 | int r;
41 | while(-1 != (r = jarStream.read(buf))) {
42 | fos.write(buf, 0, r);
43 | }
44 | }
45 | }
46 | }
47 | jar.close();
48 | } else {
49 | System.out.println("ERROR: Can't detect valid JAR");
50 | }
51 | }
52 |
53 | @Override
54 | public String[] getASMTransformerClass() {
55 | return null;
56 | }
57 |
58 | @Override
59 | public String getModContainerClass() {
60 | return null;
61 | }
62 |
63 | @Override
64 | public String getSetupClass() {
65 | return getClass().getName();
66 | }
67 |
68 | @Override
69 | public void injectData(Map data) {
70 | }
71 |
72 | @Override
73 | public Void call() {
74 | try {
75 | load();
76 | } catch (IOException | URISyntaxException e) {
77 | // TODO Auto-generated catch block
78 | e.printStackTrace();
79 | }
80 |
81 | return null;
82 | }
83 |
84 | @Override
85 | public String getAccessTransformerClass() {
86 | return null;
87 | }
88 | }
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/misc/FileUtils.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.misc;
2 |
3 | import java.io.File;
4 | import java.io.FileInputStream;
5 | import java.io.FileNotFoundException;
6 | import java.io.FileOutputStream;
7 | import java.io.IOException;
8 | import java.io.InputStream;
9 | import java.io.OutputStream;
10 | import java.net.JarURLConnection;
11 | import java.net.URL;
12 | import java.net.URLConnection;
13 | import java.util.Enumeration;
14 | import java.util.jar.JarEntry;
15 | import java.util.jar.JarFile;
16 |
17 | import org.apache.commons.lang3.StringUtils;
18 |
19 | public class FileUtils {
20 | public static boolean copyFile(final File toCopy, final File destFile) {
21 | try {
22 | return FileUtils.copyStream(new FileInputStream(toCopy),
23 | new FileOutputStream(destFile));
24 | } catch (final FileNotFoundException e) {
25 | e.printStackTrace();
26 | }
27 | return false;
28 | }
29 |
30 | private static boolean copyFilesRecusively(final File toCopy,
31 | final File destDir) {
32 | assert destDir.isDirectory();
33 |
34 | if (!toCopy.isDirectory()) {
35 | return FileUtils.copyFile(toCopy, new File(destDir, toCopy.getName()));
36 | } else {
37 | final File newDestDir = new File(destDir, toCopy.getName());
38 | if (!newDestDir.exists() && !newDestDir.mkdir()) {
39 | return false;
40 | }
41 | for (final File child : toCopy.listFiles()) {
42 | if (!FileUtils.copyFilesRecusively(child, newDestDir)) {
43 | return false;
44 | }
45 | }
46 | }
47 | return true;
48 | }
49 |
50 | public static boolean copyJarResourcesRecursively(final File destDir,
51 | final JarURLConnection jarConnection) throws IOException {
52 |
53 | final JarFile jarFile = jarConnection.getJarFile();
54 |
55 | for (final Enumeration e = jarFile.entries(); e.hasMoreElements();) {
56 | final JarEntry entry = e.nextElement();
57 | if (entry.getName().startsWith(jarConnection.getEntryName())) {
58 | final String filename = StringUtils.removeStart(entry.getName(), //
59 | jarConnection.getEntryName());
60 |
61 | final File f = new File(destDir, filename);
62 | if (!entry.isDirectory()) {
63 | final InputStream entryInputStream = jarFile.getInputStream(entry);
64 | if(!FileUtils.copyStream(entryInputStream, f)){
65 | return false;
66 | }
67 | entryInputStream.close();
68 | } else {
69 | if (!FileUtils.ensureDirectoryExists(f)) {
70 | throw new IOException("Could not create directory: "
71 | + f.getAbsolutePath());
72 | }
73 | }
74 | }
75 | }
76 | return true;
77 | }
78 |
79 | public static boolean copyResourcesRecursively( //
80 | final URL originUrl, final File destination) {
81 | try {
82 | final URLConnection urlConnection = originUrl.openConnection();
83 | if (urlConnection instanceof JarURLConnection) {
84 | return FileUtils.copyJarResourcesRecursively(destination,
85 | (JarURLConnection) urlConnection);
86 | } else {
87 | return FileUtils.copyFilesRecusively(new File(originUrl.getPath()),
88 | destination);
89 | }
90 | } catch (final IOException e) {
91 | e.printStackTrace();
92 | }
93 | return false;
94 | }
95 |
96 | private static boolean copyStream(final InputStream is, final File f) {
97 | try {
98 | return FileUtils.copyStream(is, new FileOutputStream(f));
99 | } catch (final FileNotFoundException e) {
100 | e.printStackTrace();
101 | }
102 | return false;
103 | }
104 |
105 | private static boolean copyStream(final InputStream is, final OutputStream os) {
106 | try {
107 | final byte[] buf = new byte[1024];
108 |
109 | int len = 0;
110 | while ((len = is.read(buf)) > 0) {
111 | os.write(buf, 0, len);
112 | }
113 | is.close();
114 | os.close();
115 | return true;
116 | } catch (final IOException e) {
117 | e.printStackTrace();
118 | }
119 | return false;
120 | }
121 |
122 | private static boolean ensureDirectoryExists(final File f) {
123 | return f.exists() || f.mkdir();
124 | }
125 | }
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/misc/Speaker.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.misc;
2 |
3 | import net.minecraft.world.World;
4 |
5 | public class Speaker {
6 | public int x;
7 | public int y;
8 | public int z;
9 | public World world;
10 |
11 | public Speaker(int x, int y, int z, World w) {
12 | this.x = x;
13 | this.y = y;
14 | this.z = z;
15 | this.world = w;
16 | }
17 | }
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/network/MessageRadioBase.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.network;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 |
6 | import io.netty.buffer.ByteBuf;
7 | import pcl.OpenFM.OpenFM;
8 | import pcl.OpenFM.network.message.BaseRadioMessage;
9 | import cpw.mods.fml.common.network.simpleimpl.IMessage;
10 |
11 | public class MessageRadioBase implements IMessage {
12 | BaseRadioMessage message;
13 | private static int id = 0;
14 | private static Map> idmap = new HashMap>();
15 | private static Map, Integer> msgmap = new HashMap, Integer>();
16 |
17 | public static void registerMessage(Class extends BaseRadioMessage> message) {
18 | idmap.put(id, message);
19 | msgmap.put(message, id++);
20 | }
21 |
22 | public MessageRadioBase() {}
23 |
24 | public MessageRadioBase(BaseRadioMessage message) {
25 | this.message = message;
26 | }
27 |
28 | @Override
29 | public void fromBytes(ByteBuf buf) {
30 | int id = buf.readInt();
31 | if (idmap.containsKey(id)) {
32 | Class extends BaseRadioMessage> radioMessage = idmap.get(id);
33 | try {
34 | message = radioMessage.newInstance();
35 | message.fromBytes(buf);
36 | } catch (InstantiationException | IllegalAccessException e) {
37 | OpenFM.logger.error("Failed to create instance of " + radioMessage.getSimpleName(), e);
38 | }
39 | } else {
40 | OpenFM.logger.error("No radio message for ID: " + id);
41 | }
42 | }
43 |
44 | @Override
45 | public void toBytes(ByteBuf buf) {
46 | if (this.message != null) {
47 | buf.writeInt(msgmap.get(this.message.getClass()));
48 | message.toBytes(buf);
49 | } else {
50 | buf.writeInt(-1);
51 | }
52 | }
53 | }
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/network/PacketHandler.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.network;
2 |
3 | import pcl.OpenFM.network.message.*;
4 | import cpw.mods.fml.common.network.NetworkRegistry;
5 | import cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper;
6 | import cpw.mods.fml.relauncher.Side;
7 |
8 | public class PacketHandler {
9 | public static final SimpleNetworkWrapper INSTANCE = NetworkRegistry.INSTANCE.newSimpleChannel("openfm");
10 |
11 | public static void init() {
12 | INSTANCE.registerMessage(RadioBlockMessageHandler.ServerHandler.class, MessageRadioBase.class, 0, Side.SERVER);
13 | INSTANCE.registerMessage(RadioBlockMessageHandler.ClientHandler.class, MessageRadioBase.class, 1, Side.CLIENT);
14 |
15 | MessageRadioBase.registerMessage(MessageRadioPlaying.class);
16 | MessageRadioBase.registerMessage(MessageRadioSync.class);
17 | MessageRadioBase.registerMessage(MessageRadioAddSpeaker.class);
18 | MessageRadioBase.registerMessage(MessageRadioAddStation.class);
19 | MessageRadioBase.registerMessage(MessageRadioDelStation.class);
20 | MessageRadioBase.registerMessage(MessageRadioLocked.class);
21 | MessageRadioBase.registerMessage(MessageRadioRedstone.class);
22 | MessageRadioBase.registerMessage(MessageRadioReadCard.class);
23 | MessageRadioBase.registerMessage(MessageRadioWriteCard.class);
24 | MessageRadioBase.registerMessage(MessageRadioStreamURL.class);
25 | MessageRadioBase.registerMessage(MessageRadioScreenColor.class);
26 | MessageRadioBase.registerMessage(MessageRadioScreenText.class);
27 | MessageRadioBase.registerMessage(MessageRadioVolume.class);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/network/RadioBlockMessageHandler.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.network;
2 |
3 | import net.minecraft.client.Minecraft;
4 | import net.minecraft.tileentity.TileEntity;
5 | import net.minecraft.world.World;
6 | import cpw.mods.fml.client.FMLClientHandler;
7 | import cpw.mods.fml.common.network.simpleimpl.IMessage;
8 | import cpw.mods.fml.common.network.simpleimpl.IMessageHandler;
9 | import cpw.mods.fml.common.network.simpleimpl.MessageContext;
10 | import pcl.OpenFM.TileEntity.TileEntityRadio;
11 | import pcl.OpenFM.network.message.BaseRadioMessage;
12 |
13 | public class RadioBlockMessageHandler {
14 |
15 | public static class ClientHandler implements IMessageHandler {
16 | @Override
17 | public IMessage onMessage(MessageRadioBase _message, final MessageContext ctx) {
18 | final BaseRadioMessage message = _message.message;
19 |
20 | TileEntity tileEntity = FMLClientHandler.instance().getClient().theWorld.getTileEntity(message.x, message.y, message.z);
21 | if ((tileEntity instanceof TileEntityRadio)) {
22 | message.onMessage((TileEntityRadio) tileEntity, ctx);
23 | }
24 |
25 | return null;
26 | }
27 | }
28 |
29 | public static class ServerHandler implements IMessageHandler {
30 | @Override
31 | public IMessage onMessage(MessageRadioBase _message, final MessageContext ctx) {
32 | final BaseRadioMessage message = _message.message;
33 |
34 | if (message.shouldBroadcast())
35 | PacketHandler.INSTANCE.sendToAll(_message);
36 |
37 | World world = ctx.getServerHandler().playerEntity.worldObj;
38 | TileEntity tileEntity = world.getTileEntity(message.x, message.y, message.z);
39 | if ((tileEntity instanceof TileEntityRadio)) {
40 | message.onMessage((TileEntityRadio) tileEntity, ctx);
41 | }
42 |
43 | return null;
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/network/message/BaseRadioMessage.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.network.message;
2 |
3 | import io.netty.buffer.ByteBuf;
4 | import cpw.mods.fml.common.network.simpleimpl.MessageContext;
5 | import pcl.OpenFM.TileEntity.TileEntityRadio;
6 | import pcl.OpenFM.network.MessageRadioBase;
7 |
8 | public abstract class BaseRadioMessage {
9 | public int x, y, z;
10 |
11 | public BaseRadioMessage() {}
12 |
13 | public BaseRadioMessage(TileEntityRadio radio) {
14 | x = radio.xCoord;
15 | y = radio.yCoord;
16 | z = radio.zCoord;
17 | }
18 |
19 | public abstract void onMessage(TileEntityRadio radio, MessageContext ctx);
20 |
21 | public boolean shouldBroadcast() {
22 | return true;
23 | }
24 |
25 | public MessageRadioBase wrap() {
26 | return new MessageRadioBase(this);
27 | }
28 |
29 | public void fromBytes(ByteBuf buf) {
30 | x = buf.readInt();
31 | y = buf.readInt();
32 | z = buf.readInt();
33 | }
34 |
35 | public void toBytes(ByteBuf buf) {
36 | buf.writeInt(x);
37 | buf.writeInt(y);
38 | buf.writeInt(z);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/network/message/MessageRadioAddSpeaker.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.network.message;
2 |
3 | import io.netty.buffer.ByteBuf;
4 | import cpw.mods.fml.common.network.simpleimpl.MessageContext;
5 | import pcl.OpenFM.TileEntity.TileEntityRadio;
6 | import pcl.OpenFM.misc.Speaker;
7 |
8 | public class MessageRadioAddSpeaker extends BaseRadioMessage {
9 | private int tx, ty, tz;
10 |
11 | public MessageRadioAddSpeaker() {}
12 |
13 | public MessageRadioAddSpeaker(TileEntityRadio radio, Speaker speaker) {
14 | super(radio);
15 | this.tx = speaker.x;
16 | this.ty = speaker.y;
17 | this.tz = speaker.z;
18 | }
19 |
20 | @Override
21 | public void onMessage(TileEntityRadio radio, MessageContext ctx) {
22 | radio.addSpeaker(radio.getWorldObj(), tx, ty, tz);
23 | }
24 |
25 | @Override
26 | public void fromBytes(ByteBuf buf) {
27 | super.fromBytes(buf);
28 | tx = buf.readInt();
29 | ty = buf.readInt();
30 | tz = buf.readInt();
31 | }
32 |
33 | @Override
34 | public void toBytes(ByteBuf buf) {
35 | super.toBytes(buf);
36 | buf.writeInt(tx);
37 | buf.writeInt(ty);
38 | buf.writeInt(tz);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/network/message/MessageRadioAddStation.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.network.message;
2 |
3 | import io.netty.buffer.ByteBuf;
4 | import cpw.mods.fml.common.network.ByteBufUtils;
5 | import cpw.mods.fml.common.network.simpleimpl.MessageContext;
6 | import pcl.OpenFM.TileEntity.TileEntityRadio;
7 |
8 | public class MessageRadioAddStation extends BaseRadioMessage {
9 | private String streamURL;
10 |
11 | public MessageRadioAddStation() {}
12 |
13 | public MessageRadioAddStation(TileEntityRadio radio, String streamURL) {
14 | super(radio);
15 | this.streamURL = streamURL;
16 | }
17 |
18 | @Override
19 | public void onMessage(TileEntityRadio radio, MessageContext ctx) {
20 | if (!radio.stations.contains(streamURL))
21 | radio.addStation(streamURL);
22 | radio.setStationCount(radio.stations.size());
23 | }
24 |
25 | @Override
26 | public void fromBytes(ByteBuf buf) {
27 | super.fromBytes(buf);
28 | streamURL = ByteBufUtils.readUTF8String(buf);
29 | }
30 |
31 | @Override
32 | public void toBytes(ByteBuf buf) {
33 | super.toBytes(buf);
34 | ByteBufUtils.writeUTF8String(buf, streamURL);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/network/message/MessageRadioDelStation.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.network.message;
2 |
3 | import io.netty.buffer.ByteBuf;
4 | import cpw.mods.fml.common.network.ByteBufUtils;
5 | import cpw.mods.fml.common.network.simpleimpl.MessageContext;
6 | import pcl.OpenFM.TileEntity.TileEntityRadio;
7 |
8 | public class MessageRadioDelStation extends BaseRadioMessage {
9 | private String streamURL;
10 |
11 | public MessageRadioDelStation() {}
12 |
13 | public MessageRadioDelStation(TileEntityRadio radio, String streamURL) {
14 | super(radio);
15 | this.streamURL = streamURL;
16 | }
17 |
18 | @Override
19 | public void onMessage(TileEntityRadio radio, MessageContext ctx) {
20 | radio.delStation(streamURL);
21 | radio.setStationCount(radio.stations.size());
22 | }
23 |
24 | @Override
25 | public void fromBytes(ByteBuf buf) {
26 | super.fromBytes(buf);
27 | streamURL = ByteBufUtils.readUTF8String(buf);
28 | }
29 |
30 | @Override
31 | public void toBytes(ByteBuf buf) {
32 | super.toBytes(buf);
33 | ByteBufUtils.writeUTF8String(buf, streamURL);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/network/message/MessageRadioLocked.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.network.message;
2 |
3 | import io.netty.buffer.ByteBuf;
4 | import cpw.mods.fml.common.network.simpleimpl.MessageContext;
5 | import pcl.OpenFM.TileEntity.TileEntityRadio;
6 |
7 | public class MessageRadioLocked extends BaseRadioMessage {
8 | private boolean locked;
9 |
10 | public MessageRadioLocked() {}
11 |
12 | public MessageRadioLocked(TileEntityRadio radio, boolean locked) {
13 | super(radio);
14 | this.locked = locked;
15 | }
16 |
17 | @Override
18 | public void onMessage(TileEntityRadio radio, MessageContext ctx) {
19 | radio.isLocked = locked;
20 | }
21 |
22 | @Override
23 | public void fromBytes(ByteBuf buf) {
24 | super.fromBytes(buf);
25 | locked = buf.readBoolean();
26 | }
27 |
28 | @Override
29 | public void toBytes(ByteBuf buf) {
30 | super.toBytes(buf);
31 | buf.writeBoolean(locked);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/network/message/MessageRadioPlaying.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.network.message;
2 |
3 | import io.netty.buffer.ByteBuf;
4 | import cpw.mods.fml.common.network.simpleimpl.MessageContext;
5 | import pcl.OpenFM.TileEntity.TileEntityRadio;
6 |
7 | public class MessageRadioPlaying extends BaseRadioMessage {
8 | private boolean playing;
9 |
10 | public MessageRadioPlaying() {}
11 |
12 | public MessageRadioPlaying(TileEntityRadio radio, boolean playing) {
13 | super(radio);
14 | this.playing = playing;
15 | }
16 |
17 | public MessageRadioPlaying(int x, int y, int z, boolean playing) {
18 | this.x = x;
19 | this.y = y;
20 | this.z = z;
21 | this.playing = playing;
22 | }
23 |
24 | @Override
25 | public void onMessage(TileEntityRadio radio, MessageContext ctx) {
26 | if (playing) {
27 | try {
28 | radio.startStream();
29 | } catch (Exception e) {
30 | radio.stopStream();
31 | }
32 | } else {
33 | radio.stopStream();
34 | }
35 | }
36 |
37 | @Override
38 | public void fromBytes(ByteBuf buf) {
39 | super.fromBytes(buf);
40 | playing = buf.readBoolean();
41 | }
42 |
43 | @Override
44 | public void toBytes(ByteBuf buf) {
45 | super.toBytes(buf);
46 | buf.writeBoolean(playing);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/network/message/MessageRadioReadCard.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.network.message;
2 |
3 | import cpw.mods.fml.common.network.simpleimpl.MessageContext;
4 | import pcl.OpenFM.TileEntity.TileEntityRadio;
5 |
6 | public class MessageRadioReadCard extends BaseRadioMessage {
7 |
8 | public MessageRadioReadCard() {}
9 |
10 | public MessageRadioReadCard(TileEntityRadio radio) {
11 | super(radio);
12 | }
13 |
14 | @Override
15 | public boolean shouldBroadcast() {
16 | return false;
17 | }
18 |
19 | @Override
20 | public void onMessage(TileEntityRadio radio, MessageContext ctx) {
21 | radio.readDataFromCard();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/network/message/MessageRadioRedstone.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.network.message;
2 |
3 | import io.netty.buffer.ByteBuf;
4 | import cpw.mods.fml.common.network.simpleimpl.MessageContext;
5 | import pcl.OpenFM.TileEntity.TileEntityRadio;
6 |
7 | public class MessageRadioRedstone extends BaseRadioMessage {
8 | private boolean redstone;
9 |
10 | public MessageRadioRedstone() {}
11 |
12 | public MessageRadioRedstone(TileEntityRadio radio, boolean redstone) {
13 | super(radio);
14 | this.redstone = redstone;
15 | }
16 |
17 | @Override
18 | public void onMessage(TileEntityRadio radio, MessageContext ctx) {
19 | radio.listenToRedstone = redstone;
20 | }
21 |
22 | @Override
23 | public void fromBytes(ByteBuf buf) {
24 | super.fromBytes(buf);
25 | redstone = buf.readBoolean();
26 | }
27 |
28 | @Override
29 | public void toBytes(ByteBuf buf) {
30 | super.toBytes(buf);
31 | buf.writeBoolean(redstone);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/network/message/MessageRadioScreenColor.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.network.message;
2 |
3 | import io.netty.buffer.ByteBuf;
4 | import cpw.mods.fml.common.network.simpleimpl.MessageContext;
5 | import pcl.OpenFM.TileEntity.TileEntityRadio;
6 |
7 | public class MessageRadioScreenColor extends BaseRadioMessage {
8 | private int screenColor;
9 |
10 | public MessageRadioScreenColor() {}
11 |
12 | public MessageRadioScreenColor(TileEntityRadio radio, int screenColor) {
13 | super(radio);
14 | this.screenColor = screenColor;
15 | }
16 |
17 | @Override
18 | public void onMessage(TileEntityRadio radio, MessageContext ctx) {
19 | radio.setScreenColor(screenColor);
20 | }
21 |
22 | @Override
23 | public void fromBytes(ByteBuf buf) {
24 | super.fromBytes(buf);
25 | screenColor = buf.readInt();
26 | }
27 |
28 | @Override
29 | public void toBytes(ByteBuf buf) {
30 | super.toBytes(buf);
31 | buf.writeInt(screenColor);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/network/message/MessageRadioScreenText.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.network.message;
2 |
3 | import io.netty.buffer.ByteBuf;
4 | import cpw.mods.fml.common.network.ByteBufUtils;
5 | import cpw.mods.fml.common.network.simpleimpl.MessageContext;
6 | import pcl.OpenFM.TileEntity.TileEntityRadio;
7 |
8 | public class MessageRadioScreenText extends BaseRadioMessage {
9 | private String screenText;
10 |
11 | public MessageRadioScreenText() {}
12 |
13 | public MessageRadioScreenText(TileEntityRadio radio, String screenText) {
14 | super(radio);
15 | this.screenText = screenText;
16 | }
17 |
18 | @Override
19 | public void onMessage(TileEntityRadio radio, MessageContext ctx) {
20 | radio.setScreenText(screenText);
21 | }
22 |
23 | @Override
24 | public void fromBytes(ByteBuf buf) {
25 | super.fromBytes(buf);
26 | screenText = ByteBufUtils.readUTF8String(buf);
27 | }
28 |
29 | @Override
30 | public void toBytes(ByteBuf buf) {
31 | super.toBytes(buf);
32 | ByteBufUtils.writeUTF8String(buf, screenText);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/network/message/MessageRadioStreamURL.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.network.message;
2 |
3 | import io.netty.buffer.ByteBuf;
4 | import cpw.mods.fml.common.network.ByteBufUtils;
5 | import cpw.mods.fml.common.network.simpleimpl.MessageContext;
6 | import pcl.OpenFM.TileEntity.TileEntityRadio;
7 |
8 | public class MessageRadioStreamURL extends BaseRadioMessage {
9 | private String streamURL;
10 |
11 | public MessageRadioStreamURL() {}
12 |
13 | public MessageRadioStreamURL(TileEntityRadio radio, String streamURL) {
14 | super(radio);
15 | this.streamURL = streamURL;
16 | }
17 |
18 | @Override
19 | public void onMessage(TileEntityRadio radio, MessageContext ctx) {
20 | if (radio.streamURL != streamURL) {
21 | if (radio.isPlaying()) {
22 | radio.stopStream();
23 | radio.streamURL = streamURL;
24 | try {
25 | radio.startStream();
26 | } catch (Exception e) {
27 | radio.stopStream();
28 | }
29 | } else {
30 | radio.streamURL = streamURL;
31 | }
32 | }
33 | }
34 |
35 | @Override
36 | public void fromBytes(ByteBuf buf) {
37 | super.fromBytes(buf);
38 | streamURL = ByteBufUtils.readUTF8String(buf);
39 | }
40 |
41 | @Override
42 | public void toBytes(ByteBuf buf) {
43 | super.toBytes(buf);
44 | ByteBufUtils.writeUTF8String(buf, streamURL);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/network/message/MessageRadioSync.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.network.message;
2 |
3 | import io.netty.buffer.ByteBuf;
4 | import cpw.mods.fml.common.network.ByteBufUtils;
5 | import cpw.mods.fml.common.network.simpleimpl.MessageContext;
6 | import pcl.OpenFM.TileEntity.TileEntityRadio;
7 |
8 | public class MessageRadioSync extends BaseRadioMessage {
9 | private String streamURL = "";
10 | private int screenColor = 0x0000FF;
11 | private String screenText = "OpenFM";
12 | private boolean playing;
13 | private float volume;
14 |
15 | public MessageRadioSync() {}
16 |
17 | public MessageRadioSync(TileEntityRadio radio) {
18 | super(radio);
19 | this.streamURL = radio.streamURL;
20 | this.screenColor = radio.getScreenColor();
21 | this.screenText = radio.getScreenText();
22 | this.playing = radio.isPlaying();
23 | this.volume = radio.volume;
24 | }
25 |
26 | @Override
27 | public void onMessage(TileEntityRadio radio, MessageContext ctx) {
28 | radio.streamURL = streamURL;
29 | radio.screenColor = screenColor;
30 | radio.screenText = screenText;
31 | radio.volume = volume;
32 | if (playing) {
33 | try {
34 | radio.startStream();
35 | } catch (Exception e) {
36 | radio.stopStream();
37 | }
38 | } else {
39 | radio.stopStream();
40 | }
41 | }
42 |
43 | @Override
44 | public void fromBytes(ByteBuf buf) {
45 | super.fromBytes(buf);
46 | streamURL = ByteBufUtils.readUTF8String(buf);
47 | screenColor = buf.readInt();
48 | screenText = ByteBufUtils.readUTF8String(buf);
49 | playing = buf.readBoolean();
50 | volume = buf.readFloat();
51 | }
52 |
53 | @Override
54 | public void toBytes(ByteBuf buf) {
55 | super.toBytes(buf);
56 | ByteBufUtils.writeUTF8String(buf, streamURL);
57 | buf.writeInt(screenColor);
58 | ByteBufUtils.writeUTF8String(buf, screenText);
59 | buf.writeBoolean(playing);
60 | buf.writeFloat(volume);
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/network/message/MessageRadioVolume.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.network.message;
2 |
3 | import io.netty.buffer.ByteBuf;
4 | import cpw.mods.fml.common.network.simpleimpl.MessageContext;
5 | import pcl.OpenFM.TileEntity.TileEntityRadio;
6 |
7 | public class MessageRadioVolume extends BaseRadioMessage {
8 | private float volume;
9 |
10 | public MessageRadioVolume() {}
11 |
12 | public MessageRadioVolume(TileEntityRadio radio, float v) {
13 | super(radio);
14 | this.volume = v;
15 | }
16 |
17 | @Override
18 | public void onMessage(TileEntityRadio radio, MessageContext ctx) {
19 | if ((volume > 0.0F) && (volume <= 1.0F)) {
20 | radio.volume = volume;
21 | }
22 | }
23 |
24 | @Override
25 | public void fromBytes(ByteBuf buf) {
26 | super.fromBytes(buf);
27 | volume = buf.readFloat();
28 | }
29 |
30 | @Override
31 | public void toBytes(ByteBuf buf) {
32 | super.toBytes(buf);
33 | buf.writeFloat(volume);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/network/message/MessageRadioWriteCard.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.network.message;
2 |
3 | import cpw.mods.fml.common.network.simpleimpl.MessageContext;
4 | import pcl.OpenFM.TileEntity.TileEntityRadio;
5 |
6 | public class MessageRadioWriteCard extends BaseRadioMessage {
7 |
8 | public MessageRadioWriteCard() {}
9 |
10 | public MessageRadioWriteCard(TileEntityRadio radio) {
11 | super(radio);
12 | }
13 |
14 | @Override
15 | public boolean shouldBroadcast() {
16 | return false;
17 | }
18 |
19 | @Override
20 | public void onMessage(TileEntityRadio radio, MessageContext ctx) {
21 | radio.writeDataToCard();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/player/AudioPlayer.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.player;
2 |
3 | import java.io.IOException;
4 | import java.io.InputStream;
5 | import java.nio.ByteBuffer;
6 | import java.nio.ByteOrder;
7 | import java.nio.IntBuffer;
8 |
9 | import javax.sound.sampled.AudioFormat;
10 | import javax.sound.sampled.AudioFormat.Encoding;
11 | import javax.sound.sampled.AudioInputStream;
12 | import javax.sound.sampled.AudioSystem;
13 | import javax.sound.sampled.UnsupportedAudioFileException;
14 |
15 | import org.lwjgl.BufferUtils;
16 | import org.lwjgl.openal.AL10;
17 |
18 | import javazoom.jl.player.advanced.PlaybackEvent;
19 | import net.minecraft.client.Minecraft;
20 | import net.minecraft.client.audio.SoundCategory;
21 | import net.minecraft.world.World;
22 | import pcl.OpenFM.OpenFM;
23 |
24 | public class AudioPlayer {
25 |
26 | protected IntBuffer buffer;
27 | protected IntBuffer source;
28 | protected float volume = 0.0F;
29 | protected int posX;
30 | protected int posY;
31 | protected int posZ;
32 | protected World world;
33 | protected boolean playing = false;
34 | protected InputStream stream;
35 | private PlaybackListener listener;
36 |
37 | public AudioPlayer(InputStream stream) {
38 | this.stream = stream;
39 | }
40 |
41 | protected boolean alError() {
42 | if (AL10.alGetError() != AL10.AL_NO_ERROR) {
43 | OpenFM.logger.error(String.format("AL10 Error: %d: %s", AL10.alGetError(), AL10.alGetString(AL10.alGetError())));
44 | return true;
45 | }
46 | return false;
47 | }
48 |
49 | public void setID(World w, int x, int y, int z) {
50 | this.posX = x;
51 | this.posY = y;
52 | this.posZ = z;
53 | this.world = w;
54 | }
55 |
56 | public void setPlayBackListener(PlaybackListener listener) {
57 | this.listener = listener;
58 | }
59 |
60 | public PlaybackListener getPlayBackListener() {
61 | return this.listener;
62 | }
63 |
64 | private AudioFormat getOutFormat(AudioFormat inFormat) {
65 | final int ch = inFormat.getChannels();
66 | final float rate = inFormat.getSampleRate();
67 | return new AudioFormat(Encoding.PCM_SIGNED, 44100, 16, 2, 4, 44100, false);
68 | }
69 |
70 | private PlayBackEvent createEvent(int id) {
71 | return new PlayBackEvent(this, id, 0);
72 | }
73 |
74 | public void play() throws UnsupportedAudioFileException, IOException {
75 | AudioInputStream in = (AudioInputStream) this.stream;
76 |
77 | final AudioFormat outFormat = getOutFormat(in.getFormat());
78 |
79 | this.source = BufferUtils.createIntBuffer(1);
80 |
81 | AL10.alGenSources(this.source);
82 | if (alError()) {
83 | close();
84 | return;
85 | }
86 |
87 | AL10.alSourcei(this.source.get(0), AL10.AL_LOOPING, AL10.AL_FALSE);
88 | AL10.alSourcef(this.source.get(0), AL10.AL_PITCH, 1.0f);
89 | AL10.alSourcef(this.source.get(0), AL10.AL_GAIN, this.volume * Minecraft.getMinecraft().gameSettings.getSoundLevel(SoundCategory.RECORDS));
90 |
91 | if (alError()) {
92 | close();
93 | return;
94 | }
95 |
96 | this.playing = true;
97 | if (this.listener != null)
98 | {
99 | this.listener.playbackStarted(createEvent(PlaybackEvent.STARTED));
100 | }
101 | stream(AudioSystem.getAudioInputStream(outFormat, in));
102 |
103 | if (this.playing) {
104 | while (AL10.alGetSourcei(this.source.get(0), AL10.AL_SOURCE_STATE) == AL10.AL_PLAYING) {
105 | try {
106 | Thread.sleep(1);
107 | } catch (InterruptedException e) {}
108 | }
109 | }
110 |
111 | close();
112 | }
113 |
114 | private void stream(AudioInputStream in) throws IOException {
115 | AudioFormat format = in.getFormat();
116 |
117 | byte[] databuffer = new byte[65536];
118 | for (int n = 0; this.playing && n != -1; n = in.read(databuffer, 0, databuffer.length)) {
119 | if (n > 0) {
120 | if (this.buffer == null) {
121 | this.buffer = BufferUtils.createIntBuffer(1);
122 | } else {
123 | int processed = AL10.alGetSourcei(this.source.get(0), AL10.AL_BUFFERS_PROCESSED);
124 | if (processed > 0) {
125 | AL10.alSourceUnqueueBuffers(this.source.get(0), this.buffer);
126 | alError();
127 | }
128 | }
129 |
130 | AL10.alGenBuffers(this.buffer);
131 | ByteBuffer data = (ByteBuffer) BufferUtils.createByteBuffer(n).order(ByteOrder.LITTLE_ENDIAN).put(databuffer, 0, n).flip();
132 | AL10.alBufferData(this.buffer.get(0), (format.getChannels() > 1) ? AL10.AL_FORMAT_STEREO16 : AL10.AL_FORMAT_MONO16, data, (int)format.getSampleRate());
133 | alError();
134 | AL10.alSourceQueueBuffers(this.source.get(0), buffer);
135 |
136 | int state = AL10.alGetSourcei(this.source.get(0), AL10.AL_SOURCE_STATE);
137 | if(this.playing && state != AL10.AL_PLAYING) {
138 | AL10.alSourcePlay(this.source.get(0));
139 | }
140 | }
141 | }
142 | }
143 |
144 | protected void close() {
145 | this.playing = false;
146 | if (this.listener != null)
147 | {
148 | this.listener.playbackFinished(createEvent(PlaybackEvent.STOPPED));
149 | }
150 | if (this.source != null) {
151 | AL10.alSourceStop(this.source);
152 | AL10.alDeleteSources(this.source);
153 | this.source = null;
154 | }
155 | if (this.buffer != null) {
156 | AL10.alDeleteBuffers(this.buffer);
157 | this.buffer = null;
158 | }
159 | }
160 |
161 | public void stop() {
162 | this.playing = false;
163 | if (this.source != null) {
164 | AL10.alSourcef(this.source.get(0), AL10.AL_GAIN, 0.0f);
165 | AL10.alSourceStop(this.source);
166 | }
167 | }
168 |
169 | public void setVolume(float f) {
170 | this.volume = f;
171 | if (this.playing && this.source != null) {
172 | AL10.alSourcef(this.source.get(0), AL10.AL_GAIN, f * Minecraft.getMinecraft().gameSettings.getSoundLevel(SoundCategory.RECORDS));
173 | }
174 | }
175 |
176 | public float getVolume() {
177 | return this.volume;
178 | }
179 |
180 | public boolean isPlaying() {
181 | return this.playing;
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/player/MarkErrorInputStream.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.player;
2 |
3 | import java.io.FilterInputStream;
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 |
7 | /*
8 | * An Erroring InputStream when mark limits are exceeded
9 | * Fixes MP3SPI infinitely reading until it finds a false positive
10 | */
11 | public class MarkErrorInputStream extends FilterInputStream {
12 |
13 | long pos;
14 | long marklimit;
15 | boolean mark_active = false;
16 |
17 | public MarkErrorInputStream(InputStream proxy) {
18 | super(proxy);
19 | if (!proxy.markSupported()) {
20 | throw new IllegalArgumentException("input stream does not support mark");
21 | }
22 | }
23 |
24 | private long limit(long n) throws IOException {
25 | if (mark_active) {
26 | long avail = (marklimit - pos);
27 | if (avail <= 0) {
28 | in.reset();
29 | throw new IOException("mark limit exceeded");
30 | } else if (avail < n) {
31 | return avail;
32 | }
33 | }
34 | return n;
35 | }
36 |
37 | private void addPos(long n) throws IOException {
38 | if (n >= 0 && mark_active) {
39 | pos += n;
40 | }
41 | }
42 |
43 | @Override
44 | public int read() throws IOException {
45 | limit(1);
46 | int ret = super.read();
47 | addPos(1);
48 | return ret;
49 | }
50 |
51 | @Override
52 | public int read(byte[] bts) throws IOException {
53 | int len = (int) limit(bts.length);
54 | int ret = super.read(bts, 0, len);
55 | addPos(ret);
56 | return ret;
57 | }
58 |
59 | @Override
60 | public int read(byte[] bts, int off, int len) throws IOException {
61 | len = (int) limit(len);
62 | int ret = super.read(bts, off, len);
63 | addPos(ret);
64 | return ret;
65 | }
66 |
67 | @Override
68 | public long skip(long ln) throws IOException {
69 | ln = limit(ln);
70 | long ret = super.skip(ln);
71 | addPos(ret);
72 | return ret;
73 | }
74 |
75 | @Override
76 | public synchronized void mark(int readlimit) {
77 | // prevent mp3spi's insane limit of 4096001.
78 | if (readlimit == 4096001) {
79 | readlimit = 4096;
80 | }
81 | super.mark(readlimit);
82 | mark_active = true;
83 | marklimit = readlimit;
84 | pos = 0;
85 | }
86 |
87 | @Override
88 | public synchronized void reset() throws IOException {
89 | super.reset();
90 | mark_active = false;
91 | }
92 |
93 | @Override
94 | public int available() throws IOException {
95 | if (mark_active && pos >= marklimit)
96 | return 0; // Allows BufferedInputStream to stop reading.
97 | return (int) limit(super.available());
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/player/PlayBackEvent.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.player;
2 |
3 | import pcl.OpenFM.player.AudioPlayer;
4 |
5 | public class PlayBackEvent {
6 | public static int STOPPED = 1;
7 | public static int STARTED = 2;
8 |
9 | private AudioPlayer source;
10 | private int frame;
11 | private int id;
12 |
13 | public PlayBackEvent(AudioPlayer source, int id, int frame)
14 | {
15 | this.id = id;
16 | this.source = source;
17 | this.frame = frame;
18 | }
19 |
20 | public int getId()
21 | {
22 | return this.id;
23 | }
24 |
25 | public void setId(int id) {
26 | this.id = id;
27 | }
28 |
29 | public int getFrame()
30 | {
31 | return this.frame;
32 | }
33 |
34 | public void setFrame(int frame) {
35 | this.frame = frame;
36 | }
37 |
38 | public AudioPlayer getSource()
39 | {
40 | return this.source;
41 | }
42 |
43 | public void setSource(AudioPlayer source) {
44 | this.source = source;
45 | }
46 | }
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/player/PlaybackListener.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.player;
2 |
3 | public abstract class PlaybackListener {
4 | public void playbackStarted(PlayBackEvent evt) {}
5 |
6 | public void playbackFinished(PlayBackEvent evt) {}
7 | }
--------------------------------------------------------------------------------
/src/main/java/pcl/OpenFM/player/PlayerDispatcher.java:
--------------------------------------------------------------------------------
1 | package pcl.OpenFM.player;
2 |
3 | import java.io.BufferedInputStream;
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 |
7 | import javax.sound.sampled.AudioInputStream;
8 | import javax.sound.sampled.AudioSystem;
9 | import javax.sound.sampled.UnsupportedAudioFileException;
10 |
11 | import com.squareup.okhttp.OkHttpClient;
12 | import com.squareup.okhttp.Request;
13 | import com.squareup.okhttp.Response;
14 |
15 | import cpw.mods.fml.client.FMLClientHandler;
16 | import pcl.OpenFM.OpenFM;
17 | import pcl.OpenFM.TileEntity.TileEntityRadio;
18 | import pcl.OpenFM.network.PacketHandler;
19 | import pcl.OpenFM.network.message.MessageRadioPlaying;
20 | import net.minecraft.client.Minecraft;
21 | import net.minecraft.client.audio.SoundCategory;
22 | import net.minecraft.util.ChatComponentTranslation;
23 | import net.minecraft.world.World;
24 |
25 | public class PlayerDispatcher extends PlaybackListener implements Runnable {
26 | private String streamURL;
27 | private AudioPlayer player;
28 | private TileEntityRadio radio;
29 | private Thread pThread;
30 | private int x;
31 | private int y;
32 | private int z;
33 | private World world;
34 |
35 | public PlayerDispatcher(TileEntityRadio radio, String streamURL, World w, int x, int y, int z)
36 | {
37 | try
38 | {
39 | this.world = w;
40 | this.radio = radio;
41 | this.x = x;
42 | this.y = y;
43 | this.z = z;
44 | this.streamURL = streamURL;
45 | this.pThread = new Thread(this);
46 | this.pThread.start();
47 | }
48 | catch (Exception e)
49 | {
50 | e.printStackTrace();
51 | }
52 | }
53 |
54 | @Override
55 | public void run()
56 | {
57 | OkHttpClient client = new OkHttpClient();
58 | Request request = null;
59 | try {
60 | request = new Request.Builder().url(streamURL)
61 | //.addHeader("Icy-MetaData", "1")
62 | .build();
63 | } catch (IllegalArgumentException e1) {
64 | streamURL = null;
65 | OpenFM.logger.warn(e1);
66 | return;
67 | }
68 | Response response = null;
69 | AudioInputStream audioStream = null;
70 | try {
71 | response = client.newCall(request).execute();
72 | } catch (IOException e1) {
73 | streamURL = null;
74 | OpenFM.logger.warn(e1);
75 | return;
76 | }
77 | OpenFM.logger.info("Content-Type: " + response.header("Content-Type", "unknown"));
78 | InputStream bis = null;
79 | try {
80 | bis = new MarkErrorInputStream(new BufferedInputStream(response.body().byteStream()));
81 | audioStream = AudioSystem.getAudioInputStream(bis);
82 | } catch (IOException | UnsupportedAudioFileException e1) {
83 | streamURL = null;
84 | OpenFM.logger.warn(e1);
85 | return;
86 | }
87 | OpenFM.logger.info("Starting Stream: " + streamURL + " at X:" + x + " Y:" + y + " Z:" + z);
88 | try
89 | {
90 | this.player = new AudioPlayer(audioStream);
91 | this.player.setID(this.world, this.x, this.y, this.z);
92 | this.player.setPlayBackListener(this);
93 | this.player.play();
94 | }
95 | catch (Exception e)
96 | {
97 | if (this.player != null) {
98 | this.player.close();
99 | }
100 | PacketHandler.INSTANCE.sendToServer(new MessageRadioPlaying(this.x, this.y, this.z, false).wrap());
101 | FMLClientHandler.instance().getClient().thePlayer.addChatMessage(new ChatComponentTranslation("msg.OpenFM.invalid_link", new Object[0]));
102 | OpenFM.logger.error(e);
103 | e.printStackTrace();
104 | }
105 | }
106 |
107 | public void stop()
108 | {
109 | if ((this.player != null) && (isPlaying()))
110 | {
111 | this.player.stop();
112 | }
113 | }
114 |
115 | @Override
116 | public void playbackStarted(PlayBackEvent evt) {}
117 |
118 | @Override
119 | public void playbackFinished(PlayBackEvent evt) {}
120 |
121 | public boolean isPlaying()
122 | {
123 | if (this.player != null)
124 | return this.player.isPlaying();
125 | else
126 | return this.pThread.isAlive();
127 | }
128 |
129 | public void setVolume(float f)
130 | {
131 | if (this.player != null)
132 | this.player.setVolume(f);
133 | }
134 |
135 | public float getVolume()
136 | {
137 | if (this.player != null)
138 | return this.player.getVolume() / Minecraft.getMinecraft().gameSettings.getSoundLevel(SoundCategory.RECORDS);
139 | else
140 | return 0;
141 | }
142 | }
--------------------------------------------------------------------------------
/src/main/resources/assets/openfm/deps/jaad-0.8.5.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PC-Logix/OpenFM/1f364f36fd13655f45e5fe5601004f8b76bb02ec/src/main/resources/assets/openfm/deps/jaad-0.8.5.jar
--------------------------------------------------------------------------------
/src/main/resources/assets/openfm/deps/mp3spi-1.9.5-1.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PC-Logix/OpenFM/1f364f36fd13655f45e5fe5601004f8b76bb02ec/src/main/resources/assets/openfm/deps/mp3spi-1.9.5-1.jar
--------------------------------------------------------------------------------
/src/main/resources/assets/openfm/deps/vorbisspi-1.0.3-1.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PC-Logix/OpenFM/1f364f36fd13655f45e5fe5601004f8b76bb02ec/src/main/resources/assets/openfm/deps/vorbisspi-1.0.3-1.jar
--------------------------------------------------------------------------------
/src/main/resources/assets/openfm/lang/en_US.lang:
--------------------------------------------------------------------------------
1 | tile.OpenFM.Radio.name=Radio
2 | tile.OpenFM.Speaker.name=Speaker
3 | item.OpenFM.Tuner.name=Radio Tuner
4 | item.OpenFM.MemoryCard.name=Memory Card
5 | itemGroup.OpenFM.tabOpenFM=OpenFM
6 | gui.string.OpenFM.PlayButton=Play
7 | gui.string.OpenFM.StopButton=Stop
8 | gui.string.OpenFM.VolumeUp=Volume Up
9 | gui.string.OpenFM.VolumeDown=Volume Down
10 | gui.string.OpenFM.ScrollLeft=Previous Bookmark
11 | gui.string.OpenFM.ScrollRight=Next Bookmark
12 | gui.string.OpenFM.Save=Save Bookmark
13 | gui.string.OpenFM.Delete=Delete Bookmark
14 | gui.string.OpenFM.Paste=Paste
15 | gui.string.OpenFM.Clear=Clear
16 | gui.string.OpenFM.Close=Close
17 | gui.string.OpenFM.Lock=Lock
18 | gui.string.OpenFM.Unlock=Unlock
19 | gui.string.OpenFM.RedstoneOn=Redstone On
20 | gui.string.OpenFM.RedstoneOff=Redstone Off
21 | gui.string.OpenFM.ScreenColor=Screen Color
22 | gui.string.OpenFM.ScreenText=Screen Text
23 | gui.string.OpenFM.SaveToCard=Save to Memory Card
24 | gui.string.OpenFM.LoadFromCard=Load from Memory Card
25 | msg.OpenFM.selected_speaker=[OpenFM] Selected Speaker
26 | msg.OpenFM.added_speaker=[OpenFM] Speaker Added
27 | msg.OpenFM.failed_adding_speaker_limit=[OpenFM] Could not add speaker. Max 10 allowed!
28 | msg.OpenFM.failed_adding_speaker_exists=[OpenFM] That speaker is already bound to this radio!
29 | msg.OpenFM.failed_adding_speaker_unknown=[OpenFM] Could not add speaker. Unknown error!
30 | msg.OpenFM.not_correct_stream=[OpenFM] Invalid StreamURL.
31 | msg.OpenFM.invalid_link=[OpenFM] Stream is incorrect format.
32 | msg.OpenFM.failed_adding_speaker_not_selected=[OpenFM] No speaker selected!
--------------------------------------------------------------------------------
/src/main/resources/assets/openfm/lang/ru_RU.lang:
--------------------------------------------------------------------------------
1 | tile.OpenFM.Radio.name=Радио
2 | tile.OpenFM.Speaker.name=Динамик
3 | item.OpenFM.Tuner.name=Радио-тюнер
4 | item.OpenFM.MemoryCard.name=Карта памяти
5 | itemGroup.OpenFM.tabOpenFM=OpenFM
6 | gui.string.OpenFM.PlayButton=Играть
7 | gui.string.OpenFM.StopButton=Стоп
8 | gui.string.OpenFM.VolumeUp=Увеличить громкость
9 | gui.string.OpenFM.VolumeDown=Уменьшить громкость
10 | gui.string.OpenFM.ScrollLeft=Предыдущая закладка
11 | gui.string.OpenFM.ScrollRight=Следующая закладка
12 | gui.string.OpenFM.Save=Сохранить закладку
13 | gui.string.OpenFM.Delete=Удалить закладку
14 | gui.string.OpenFM.Paste=Вставить
15 | gui.string.OpenFM.Clear=Очистить
16 | gui.string.OpenFM.Close=Закрыть
17 | gui.string.OpenFM.Lock=Заблокировать
18 | gui.string.OpenFM.Unlock=Разблокировать
19 | gui.string.OpenFM.RedstoneOn=Включен редстоун
20 | gui.string.OpenFM.RedstoneOff=Выключен редстоун
21 | gui.string.OpenFM.ScreenColor=Цвет экрана
22 | gui.string.OpenFM.ScreenText=Текст на экране
23 | gui.string.OpenFM.SaveToCard=Сохранить на карту памяти
24 | gui.string.OpenFM.LoadFromCard=Загрузить с карты памяти
25 | msg.OpenFM.selected_speaker=[OpenFM] Выбран динамик
26 | msg.OpenFM.added_speaker=[OpenFM] Добавлен динамик
27 | msg.OpenFM.failed_adding_speaker_limit=[OpenFM] Неудалось добавить динамик. Максимальное количество 10!
28 | msg.OpenFM.failed_adding_speaker_exists=[OpenFM] Этот динамик уже привязан к этому радио!
29 | msg.OpenFM.failed_adding_speaker_unknown=[OpenFM] Неудалось добавить динамик. Неизвестная ошибка!
30 | msg.OpenFM.not_correct_stream=[OpenFM] Неправильная ссылка на радиопоток.
31 | msg.OpenFM.invalid_link=[OpenFM] Поток в некорректном формате.
32 | msg.OpenFM.failed_adding_speaker_not_selected=[OpenFM] Нет выбранных динамиков!
--------------------------------------------------------------------------------
/src/main/resources/assets/openfm/lang/zh_CN.lang:
--------------------------------------------------------------------------------
1 | tile.OpenFM.Radio.name=电台
2 | tile.OpenFM.Speaker.name=扬声器
3 | item.OpenFM.Tuner.name=电台调频器
4 | item.OpenFM.MemoryCard.name=内存卡
5 | itemGroup.OpenFM.tabOpenFM=OepnFM
6 | gui.string.OpenFM.PlayButton=播放
7 | gui.string.OpenFM.StopButton=停止
8 | gui.string.OpenFM.VolumeUp=音量加
9 | gui.string.OpenFM.VolumeDown=音量减
10 | gui.string.OpenFM.ScrollLeft=上一个收藏
11 | gui.string.OpenFM.ScrollRight=下一个收藏
12 | gui.string.OpenFM.Save=保存收藏
13 | gui.string.OpenFM.Delete=删除收藏
14 | gui.string.OpenFM.Paste=粘贴
15 | gui.string.OpenFM.Clear=清除
16 | gui.string.OpenFM.Close=关闭
17 | gui.string.OpenFM.Lock=锁定
18 | gui.string.OpenFM.Unlock=解锁
19 | gui.string.OpenFM.RedstoneOn=红石开启
20 | gui.string.OpenFM.RedstoneOff=红石关闭
21 | gui.string.OpenFM.ScreenColor=屏幕颜色
22 | gui.string.OpenFM.ScreenText=屏幕文字
23 | gui.string.OpenFM.SaveToCard=保存到内存卡中
24 | gui.string.OpenFM.LoadFromCard=从内存卡加载
25 | msg.OpenFM.selected_speaker=[OpenFM]选择扬声器.
26 | msg.OpenFM.added_speaker=[OpenFM]已添加扬声器.
27 | msg.OpenFM.failed_adding_speaker_limit=[OpenFM]最多只允许绑定10个扬声器.
28 | msg.OpenFM.failed_adding_speaker_exists=[OpenFM]该扬声器已经绑定到电台.
29 | msg.OpenFM.failed_adding_speaker_unknown=[OpenFM]未知错误,添加扬声器错误.
30 | msg.OpenFM.not_correct_stream=[OpenFM]错误的链接.
31 | msg.OpenFM.invalid_link=[OpenFM]错误的格式.
32 | msg.OpenFM.failed_adding_speaker_not_selected=[OpenFM]没有扬声器.
--------------------------------------------------------------------------------
/src/main/resources/assets/openfm/lang/zh_TW.lang:
--------------------------------------------------------------------------------
1 | tile.OpenFM.Radio.name=無線電收音機
2 | tile.OpenFM.Speaker.name=喇叭/揚聲器
3 | item.OpenFM.Tuner.name=無線電調諧器
4 | item.OpenFM.MemoryCard.name=記憶卡
5 | itemGroup.OpenFM.tabOpenFM=OpenFM
6 | gui.string.OpenFM.PlayButton=播放
7 | gui.string.OpenFM.StopButton=停止
8 | gui.string.OpenFM.VolumeUp=音量+
9 | gui.string.OpenFM.VolumeDown=音量—
10 | gui.string.OpenFM.ScrollLeft=上一個收藏
11 | gui.string.OpenFM.ScrollRight=下一個收藏
12 | gui.string.OpenFM.Save=儲存收藏
13 | gui.string.OpenFM.Delete=刪除收藏
14 | gui.string.OpenFM.Paste=貼上
15 | gui.string.OpenFM.Clear=清除
16 | gui.string.OpenFM.Close=關閉
17 | gui.string.OpenFM.Lock=鎖定
18 | gui.string.OpenFM.Unlock=解鎖
19 | gui.string.OpenFM.RedstoneOn=紅石開啟
20 | gui.string.OpenFM.RedstoneOff=紅石關閉
21 | gui.string.OpenFM.ScreenColor=屏幕顏色
22 | gui.string.OpenFM.ScreenText=屏幕文字
23 | gui.string.OpenFM.SaveToCard=儲存至記憶卡
24 | gui.string.OpenFM.LoadFromCard=從記憶卡載入
25 | msg.OpenFM.selected_speaker=[OpenFM] 選擇喇叭/揚聲器
26 | msg.OpenFM.added_speaker=[OpenFM] 已添加喇叭/揚聲器
27 | msg.OpenFM.failed_adding_speaker_limit=[OpenFM] 無法添加喇叭/揚聲器。只允許綁定最多10個。
28 | msg.OpenFM.failed_adding_speaker_exists=[OpenFM] 該喇叭/揚聲器已被綁定至這個無線電收音機!
29 | msg.OpenFM.failed_adding_speaker_unknown=[OpenFM] 無法添加喇叭/揚聲器。未知錯誤!
30 | msg.OpenFM.not_correct_stream=[OpenFM] 錯誤的廣播連結!
31 | msg.OpenFM.invalid_link=[OpenFM] 錯誤的廣播制式!
32 | msg.OpenFM.failed_adding_speaker_not_selected=[OpenFM] 沒有喇叭/揚聲器!
33 |
--------------------------------------------------------------------------------
/src/main/resources/assets/openfm/textures/blocks/radio_front.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PC-Logix/OpenFM/1f364f36fd13655f45e5fe5601004f8b76bb02ec/src/main/resources/assets/openfm/textures/blocks/radio_front.png
--------------------------------------------------------------------------------
/src/main/resources/assets/openfm/textures/blocks/radio_side.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PC-Logix/OpenFM/1f364f36fd13655f45e5fe5601004f8b76bb02ec/src/main/resources/assets/openfm/textures/blocks/radio_side.png
--------------------------------------------------------------------------------
/src/main/resources/assets/openfm/textures/blocks/speaker_rear.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PC-Logix/OpenFM/1f364f36fd13655f45e5fe5601004f8b76bb02ec/src/main/resources/assets/openfm/textures/blocks/speaker_rear.png
--------------------------------------------------------------------------------
/src/main/resources/assets/openfm/textures/blocks/speaker_side.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PC-Logix/OpenFM/1f364f36fd13655f45e5fe5601004f8b76bb02ec/src/main/resources/assets/openfm/textures/blocks/speaker_side.png
--------------------------------------------------------------------------------
/src/main/resources/assets/openfm/textures/gui/buttons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PC-Logix/OpenFM/1f364f36fd13655f45e5fe5601004f8b76bb02ec/src/main/resources/assets/openfm/textures/gui/buttons.png
--------------------------------------------------------------------------------
/src/main/resources/assets/openfm/textures/gui/gui_radio.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PC-Logix/OpenFM/1f364f36fd13655f45e5fe5601004f8b76bb02ec/src/main/resources/assets/openfm/textures/gui/gui_radio.png
--------------------------------------------------------------------------------
/src/main/resources/assets/openfm/textures/items/ItemMemoryCard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PC-Logix/OpenFM/1f364f36fd13655f45e5fe5601004f8b76bb02ec/src/main/resources/assets/openfm/textures/items/ItemMemoryCard.png
--------------------------------------------------------------------------------
/src/main/resources/assets/openfm/textures/items/ItemTuner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PC-Logix/OpenFM/1f364f36fd13655f45e5fe5601004f8b76bb02ec/src/main/resources/assets/openfm/textures/items/ItemTuner.png
--------------------------------------------------------------------------------
/src/main/resources/mcmod.info:
--------------------------------------------------------------------------------
1 | {
2 | "modListVersion": 2,
3 | "modList": [{
4 | "modid": "openfm",
5 | "name": "OpenFM",
6 | "description": "Streaming radio in Minecraft! With optional OpenComputers support.",
7 | "version": "${version}",
8 | "mcversion": "${mcversion}",
9 | "url": "http://minecraft.curseforge.com/projects/openfm",
10 | "updateUrl": "",
11 | "authorList": [ "MichiyoRavencroft"],
12 | "credits": "Authored by MichiyoRavencroft, based on an original idea by DragonbornSR",
13 | "logoFile": "/OpenFM.logo.png",
14 | "screenshots": [ ],
15 | "parent": "",
16 | "requiredMods": [ "Forge" ],
17 | "dependencies": [ "OpenComputers" ],
18 | "useDependencyInformation": true
19 | }]
20 | }
--------------------------------------------------------------------------------