Skip to content

Instantly share code, notes, and snippets.

@Elix-x
Created November 6, 2015 19:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Elix-x/4a17ecda55c0bc7fbcfe to your computer and use it in GitHub Desktop.
Save Elix-x/4a17ecda55c0bc7fbcfe to your computer and use it in GitHub Desktop.
KBO Double Click Bug Code
public class AdvancedKeyBinding implements IAdvancedKeyBinding {
public final KeyBindingsHandler HANDLER;
public String name;
public String displayName;
public String categoryName;
protected final int[] defaultKeys;
protected int[] keys;
protected boolean pressed = false;
public AdvancedKeyBinding(KeyBindingsHandler handler, String name, String displayName, String categoryName, int... defaultKeys) {
this.HANDLER = handler;
this.name = name;
this.displayName = displayName;
this.categoryName = categoryName;
this.defaultKeys = defaultKeys;
this.keys = ArrayUtils.clone(defaultKeys);
}
@Override
public KeyBindingsHandler getHandler() {
return HANDLER;
}
@Override
public String getName() {
return name;
}
@Override
public String getDisplayName() {
return displayName;
}
@Override
public String getCategoryName() {
return categoryName;
}
@Override
public boolean isPressed() {
return pressed;
}
@Override
public void setPressed(boolean pressed) {
this.pressed = pressed;
}
@Override
public void updateState() {
pressed = keys.length > 0;
for(int key : keys){
pressed &= HANDLER.API.INPUT.isPressed(key);
}
}
@Override
public void performAction() {
}
@Override
public void reset() {
this.keys = ArrayUtils.clone(defaultKeys);
}
@Override
public int[] save() {
return ArrayUtils.clone(keys);
}
@Override
public void load(int[] saved) {
keys = ArrayUtils.clone(saved);
}
}
public interface IAdvancedKeyBinding {
public KeyBindingsHandler getHandler();
public String getName();
public String getDisplayName();
public String getCategoryName();
public boolean isPressed();
public void setPressed(boolean pressed);
public void updateState();
public void performAction();
public void reset();
public int[] save();
public void load(int[] saved);
}
public class InputHandler {
public final Logger logger = LogManager.getLogger("Input Handler");
public final KBOApi api;
private Map<Integer, Boolean> keyStatesMap = new HashMap<Integer, Boolean>();
private int maxKeyboardId = Keyboard.getKeyCount();
private int maxMouseId = Mouse.getButtonCount();
private Controller gamepad;
private int maxGamepadId = 0;
public InputHandler(KBOApi api) {
this.api = api;
try {
Controllers.create();
} catch (LWJGLException e) {
logger.error("Caught exceзtion while creating controllers: ", e);
}
for(int i = 0; i < Controllers.getControllerCount(); i++){
Controller controller = Controllers.getController(i);
if(!controller.getName().toLowerCase().contains("keyboard") && !controller.getName().toLowerCase().contains("mouse")){
this.gamepad = controller;
this.maxGamepadId = controller.getButtonCount();
}
}
}
public void tick(){
for(int i = 0; i < maxKeyboardId; i++){
setKeyboardKeyPressed(i, Keyboard.isKeyDown(i));
}
for(int i = 0; i < maxMouseId; i++){
setMouseKeyPressed(i, Mouse.isButtonDown(i));
}
for(int i = 0; i < maxGamepadId; i++){
setGamepadKeyPressed(i, Keyboard.isKeyDown(i));
}
}
public boolean isPressed(int key){
Boolean pressed = keyStatesMap.get(key);
return pressed == null ? false : pressed;
}
public void setPressed(int key, boolean pressed){
keyStatesMap.put(key, pressed);
}
/*
* Keyboard
*/
public boolean isKeyboardKeyPressed(int key){
if(key > maxKeyboardId) maxKeyboardId = key;
return isPressed(key);
}
public void setKeyboardKeyPressed(int key, boolean pressed){
if(key > maxKeyboardId) maxKeyboardId = key;
setPressed(key, pressed);
}
public boolean isKeyboardKeyPressed(String key){
return isKeyboardKeyPressed(Keyboard.getKeyIndex(key));
}
public void setKeyboardKeyPressed(String key, boolean pressed){
setKeyboardKeyPressed(Keyboard.getKeyIndex(key), pressed);
}
/*
* Mouse
*/
public boolean isMouseKeyPressed(int key){
if(key > maxMouseId) maxMouseId = key;
return isPressed(-100 + key);
}
public void setMouseKeyPressed(int key, boolean pressed){
if(key > maxMouseId) maxMouseId = key;
setPressed(-100 + key, pressed);
}
public boolean isMouseKeyPressed(String key){
return isMouseKeyPressed(Mouse.getButtonIndex(key));
}
public void setMouseKeyPressed(String key, boolean pressed){
setMouseKeyPressed(Mouse.getButtonIndex(key), pressed);
}
/*
* Gamepad
*/
public String getGamepadKeyIndex(String key){
for(int i = 0; i < maxGamepadId; i++){
if(gamepad.getButtonName(i).equals(key)) return gamepad.getButtonName(i);
}
return null;
}
public boolean isGamepadKeyPressed(int key){
if(key > maxGamepadId) maxGamepadId = key;
return isPressed(-200 + key);
}
public void setGamepadKeyPressed(int key, boolean pressed){
if(key > maxGamepadId) maxGamepadId = key;
setPressed(-200 + key, pressed);
}
public boolean isGamepadKeyPressed(String key){
return isMouseKeyPressed(getGamepadKeyIndex(key));
}
public void setGamepadKeyPressed(String key, boolean pressed){
setMouseKeyPressed(getGamepadKeyIndex(key), pressed);
}
}
public class KBOApi {
public static final KBOApi INSTANCE = new KBOApi("./KBO/");
public final File saveDir;
public final InputHandler INPUT;
public final KeyBindingsHandler KEYS;
public final ScriptHandler SCRIPTS;
public boolean updateKeysInGui = false;
public boolean runScriptsInGui = false;
public KBOApi(String saveDir) {
this.saveDir = new File(saveDir);
this.saveDir.mkdirs();
INPUT = new InputHandler(this);
KEYS = new KeyBindingsHandler(this);
SCRIPTS = new ScriptHandler(this);
}
public void preInit(FMLPreInitializationEvent event){
}
public void init(FMLInitializationEvent event){
FMLCommonHandler.instance().bus().register(new OnClientTickEvent());
}
public void postInit(FMLPostInitializationEvent event){
SCRIPTS.load();
SCRIPTS.init();
KEYS.load();
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
@Override
public void run() {
save();
}
}));
}
public class OnClientTickEvent {
private OnClientTickEvent() {
}
@SubscribeEvent
public void onTick(ClientTickEvent event){
if(event.phase == Phase.START){
tick();
}
}
}
private void tick(){
INPUT.tick();
if(runScriptsInGui || Minecraft.getMinecraft().currentScreen == null) SCRIPTS.tickPre();
if(updateKeysInGui || Minecraft.getMinecraft().currentScreen == null) KEYS.tickPre();
if(runScriptsInGui || Minecraft.getMinecraft().currentScreen == null) SCRIPTS.tickPost();
if(updateKeysInGui || Minecraft.getMinecraft().currentScreen == null) KEYS.tickPost();
}
public void load(){
KEYS.load();
SCRIPTS.load();
}
public void save(){
KEYS.save();
SCRIPTS.save();
}
}
@Mod(modid = KBOBase.MODID, name = KBOBase.NAME, version = KBOBase.VERSION, dependencies = "required-after:" + EXCore.DEPENDENCY, acceptedMinecraftVersions = "1.7.10")
public class KBOBase {
public static final String MODID = "KBO";
public static final String NAME = "Key Bindings Overhaul";
public static final String VERSION = "2.0";
@EventHandler
public void preInit(FMLPreInitializationEvent event){
KBOApi.INSTANCE.preInit(event);
}
@EventHandler
public void init(FMLInitializationEvent event){
KBOApi.INSTANCE.init(event);
}
@EventHandler
public void postInit(FMLPostInitializationEvent event){
for(KeyBinding key : Minecraft.getMinecraft().gameSettings.keyBindings){
KBOApi.INSTANCE.KEYS.addKey(new KeyBindingBasedAdvancedKeyBinding(KBOApi.INSTANCE.KEYS, key));
key.setKeyCode(0);
}
KeyBinding.resetKeyBindingArrayAndHash();
KBOApi.INSTANCE.postInit(event);
}
}
public class KeyBindingBasedAdvancedKeyBinding extends AdvancedKeyBinding {
public final KeyBinding keybinding;
public KeyBindingBasedAdvancedKeyBinding(KeyBindingsHandler handler, KeyBinding keybinding) {
super(handler, keybinding.getKeyDescription(), I18n.format(keybinding.getKeyDescription()), keybinding.getKeyCategory(), keybinding.getKeyCodeDefault());
this.keybinding = keybinding;
}
@Override
public void performAction() {
if(pressed && !(Boolean)ObfuscationReflectionHelper.getPrivateValue(KeyBinding.class, keybinding, "pressed", "field_74513_e")){
ObfuscationReflectionHelper.setPrivateValue(KeyBinding.class, keybinding, ((Integer)ObfuscationReflectionHelper.getPrivateValue(KeyBinding.class, keybinding, "pressTime", "field_151474_i")) + 1, "pressTime", "field_151474_i");
}
ObfuscationReflectionHelper.setPrivateValue(KeyBinding.class, keybinding, pressed, "pressed", "field_74513_e");
}
}
public class KeyBindingsHandler {
public final Logger logger = LogManager.getLogger("Key Bindings Handler");
public final Gson gson = new Gson();
public final KBOApi API;
public final File json;
private final List<IAdvancedKeyBinding> keys = new ArrayList<IAdvancedKeyBinding>();
public KeyBindingsHandler(KBOApi API) {
this.API = API;
json = new File(API.saveDir, "keys.json");
try{
json.createNewFile();
} catch(IOException e){
logger.error("Caught exception while creating keys.json: ", e);
}
}
public void tickPre(){
for(IAdvancedKeyBinding key : keys){
key.updateState();
}
}
public void tickPost(){
for(IAdvancedKeyBinding key : keys){
key.performAction();
}
}
public void resetAll(){
for(IAdvancedKeyBinding key : keys){
key.reset();
}
}
public void load(){
try {
SavedKeys keys = gson.fromJson(new JsonReader(new FileReader(json)), SavedKeys.class);
for(SavedKey key : keys.keys){
if(getKeyByName(key.name) != null){
getKeyByName(key.name).load(key.keys);
}
}
} catch (Exception e) {
logger.error("Caught exception while loading keys.json: ", e);
}
}
public void save(){
try {
JsonWriter writer = new JsonWriter(new FileWriter(json));
writer.setIndent(" ");
gson.toJson(new SavedKeys(Lists.transform(this.keys, new Function<IAdvancedKeyBinding, SavedKey>() {
@Override
public SavedKey apply(IAdvancedKeyBinding input) {
return new SavedKey(input.getName(), input.save());
}
})), SavedKeys.class, writer);
writer.close();
} catch (Exception e) {
logger.error("Caught exception while saving keys.json: ", e);
}
}
public boolean hasKey(IAdvancedKeyBinding key){
return keys.contains(key);
}
public void addKey(IAdvancedKeyBinding key){
keys.add(key);
}
public IAdvancedKeyBinding getKeyByName(String name){
for(IAdvancedKeyBinding key : keys){
if(key.getName().equals(name)){
return key;
}
}
return null;
}
public List<IAdvancedKeyBinding> getAllKeys(){
return keys;
}
public List<String> getAllCategories(){
List<String> list = new ArrayList<String>();
for(IAdvancedKeyBinding key : keys){
if(!list.contains(key.getCategoryName())){
list.add(key.getCategoryName());
}
}
return list;
}
public Multimap<String, IAdvancedKeyBinding> getCategoryKeysMultimap(){
Multimap<String, IAdvancedKeyBinding> map = HashMultimap.create();
for(IAdvancedKeyBinding key : keys){
map.put(key.getCategoryName(), key);
}
return map;
}
public static class SavedKeys {
private List<SavedKey> keys;
public SavedKeys(List<SavedKey> keys) {
this.keys = keys;
}
public List<SavedKey> getKeys() { return keys; }
public void setKeys(List<SavedKey> keys) { this.keys = keys; }
public static class SavedKey{
private String name;
private int[] keys;
public SavedKey(String name, int[] keys) {
this.name = name;
this.keys = keys;
}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int[] getKeys() { return keys; }
public void setKeys(int[] keys) { this.keys = keys; }
}
}
}
public class ScriptHandler {
public final Logger logger = LogManager.getLogger("Scripts Handler");
public final KBOApi api;
public File scriptsDir;
public Map<String, String> scripts = new HashMap<String, String>();
public ScriptEngineManager factory;
public ScriptEngine engine;
public ScriptHandler(KBOApi api) {
this.api = api;
}
public void load(){
scriptsDir = new File(api.saveDir, "scripts");
createDefaultScripts(scriptsDir);
scripts.clear();
loadScripts(scriptsDir);
}
protected void createDefaultScripts(File scriptsDir) {
boolean existed = scriptsDir.exists();
if(!existed){
scriptsDir.mkdir();
}
File initScript = new File(scriptsDir, "init.js");
if(!initScript.exists()){
try {
initScript.createNewFile();
FileUtils.writeLines(initScript, Lists.newArrayList(
"/*",
"This is a script that is executed once, whe minecraft finishes loading.",
"It is used to initialize any variables (in scripts) and in KBO itself.",
"You are provided with variable \"API\" (defined externally), which has 2 fields that you will want to set here: ",
" boolean API.updateKeysInGui: when set to true, keys will be updated even when gui is opened. False by default.",
" boolean API.runScriptsInGui: when set to true, scripts will be run even when gui is opened. False by default.",
"Also, here you can create your own key bindings that will be saved, because script is executed right before key bindings are loaded from save file.",
"Note: there are a tonn of methods and fields that you can access from this API field. For all of them, visit github.",
"*/",
"",
"API.updateKeysInGui = false;",
"API.runScriptsInGui = false;"));
} catch (IOException e) {
logger.info("Caught exception while writing default init script: ", e);
}
}
File tickPreScript = new File(scriptsDir, "tick pre.js");
if(!tickPreScript.exists()){
try {
tickPreScript.createNewFile();
FileUtils.writeLines(tickPreScript, Lists.newArrayList(
"/*",
"This is a script that is executed each tick, BEFORE key bindings states are updated.",
"Here you can emulate key states.",
"Emulated key states will be taken in account by key bindings to set their state upon combination of states of combined keys.",
"You can also check key states, before changing them.",
"You are provided with variable \"API\" (defined externally), where you can get 2 main objects that you will likely use:",
" INPUT: input handler. Using .isKeyboardKeyPressed(key) and .isMouseKeyPressed(key) you can get key state and using .setKeyboardKeyPressed(key, boolean pressed) and .setMouseKeyPressed(key) you can set key state. Key may be int (key id) and may be string (key name).",
" SCRIPTS: scripts handler. Use this to execute other scripts. To execute other script, call .executeScript(script), where script is name of script. If you want to provide executed script some variables, after script, alter variable name with it's value. Do NOT set any variable's name to API!",
"",
"Note: Each tick, before this script is executed, all key presses are reset to those from keyboard.",
"",
"Example:",
"This script below, will invert press of 'W' key:",
"API.INPUT.setKeyboardKeyPressed(\"W\", !API.INPUT.isKeyboardKeyPressed(\"W\"));",
"*/"));
} catch (IOException e) {
logger.info("Caught exception while writing default tick pre script: ", e);
}
}
File tickPostScript = new File(scriptsDir, "tick post.js");
if(!tickPostScript.exists()){
try {
tickPostScript.createNewFile();
FileUtils.writeLines(tickPostScript, Lists.newArrayList(
"/*",
"This is a script that is executed each tick, AFTER key bindings states are updated.",
"Here you can emulate key binding states.",
"You can also check key binding states, before changing them.",
"Emulated key binding states, will be taken in account by key binding to perform what they do or not to.",
"You are provided with variable \"API\" (defined externally), where you can get 2 main objects that you will likely use:",
" KEYS: key bindings handler. Use .getAllKeys() to get list of all keys, .hasKey(keyBinding) to check if it already has this key binding, .addKey(keyBinding) to add key binding and .getKeyByName(keyBindingName) to get key binding by it's name.",
" SCRIPTS: scripts handler. Use this to execute other scripts. To execute other script, call .executeScript(script), where script is name of script. If you want to provide executed script some variables, after script, alter variable name with it's value. Do NOT set any variable's name to API!",
"",
"Note: each tick, before script is executed, all key bindings presses are recomputed by key bindings.",
"",
"Example:",
"This script below, will invert press of \"key.attack\" (left click) key binding:",
"API.KEYS.getKeyByName(\"key.attack\").setPressed(!API.KEYS.getKeyByName(\"key.attack\").isPressed());",
"*/"));
} catch (IOException e) {
logger.info("Caught exception while writing default tick post script: ", e);
}
}
}
protected void loadScripts(File scriptsDir) {
for(File file : scriptsDir.listFiles(new FileFilter() {
@Override
public boolean accept(File file) {
return file.getName().endsWith(".js");
}
})){
try {
scripts.put(file.getName().replaceAll(".js", ""), FileUtils.readFileToString(file));
} catch (IOException e) {
logger.error(String.format("Caught exception while reading next java script file (%s): ", file.getName()), e);
}
}
logger.info("Loaded scripts: " + scripts.keySet());
}
public void save(){
}
public void init(){
factory = new ScriptEngineManager(null);
engine = factory.getEngineByName("JavaScript");
logger.info("Initialised script engine: " + engine);
engine.put("API", api);
try {
executeScript("init");
} catch (ScriptException e) {
logger.error("Caught exception while exectuting init script: ", e);
}
}
public void tickPre(){
try {
executeScript("tick pre");
} catch (ScriptException e) {
logger.error("Caught exception while exectuting tick pre script: ", e);
}
}
public void tickPost() {
try {
executeScript("tick post");
} catch (ScriptException e) {
logger.error("Caught exception while exectuting tick post script: ", e);
}
}
public void executeScript(String name) throws ScriptException {
engine.eval(scripts.get(name));
}
public void executeScript(String name, Object... vars) throws ScriptException {
for(int i = 0; i < vars.length; i += 2){
engine.put((String) vars[i], vars[i + 1]);
}
engine.eval(scripts.get(name));
for(int i = 0; i < vars.length; i += 2){
engine.getBindings(ScriptContext.ENGINE_SCOPE).remove(vars[i]);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment