Compare commits

...

17 Commits

Author SHA1 Message Date
Jkibbels
c8e379e564 [factions-banking] Huge amount of unrelated fixes with null checks + a new faction skill in the works (beacon effect). Fixed bad listener code in flight code!
Some checks failed
build / build (21) (push) Has been cancelled
2025-01-19 02:56:17 -05:00
Jkibbels
7efeb689cb [factions-banking] Fixed faction fly bugs
Some checks are pending
build / build (21) (push) Waiting to run
2025-01-18 23:41:09 -05:00
Jkibbels
74722b465a [factions-banking] IMPLEMENT FIRST COMMISSIONED ART INTO GAMEgit br
Some checks are pending
build / build (21) (push) Waiting to run
2025-01-18 15:01:08 -05:00
Jkibbels
6d14d47e0b [factions-banking] Flight tweaks to be MWAH before I go to bed
Some checks are pending
build / build (21) (push) Waiting to run
2025-01-18 04:38:34 -05:00
Jkibbels
d274810ca4 [factions-banking] Refinement on last commit with entry + exit stuff. IT WORKS!
Some checks are pending
build / build (21) (push) Waiting to run
2025-01-18 03:29:27 -05:00
Jkibbels
bcbd481fcf [factions-banking] Initial somewhat-functional system for the faction block radius detection
Some checks are pending
build / build (21) (push) Waiting to run
2025-01-18 03:10:58 -05:00
Jkibbels
f22da92cab [factions-banking] VERY start of SQL stuff for the banking system. Tables are figured out locally; implementing logic for JBDC driver here
Some checks failed
build / build (21) (push) Has been cancelled
2025-01-14 22:56:38 -05:00
Jkibbels
f6af706a60 [factions-banking] Retracting clearly bad custom command stuff in banking system to make it more user friendly. Ensured commands tested before worked new in the update
Some checks failed
build / build (21) (push) Has been cancelled
2025-01-09 21:44:17 -05:00
Jkibbels
cde06d56c0 [factions-banking] Necessary change to introduce MY SQL into the mod!
Some checks failed
build / build (21) (push) Has been cancelled
2025-01-02 23:05:16 -05:00
Jkibbels
ef49519368 [finish-factions-banking] Moved around logger information and chat system stuff FOR capabilities of mailing system and factions. This caused a sizable re-write but it is what it is
Some checks are pending
build / build (21) (push) Waiting to run
2025-01-01 22:47:50 -05:00
Jkibbels
82ee25ee97 [factions-and-banking] Commenting out yesterdays mixins since they're example only but maintaining in source code since they may be used. Added configuration file stuff to maintain UUID and name to be persistant when players log off. Updated more faction stuff as well! 2024-12-23 23:20:39 -05:00
Jkibbels
79a4738bbc [unrelated] Mixins for brother reference
Some checks are pending
build / build (21) (push) Waiting to run
2024-12-23 00:09:09 -05:00
Jkibbels
4c3e9c65aa [factions-and-banking] Extra detail
Some checks are pending
build / build (21) (push) Waiting to run
2024-12-22 22:30:42 -05:00
Jkibbels
20e0325493 [factions-and-banking] More work on the faction base block + mixin example of player drop
Some checks are pending
build / build (21) (push) Waiting to run
2024-12-22 22:28:39 -05:00
Jkibbels
a7f8504c2c [factions-banking] Updated build script to run both server and client at once properly with no options plugged in
Some checks failed
build / build (21) (push) Has been cancelled
2024-12-21 02:28:28 -05:00
Jkibbels
b6b73d96e8 [finish-factions-and-banking] A few QOL commands. Block entity with working model & textures and screen handler. UPDATED MOD TO 1.20.2 IN THIS
Some checks are pending
build / build (21) (push) Waiting to run
2024-12-21 02:07:14 -05:00
Jkibbels
c9473c59a1 [issue/finish-factions-and-banking] Added build script
Some checks failed
build / build (21) (push) Has been cancelled
2024-12-09 21:20:42 -05:00
83 changed files with 3633 additions and 1853 deletions

2
.gitignore vendored
View File

@ -5,6 +5,8 @@ build/
out/ out/
classes/ classes/
remappedSrc/
# eclipse # eclipse
*.launch *.launch

View File

@ -32,13 +32,13 @@ DOXYFILE_ENCODING = UTF-8
# title of most generated pages and in a few other places. # title of most generated pages and in a few other places.
# The default value is: My Project. # The default value is: My Project.
PROJECT_NAME = "My Project" PROJECT_NAME = "Keeblarcraft"
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This # The PROJECT_NUMBER tag can be used to enter a project or revision number. This
# could be handy for archiving the generated documentation or if some version # could be handy for archiving the generated documentation or if some version
# control system is used. # control system is used.
PROJECT_NUMBER = PROJECT_NUMBER = 1.0
# Using the PROJECT_BRIEF tag one can provide an optional one line description # Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a # for a project that appears at the top of each page and should give viewer a

View File

@ -1,5 +1,5 @@
plugins { plugins {
id 'fabric-loom' version '1.7-SNAPSHOT' id 'fabric-loom' version '1.9-SNAPSHOT'
id 'maven-publish' id 'maven-publish'
} }
@ -26,7 +26,7 @@ repositories {
// includeGroup("cc.tweaked") // includeGroup("cc.tweaked")
// } // }
// } // }
maven {url = "https://maven.kyrptonaught.dev"} maven { url = "https://maven.kyrptonaught.dev" }
maven { url = 'https://maven.minecraftforge.net/' } // for Terrablender maven { url = 'https://maven.minecraftforge.net/' } // for Terrablender
} }
@ -47,13 +47,16 @@ dependencies {
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
// modImplementation "mysql:mysql-connector-java:9.1.0"
include(implementation("mysql:mysql-connector-java:8.0.27"))
// Fabric API. This is technically optional, but you probably want it anyway. // Fabric API. This is technically optional, but you probably want it anyway.
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
//modCompileOnly "cc.tweaked:cc-tweaked-1.20-fabric-api:1.105.0" //modCompileOnly "cc.tweaked:cc-tweaked-1.20-fabric-api:1.105.0"
//modRuntimeOnly "cc.tweaked:cc-tweaked-1.20-fabric-api:1.105.0" //modRuntimeOnly "cc.tweaked:cc-tweaked-1.20-fabric-api:1.105.0"
modImplementation 'net.kyrptonaught:customportalapi:0.0.1-beta65-1.20' modImplementation 'net.kyrptonaught:customportalapi:0.0.1-beta64.5-1.20.2'
include 'net.kyrptonaught:customportalapi:0.0.1-beta65-1.20' include 'net.kyrptonaught:customportalapi:0.0.1-beta64.5-1.20.2'
modImplementation 'com.github.glitchfiend:TerraBlender-fabric:1.20.1-3.0.1.7' modImplementation 'com.github.glitchfiend:TerraBlender-fabric:1.20.2-3.2.0.14'
} }
processResources { processResources {
@ -72,10 +75,10 @@ java {
// Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task
// if it is present. // if it is present.
// If you remove this line, sources will not be generated. // If you remove this line, sources will not be generated.
withSourcesJar()
sourceCompatibility = JavaVersion.VERSION_17 sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17
withSourcesJar()
} }
jar { jar {

View File

@ -1,17 +1,17 @@
# Done to increase the memory available to gradle. # Done to increase the memory available to gradle.
org.gradle.jvmargs=-Xmx1G org.gradle.jvmargs=-Xmx2G
org.gradle.parallel=true org.gradle.parallel=true
# Fabric Properties # Fabric Properties
# check these on https://fabricmc.net/develop # check these on https://fabricmc.net/develop
minecraft_version=1.20 minecraft_version=1.20.2
yarn_mappings=1.20+build.1 yarn_mappings=1.20.2+build.4
loader_version=0.15.11 loader_version=0.16.9
# Mod Properties # Mod Properties
mod_version=0.0.1 mod_version=1.0.0
maven_group=jesse.keeblarcraft maven_group=jesse.keeblarcraft
archives_base_name=keeblarcraft archives_base_name=keeblarcraft
# Dependencies # Dependencies
fabric_version=0.83.0+1.20 fabric_version=0.91.6+1.20.2

Binary file not shown.

View File

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

5
gradlew vendored
View File

@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# #
# SPDX-License-Identifier: Apache-2.0
#
############################################################################## ##############################################################################
# #
@ -84,7 +86,8 @@ done
# shellcheck disable=SC2034 # shellcheck disable=SC2034
APP_BASE_NAME=${0##*/} APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum MAX_FD=maximum

2
gradlew.bat vendored
View File

@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and @rem See the License for the specific language governing permissions and
@rem limitations under the License. @rem limitations under the License.
@rem @rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off @if "%DEBUG%"=="" @echo off
@rem ########################################################################## @rem ##########################################################################

Binary file not shown.

188
run.sh Executable file
View File

@ -0,0 +1,188 @@
#!/bin/bash
BASH_PATH=$(which bash)
#########
# GLOBALS
#########
REPO_TOP=$(dirname $(readlink -f "${BASH_SOURCE[0]}"))
SCRIPT_NAME=$(basename $0)
SERVER_MODE=0 # 1=true, 0=false
CLIENT_MODE=0 # 1=true, 0=false
LOG_LEVEL=1
BUILD_PATH="build"
RUN_PATH="run"
RESET_ALL=0
RUN_ALL=1
GRADLEW_PATH=${REPO_TOP}/gradlew
declare SERVER_PID
declare CLIENT_PID
# $1 is text level
# LEVELS:
# 1: Info
# 2: Debug
# 3: Warning
function TermWrite() {
textLevel=$1
text="${2}"
prefix="[\033[34m"${SCRIPT_NAME}"\033[0m]: "
if [[ "${textLevel}" == "2" ]]; then
prefix="[\033[33m"${SCRIPT_NAME}"\033[0m]:"
fi
if [[ "${textLevel}" == "3" ]]; then
prefix="[\033[31m"${SCRIPT_NAME}"\033[0m]:"
fi
if [[ ${LOG_LEVEL} -ge ${textLevel} ]]; then
printf "${prefix} ${text}\n"
fi
}
function help() {
echo -e "Help for running $0:"
echo -e " -s: Build and run the program in server mode"
echo -e " -c: Build and run the program in client mode"
echo -e " -l [1-3]: Turn up the logging level to see more messages (default: 1)"
echo -e " -g <path>: The path to the gradlew executable (default: $(pwd)/gradlew)"
echo -e " -r: Reset everything. This will nuke the previous install area and re-build EVERYTHING from scratch"
echo -e " -b <path>: Specify the build area (default is cur dir $(pwd)/build)"
echo -e " -b2 <path>: Specify the run area (default is cur dir $(pwd)/run)"
echo -e " -a: Run everything at once (default option if nothing specified)"
echo -e " -h: Bring up this help message"
}
function ExitAll() {
TermWrite 1 "Cleaning up..."
if [ ! -z $SERVER_PID ]; then
TermWrite 1 "Killing PID $SERVER_PID"
kill -9 $SERVER_PID
fi
if [ ! -z $CLIENT_PID ]; then
TermWrite 1 "Killing PID $CLIENT_PID"
kill -9 $CLIENT_PID
fi
# Close with exit code 1 because a clean close isn't guarenteed with this
exit 1
}
# Capture CTRL+C event into ExitAll function
trap ExitAll INT
while getopts ":schl:g:r:b:b2:" opt; do
case ${opt} in
s)
TermWrite 2 "SERVER MODE ENABLED"
SERVER_MODE=1
RUN_ALL=0
;;
c)
TermWrite 2 "CLIENT MODE ENABLED"
CLIENT_MODE=1
RUN_ALL=0
;;
h)
help
exit 0
;;
l)
if [[ $OPTARG =~ [1-3] ]]; then
LOG_LEVEL=$OPTARG
TermWrite 2 "LOG LEVEL SET TO $LOG_LEVEL"
fi
;;
g)
if [[ -f "${OPTARG}" ]]; then
TermWrite 2 "Set gradlew path to $OPTARG"
GRADLEW_PATH="$OPTARG"
else
TermWrite 3 "The path you gave to the gradlew executable (${OPTARG}) does not appear to exist. Please check the path!"
fi
;;
r)
RESET_ALL=1
;;
b)
if [[ -f "${OPTARG}" ]]; then
TermWrite 2 "Setting build directory to: ${OPTARG}"
BUILD_PATH="${OPTARG}"
else
TermWrite 3 "The specified path (${OPTARG}) does not appear to exist. Please check the path!"
exit 1
fi
;;
b1)
if [[ "${OPTARG}" ]]; then
TermWrite 2 "Setting run directory to: ${OPTARG}"
RUN_PATH="${OPTARG}"
else
TermWrite 3 "The specified path (${OPTARG}) does not appear to exist. Please check the path!"
exit 1
fi
;;
?)
help
exit 0
;;
esac
done
TermWrite 2 "CURRENT DIRECTORY: $(pwd)"
TermWrite 2 "SERVER MODE? ${SERVER_MODE}"
TermWrite 2 "CLIENT MODE? ${CLIENT_MODE}"
# If the user specified they wish to wipe everything before we begin; then let us do so.
if [[ $RESET_ALL -eq 1 ]]; then
TermWrite 1 "Removing $BUILD_PATH"
rm -rf $BUILD_PATH
TermWrite 1 "Removing $RUN_PATH"
rm -rf $RUN_PATH
TermWrite 1 "Running build..."
$BASH_PATH $GRADLEW_PATH build
TermWrite 1 "Running datagen..."
$BASH_PATH $GRADLEW_PATH runDatagen
TermWrite 1 "All completed!"
fi
if [[ $RUN_ALL -eq 0 ]]; then
if [[ $SERVER_MODE -eq 1 ]]; then
TermWrite 1 "Running ./gradlew build"
$BASH_PATH $GRADLEW_PATH build
TermWrite 1 "Running ./gradlew runServer"
$BASH_PATH $GRADLEW_PATH runServer &
SERVER_PID=$!
fi
if [[ $CLIENT_MODE -eq 1 ]]; then
TermWrite 1 "Running ./gradlew build"
$BASH_PATH $GRADLEW_PATH build
TermWrite 1 "Running ./gradlew runClient"
$BASH_PATH $GRADLEW_PATH runClient
CLIENT_PID=$!
fi
else
# Run everything
TermWrite 1 "Running both client and server processes..."
$BASH_PATH $GRADLEW_PATH clean
$BASH_PATH $GRADLEW_PATH build
$BASH_PATH $GRADLEW_PATH runClient &
CLIENT_PID=$!
# We do not run the server in the background so the player may run commands in the server terminal
$BASH_PATH $GRADLEW_PATH runServer
SERVER_PID=$!
TermWrite 1 "Server and client processes started"
fi
TermWrite 1 "Finished running gradlew command with exit code $?"
# We wait and hang here until BOTH background processes finish (or until CTRL+C event)
wait
# Clean up and leave
ExitAll

View File

@ -1,8 +1,8 @@
package jesse.keeblarcraft; package jesse.keeblarcraft;
import jesse.keeblarcraft.gui.ClientHandlers; import jesse.keeblarcraft.gui.ClientHandlers;
import jesse.keeblarcraft.gui.ScreenManager; // import jesse.keeblarcraft.gui.ScreenManager;
import jesse.keeblarcraft.gui.widgets.TreeWidget; // import jesse.keeblarcraft.gui.widgets.TreeWidget;
import jesse.keeblarcraft.Shortcuts.ShortcutManager; import jesse.keeblarcraft.Shortcuts.ShortcutManager;
import net.fabricmc.api.ClientModInitializer; import net.fabricmc.api.ClientModInitializer;
@ -14,8 +14,8 @@ public class KeeblarcraftClient implements ClientModInitializer {
ShortcutManager.RegisterKeybinds(); ShortcutManager.RegisterKeybinds();
ClientHandlers.RegisterHandlers(); ClientHandlers.RegisterHandlers();
ScreenManager.GetInstance(); // ScreenManager.GetInstance();
ScreenManager.AddWidget(TreeWidget.class, 10); // ScreenManager.AddWidget(TreeWidget.class, 10);
} }
} }

View File

@ -12,7 +12,7 @@ package jesse.keeblarcraft.Shortcuts;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
// import jesse.keeblarcraft.Keeblarcraft; // import jesse.keeblarcraft.Keeblarcraft;
import jesse.keeblarcraft.gui.ScreenManager; // import jesse.keeblarcraft.gui.ScreenManager;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
@ -83,10 +83,10 @@ public class ShortcutManager {
// treeGui = new ScreenManager(Keeblarcraft.TREE_HANDLER.create(0, client.player.getInventory()), client.player.getInventory(), Text.of("Test")); // treeGui = new ScreenManager(Keeblarcraft.TREE_HANDLER.create(0, client.player.getInventory()), client.player.getInventory(), Text.of("Test"));
// treeGui.AddParent(currentScreen); ///TODO: Put this in the constructor when you figure out how the hell the magic is happening with registration // treeGui.AddParent(currentScreen); ///TODO: Put this in the constructor when you figure out how the hell the magic is happening with registration
ScreenManager treeGui = ScreenManager.GetInstance(); // ScreenManager treeGui = ScreenManager.GetInstance();
treeGui.AddParent(currentScreen); // treeGui.AddParent(currentScreen);
MinecraftClient.getInstance().setScreen(treeGui); // MinecraftClient.getInstance().setScreen(treeGui);
// toggleTreeGui intentionally never bit-flipped to false as a slight implementation bug exists such that pressing the keybind again // toggleTreeGui intentionally never bit-flipped to false as a slight implementation bug exists such that pressing the keybind again
// does NOT call this callback function until the previous screen is CLOSED (which is why this isn't resource leaking...). This will // does NOT call this callback function until the previous screen is CLOSED (which is why this isn't resource leaking...). This will

View File

@ -1,11 +1,13 @@
package jesse.keeblarcraft.gui; package jesse.keeblarcraft.gui;
import jesse.keeblarcraft.Keeblarcraft; import jesse.keeblarcraft.Keeblarcraft;
import jesse.keeblarcraft.GuiMgr.ScreenHandlerRegistration;
import net.minecraft.client.gui.screen.ingame.HandledScreens; import net.minecraft.client.gui.screen.ingame.HandledScreens;
public class ClientHandlers { public class ClientHandlers {
public static void RegisterHandlers() { public static void RegisterHandlers() {
System.out.println("Registering tree handler screen"); System.out.println("Registering tree handler screen");
HandledScreens.register(Keeblarcraft.TREE_HANDLER, ScreenManager::new); // HandledScreens.register(Keeblarcraft.TREE_HANDLER, ScreenManager::new);
HandledScreens.register(ScreenHandlerRegistration.FACTION_BLOCK_SCREEN_HANDLER, FactionBlockScreen::new);
} }
} }

View File

@ -0,0 +1,51 @@
package jesse.keeblarcraft.gui;
import com.mojang.blaze3d.systems.RenderSystem;
import jesse.keeblarcraft.Keeblarcraft;
import jesse.keeblarcraft.GuiMgr.FactionBlockScreenHandler;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.client.render.GameRenderer;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
public class FactionBlockScreen extends HandledScreen<FactionBlockScreenHandler> {
// This is a placeholder image until an actual one is drawn
private static final Identifier TEXTURE = new Identifier(Keeblarcraft.MOD_ID, "textures/gui/faction_block_menu.png");
public FactionBlockScreen(FactionBlockScreenHandler handler, PlayerInventory inventory, Text title) {
super(handler, inventory, title);
}
@Override
protected void init() {
super.init();
titleY = 1000; //begone from screen
playerInventoryTitleY = 1000; //begone from screen
}
@Override
protected void drawBackground(DrawContext context, float delta, int mouseX, int mouseY) {
RenderSystem.setShader(GameRenderer::getPositionTexProgram);
RenderSystem.setShaderColor(1f, 1f, 1f, 1f);
RenderSystem.setShaderTexture(0, TEXTURE);
this.backgroundHeight = 256;
this.backgroundWidth = 256;
int x = (width - backgroundWidth) / 2;
int y = (height - backgroundHeight) / 2;
context.drawTexture(TEXTURE, x, y, 0, 0, backgroundWidth, backgroundHeight);
}
@Override
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
renderBackground(context, mouseX, mouseY, delta);
super.render(context, mouseX, mouseY, delta);
drawMouseoverTooltip(context, mouseX, mouseY);
}
}

View File

@ -1,381 +1,381 @@
/* // /*
* // *
* ScreenManager // * ScreenManager
* // *
* This is the screen manager for the global screen handler of `TreeHandler` type // * This is the screen manager for the global screen handler of `TreeHandler` type
* Please note: `TreeHandler` is suited for a more broad range of things; however // * Please note: `TreeHandler` is suited for a more broad range of things; however
* its initial implementation is for the skill tree. It will be renamed to a more // * its initial implementation is for the skill tree. It will be renamed to a more
* generic name so this class is more obviously re-usable after its implementation // * generic name so this class is more obviously re-usable after its implementation
* is complete AND we verify this class can be made more generic for it. Since this // * is complete AND we verify this class can be made more generic for it. Since this
* is unknown, it will remain the name it has currently. // * is unknown, it will remain the name it has currently.
* // *
* // *
*/ // */
package jesse.keeblarcraft.gui; // package jesse.keeblarcraft.gui;
import java.lang.reflect.InvocationTargetException; // import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList; // import java.util.ArrayList;
import java.util.HashMap; // import java.util.HashMap;
import java.util.List; // import java.util.List;
import java.util.Map.Entry; // import java.util.Map.Entry;
import jesse.keeblarcraft.Keeblarcraft; // import jesse.keeblarcraft.Keeblarcraft;
import jesse.keeblarcraft.GuiMgr.TreeHandler; // import jesse.keeblarcraft.GuiMgr.TreeHandler;
import net.minecraft.client.MinecraftClient; // import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.DrawContext; // import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.Screen; // import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.ingame.HandledScreen; // import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.entity.player.PlayerInventory; // import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.text.Text; // import net.minecraft.text.Text;
// Client side renderer // // Client side renderer
public class ScreenManager extends HandledScreen<TreeHandler> { // public class ScreenManager extends HandledScreen<TreeHandler> {
private static ScreenManager static_inst; // private static ScreenManager static_inst;
@SuppressWarnings("resource") // @SuppressWarnings("resource")
private static PlayerInventory static_inventory = new PlayerInventory(null);// = MinecraftClient.getInstance().player.getInventory(); // private static PlayerInventory static_inventory = new PlayerInventory(null);// = MinecraftClient.getInstance().player.getInventory();
public static ScreenManager GetInstance() { // public static ScreenManager GetInstance() {
if (static_inst == null) { // if (static_inst == null) {
static_inst = new ScreenManager(Keeblarcraft.TREE_HANDLER.create(0, static_inventory), static_inventory, Text.of("Test")); // static_inst = new ScreenManager(Keeblarcraft.TREE_HANDLER.create(0, static_inventory), static_inventory, Text.of("Test"));
} // }
return static_inst; // return static_inst;
} // }
private static HashMap<Integer, ArrayList<Class<? extends GenericLayerT>>> layerMap = new HashMap<Integer, ArrayList<Class<? extends GenericLayerT>>>(); // private static HashMap<Integer, ArrayList<Class<? extends GenericLayerT>>> layerMap = new HashMap<Integer, ArrayList<Class<? extends GenericLayerT>>>();
private static HashMap<Integer, ArrayList<GenericLayerT>> layers = new HashMap<Integer, ArrayList<GenericLayerT>>(); // key: layer id; value: list of classes to draw // private static HashMap<Integer, ArrayList<GenericLayerT>> layers = new HashMap<Integer, ArrayList<GenericLayerT>>(); // key: layer id; value: list of classes to draw
// private TreeWidget treeWidget = null; // // private TreeWidget treeWidget = null;
private Screen parent; // private Screen parent;
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
/// @fn ScreenManager // /// @fn ScreenManager
/// // ///
/// @arg[in] handler is the TreeHandler (ScreenHandler) object // /// @arg[in] handler is the TreeHandler (ScreenHandler) object
/// // ///
/// @arg[in] inventory is the players inventory. Required by HandledScreen // /// @arg[in] inventory is the players inventory. Required by HandledScreen
/// object however is unused currently in this Screen // /// object however is unused currently in this Screen
/// // ///
/// @arg[in] title is the title of the screen window // /// @arg[in] title is the title of the screen window
/// // ///
/// @brief Class constructor // /// @brief Class constructor
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
public ScreenManager(TreeHandler handler, PlayerInventory inventory, Text title) { // public ScreenManager(TreeHandler handler, PlayerInventory inventory, Text title) {
super(handler, inventory, title); // super(handler, inventory, title);
System.out.println("Called constructor of screen manager!"); // System.out.println("Called constructor of screen manager!");
// Initialize layers in map // // Initialize layers in map
// for (int i = 0; i < NUMBER_DRAW_LAYERS; i++) { // // for (int i = 0; i < NUMBER_DRAW_LAYERS; i++) {
// layers.put(i, new ArrayList<Class<? extends GenericLayerT>>()); // // layers.put(i, new ArrayList<Class<? extends GenericLayerT>>());
// } // // }
} // }
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
/// @fn AddParent // /// @fn AddParent
/// // ///
/// @arg[in] parent is the parent screen object // /// @arg[in] parent is the parent screen object
/// // ///
/// @brief Add a parent screen to the screen object. This is useful if // /// @brief Add a parent screen to the screen object. This is useful if
/// you want to return to the previous screen when this one gets // /// you want to return to the previous screen when this one gets
/// closed by the user // /// closed by the user
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
public void AddParent(Screen parent) { // public void AddParent(Screen parent) {
this.parent = parent; // this.parent = parent;
} // }
public static void AddWidget(Class<? extends GenericLayerT> widget, int drawLayer) { // public static void AddWidget(Class<? extends GenericLayerT> widget, int drawLayer) {
if (layerMap.containsKey(drawLayer)) { // if (layerMap.containsKey(drawLayer)) {
// Just append the widget to the draw layer // // Just append the widget to the draw layer
var layerList = layerMap.get(drawLayer); // var layerList = layerMap.get(drawLayer);
layerList.add(widget); // layerList.add(widget);
} else { // } else {
// Brand new layer! // // Brand new layer!
layerMap.put(drawLayer, new ArrayList<>(List.of(widget))); // layerMap.put(drawLayer, new ArrayList<>(List.of(widget)));
} // }
} // }
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
/// @fn init // /// @fn init
/// // ///
/// @brief Initialize method; called one-time to setup class variables // /// @brief Initialize method; called one-time to setup class variables
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
@Override // @Override
public void init() { // public void init() {
// initialize screen size to the global background picture // // initialize screen size to the global background picture
this.width = MinecraftClient.getInstance().getWindow().getScaledWidth(); // this.width = MinecraftClient.getInstance().getWindow().getScaledWidth();
this.height = MinecraftClient.getInstance().getWindow().getScaledHeight(); // this.height = MinecraftClient.getInstance().getWindow().getScaledHeight();
// Let's go through and initialize all the screen types now in our active memory // // Let's go through and initialize all the screen types now in our active memory
for (Entry<Integer, ArrayList<Class<? extends GenericLayerT>>> layerEntry : layerMap.entrySet()) { // for (Entry<Integer, ArrayList<Class<? extends GenericLayerT>>> layerEntry : layerMap.entrySet()) {
var layerList = layerEntry.getValue(); // var layerList = layerEntry.getValue();
layers.put(layerEntry.getKey(), new ArrayList<>()); // layers.put(layerEntry.getKey(), new ArrayList<>());
var activeLayerList = layers.get(layerEntry.getKey()); // var activeLayerList = layers.get(layerEntry.getKey());
for (int i = 0; i < layerList.size(); i++) { // for (int i = 0; i < layerList.size(); i++) {
try { // try {
System.out.println("Attempting to initialize widget with information: LAYER I-VAL W H: " + layerEntry.getKey() + " " + i + " " + this.width + " " + this.height); // System.out.println("Attempting to initialize widget with information: LAYER I-VAL W H: " + layerEntry.getKey() + " " + i + " " + this.width + " " + this.height);
GenericLayerT initializedWidget = layerList.get(i).getDeclaredConstructor(int.class, int.class, int.class, int.class, Text.class).newInstance(0, 0, this.width, this.height, Text.of("")); // GenericLayerT initializedWidget = layerList.get(i).getDeclaredConstructor(int.class, int.class, int.class, int.class, Text.class).newInstance(0, 0, this.width, this.height, Text.of(""));
activeLayerList.add(initializedWidget); // activeLayerList.add(initializedWidget);
} catch (InstantiationException e) { // } catch (InstantiationException e) {
System.out.println("Could not initialize GenericLayerT class (" + layerList.get(i).getClass().toString() + ") because of IntantiationException"); // System.out.println("Could not initialize GenericLayerT class (" + layerList.get(i).getClass().toString() + ") because of IntantiationException");
e.printStackTrace(); // e.printStackTrace();
} catch (IllegalAccessException e) { // } catch (IllegalAccessException e) {
System.out.println("Could not initialize GenericLayerT class (" + layerList.get(i).getClass().toString() + ") because of IllegalAccessException"); // System.out.println("Could not initialize GenericLayerT class (" + layerList.get(i).getClass().toString() + ") because of IllegalAccessException");
e.printStackTrace(); // e.printStackTrace();
} catch (IllegalArgumentException e) { // } catch (IllegalArgumentException e) {
System.out.println("Could not initialize GenericLayerT class (" + layerList.get(i).getClass().toString() + ") because of IllegalArgumentException"); // System.out.println("Could not initialize GenericLayerT class (" + layerList.get(i).getClass().toString() + ") because of IllegalArgumentException");
e.printStackTrace(); // e.printStackTrace();
} catch (InvocationTargetException e) { // } catch (InvocationTargetException e) {
System.out.println("Could not initialize GenericLayerT class (" + layerList.get(i).getClass().toString() + ") because of InvocationTargetException"); // System.out.println("Could not initialize GenericLayerT class (" + layerList.get(i).getClass().toString() + ") because of InvocationTargetException");
e.printStackTrace(); // e.printStackTrace();
} catch (NoSuchMethodException e) { // } catch (NoSuchMethodException e) {
System.out.println("Could not initialize GenericLayerT class (" + layerList.get(i).getClass().toString() + ") because of NoSuchMethodException"); // System.out.println("Could not initialize GenericLayerT class (" + layerList.get(i).getClass().toString() + ") because of NoSuchMethodException");
e.printStackTrace(); // e.printStackTrace();
} catch (SecurityException e) { // } catch (SecurityException e) {
System.out.println("Could not initialize GenericLayerT class (" + layerList.get(i).getClass().toString() + ") because of SecurityException"); // System.out.println("Could not initialize GenericLayerT class (" + layerList.get(i).getClass().toString() + ") because of SecurityException");
e.printStackTrace(); // e.printStackTrace();
} // }
} // }
} // }
// Initialize child widgets with correct screen values so they can draw themselves in the right area on the screen (duh!) // // Initialize child widgets with correct screen values so they can draw themselves in the right area on the screen (duh!)
// treeWidget = new TreeWidget(GLOBAL_SCREEN_START_X + 24, GLOBAL_SCREEN_START_Y + 24, GLOBAL_SCREEN_WIDTH - 24, GLOBAL_SCREEN_HEIGHT - 24); // // treeWidget = new TreeWidget(GLOBAL_SCREEN_START_X + 24, GLOBAL_SCREEN_START_Y + 24, GLOBAL_SCREEN_WIDTH - 24, GLOBAL_SCREEN_HEIGHT - 24);
// this.addDrawableChild(treeWidget); // // this.addDrawableChild(treeWidget);
} // }
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
/// @fn render // /// @fn render
/// // ///
/// @arg[in] context is the drawing context of super class // /// @arg[in] context is the drawing context of super class
/// // ///
/// @arg[in] mouseX is passed to parent class but unused here // /// @arg[in] mouseX is passed to parent class but unused here
/// // ///
/// @arg[in] mouseY is passed to parent class but unused here // /// @arg[in] mouseY is passed to parent class but unused here
/// // ///
/// @brief Render is called every frame while the screen is open // /// @brief Render is called every frame while the screen is open
/// // ///
/// @note This is a pure abstract in parent and is required // /// @note This is a pure abstract in parent and is required
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
@Override // @Override
public void render(DrawContext context, int mouseX, int mouseY, float delta) { // public void render(DrawContext context, int mouseX, int mouseY, float delta) {
super.render(context, mouseX, mouseY, delta); // This takes care of calling drawBackground which calls DrawMainScreen // super.render(context, mouseX, mouseY, delta); // This takes care of calling drawBackground which calls DrawMainScreen
} // }
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
/// @fn drawForeground // /// @fn drawForeground
/// // ///
/// @arg[in] context is the drawing context of super class // /// @arg[in] context is the drawing context of super class
/// // ///
/// @arg[in] mouseX is unused // /// @arg[in] mouseX is unused
/// // ///
/// @arg[in] mouseY is unused // /// @arg[in] mouseY is unused
/// // ///
/// @brief Draw foreground exists to draw the titles; however we // /// @brief Draw foreground exists to draw the titles; however we
/// intentionally override it so the superclass object does not // /// intentionally override it so the superclass object does not
/// draw the overlay over the background screen // /// draw the overlay over the background screen
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
@Override // @Override
public void drawForeground(DrawContext context, int mouseX, int mouseY) { // public void drawForeground(DrawContext context, int mouseX, int mouseY) {
// We override this function to intentionally do nothing // // We override this function to intentionally do nothing
// If in the future we want, we would draw the foreground and TITLES with this! // // If in the future we want, we would draw the foreground and TITLES with this!
} // }
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
/// @fn close // /// @fn close
/// // ///
/// @brief Called when the screen closes // /// @brief Called when the screen closes
/// // ///
/// @note This is a pure abstract in parent and is required // /// @note This is a pure abstract in parent and is required
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
@Override // @Override
public void close() { // public void close() {
this.client.setScreen(parent); // return to previous screen or null // this.client.setScreen(parent); // return to previous screen or null
} // }
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
/// @fn mouseDragged // /// @fn mouseDragged
/// // ///
/// @arg[in] mouseX is x-axis position of original mouse click // /// @arg[in] mouseX is x-axis position of original mouse click
/// // ///
/// @arg[in] mouseY is y-axis position of original mouse click // /// @arg[in] mouseY is y-axis position of original mouse click
/// // ///
/// @arg[in] button is the int value of button pressed for mouse dragging // /// @arg[in] button is the int value of button pressed for mouse dragging
/// // ///
/// @arg[in] deltaX is the change in the X position from the previous // /// @arg[in] deltaX is the change in the X position from the previous
/// mouse click // /// mouse click
/// // ///
/// @arg[in] deltaY is the change in the Y position from the previous // /// @arg[in] deltaY is the change in the Y position from the previous
/// mouse click // /// mouse click
/// // ///
/// @brief The drag event is called on all widgets on the screen so // /// @brief The drag event is called on all widgets on the screen so
/// long as the initial position of the drag is within the // /// long as the initial position of the drag is within the
/// bounds of the widget box itself. Widgets themselves will need // /// bounds of the widget box itself. Widgets themselves will need
/// to handle any sub-widgets since the bound check is only // /// to handle any sub-widgets since the bound check is only
/// there to verify if the event happened ANYWHERE within a // /// there to verify if the event happened ANYWHERE within a
/// widget box // /// widget box
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
@Override // @Override
public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { // public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) {
super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY); // super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY);
// UpdateAnchorValues(); // // UpdateAnchorValues();
for (Entry<Integer, ArrayList<GenericLayerT>> layerEntry : layers.entrySet()) { // for (Entry<Integer, ArrayList<GenericLayerT>> layerEntry : layers.entrySet()) {
var layerList = layerEntry.getValue(); // var layerList = layerEntry.getValue();
for (var layerListIterator = 0; layerListIterator < layerList.size(); layerListIterator++) { // for (var layerListIterator = 0; layerListIterator < layerList.size(); layerListIterator++) {
var layer = layerList.get(layerListIterator); // var layer = layerList.get(layerListIterator);
// Check to make sure scroll is within the context of the widget then deliver information // // Check to make sure scroll is within the context of the widget then deliver information
if (InBounds(layer.startX, layer.startY, layer.endX, layer.endY, (int) mouseX, (int) mouseY)) { // if (InBounds(layer.startX, layer.startY, layer.endX, layer.endY, (int) mouseX, (int) mouseY)) {
layer.mouseDragged(mouseX, mouseY, button, deltaX, deltaY); // layer.mouseDragged(mouseX, mouseY, button, deltaX, deltaY);
} // }
} // }
} // }
return true; // return true;
} // }
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
/// @fn mouseScrolled // /// @fn mouseScrolled
/// // ///
/// @arg[in] mouseX is the initial X position of the cursor on a scroll // /// @arg[in] mouseX is the initial X position of the cursor on a scroll
/// // ///
/// @arg[in] mouseY is the initial Y position of the cursor on a scroll // /// @arg[in] mouseY is the initial Y position of the cursor on a scroll
/// // ///
/// @arg[in] amount is a normalized value that indicates scroll direction // /// @arg[in] amount is a normalized value that indicates scroll direction
/// // ///
/// @brief The scroll event is called on all widgets on the screen so // /// @brief The scroll event is called on all widgets on the screen so
/// long as the initial position of the scroll is within the // /// long as the initial position of the scroll is within the
/// bounds of the widget box itself. Widgets themselves will need // /// bounds of the widget box itself. Widgets themselves will need
/// to handle any sub-widgets since the bound check is only // /// to handle any sub-widgets since the bound check is only
/// there to verify if the event happened ANYWHERE within a // /// there to verify if the event happened ANYWHERE within a
/// widget box // /// widget box
/// // ///
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
@Override // @Override
public boolean mouseScrolled(double mouseX, double mouseY, double amount) { // public boolean mouseScrolled(double mouseX, double mouseY, double amount) {
super.mouseScrolled(mouseX, mouseY, amount); // super.mouseScrolled(mouseX, mouseY, amount);
for (Entry<Integer, ArrayList<GenericLayerT>> layerEntry : layers.entrySet()) { // for (Entry<Integer, ArrayList<GenericLayerT>> layerEntry : layers.entrySet()) {
var layerList = layerEntry.getValue(); // var layerList = layerEntry.getValue();
for (var layerListIterator = 0; layerListIterator < layerList.size(); layerListIterator++) { // for (var layerListIterator = 0; layerListIterator < layerList.size(); layerListIterator++) {
var layer = layerList.get(layerListIterator); // var layer = layerList.get(layerListIterator);
// Check to make sure scroll is within the context of the widget then deliver information // // Check to make sure scroll is within the context of the widget then deliver information
if (InBounds(layer.startX, layer.startY, layer.endX, layer.endY, (int) mouseX, (int) mouseY)) { // if (InBounds(layer.startX, layer.startY, layer.endX, layer.endY, (int) mouseX, (int) mouseY)) {
layer.mouseScrolled(mouseX, mouseY, amount); // layer.mouseScrolled(mouseX, mouseY, amount);
} // }
} // }
} // }
return true; // The parent function defines this to be boolean; but I have no idea when I would want to return false from this // return true; // The parent function defines this to be boolean; but I have no idea when I would want to return false from this
} // }
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
/// @fn mouseClicked // /// @fn mouseClicked
/// // ///
/// @arg[in] mouseX is the initial X position of the mouse click event // /// @arg[in] mouseX is the initial X position of the mouse click event
/// // ///
/// @arg[in] mouseY is the initial Y position of the mouse click event // /// @arg[in] mouseY is the initial Y position of the mouse click event
/// // ///
/// @arg[in] button is the mouse click button (left/right click value) // /// @arg[in] button is the mouse click button (left/right click value)
/// // ///
/// @brief The mouse click is called on all widgets on the screen so // /// @brief The mouse click is called on all widgets on the screen so
/// long as the initial position of the click is within the // /// long as the initial position of the click is within the
/// bounds of the widget box itself. Widgets themselves will need // /// bounds of the widget box itself. Widgets themselves will need
/// to handle any sub-widgets since the bound check is only // /// to handle any sub-widgets since the bound check is only
/// there to verify if the event happened ANYWHERE within a // /// there to verify if the event happened ANYWHERE within a
/// widget box // /// widget box
/// // ///
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
@Override // @Override
public boolean mouseClicked(double mouseX, double mouseY, int button) { // public boolean mouseClicked(double mouseX, double mouseY, int button) {
super.mouseClicked(mouseX, mouseY, button); // super.mouseClicked(mouseX, mouseY, button);
for (Entry<Integer, ArrayList<GenericLayerT>> layerEntry : layers.entrySet()) { // for (Entry<Integer, ArrayList<GenericLayerT>> layerEntry : layers.entrySet()) {
var layerList = layerEntry.getValue(); // var layerList = layerEntry.getValue();
for (var layerListIterator = 0; layerListIterator < layerList.size(); layerListIterator++) { // for (var layerListIterator = 0; layerListIterator < layerList.size(); layerListIterator++) {
var layer = layerList.get(layerListIterator); // var layer = layerList.get(layerListIterator);
// Check to make sure scroll is within the context of the widget then deliver information // // Check to make sure scroll is within the context of the widget then deliver information
if (InBounds(layer.startX, layer.startY, layer.endX, layer.endY, (int) mouseX, (int) mouseY)) { // if (InBounds(layer.startX, layer.startY, layer.endX, layer.endY, (int) mouseX, (int) mouseY)) {
layer.mouseClicked(mouseX, mouseY, button); // layer.mouseClicked(mouseX, mouseY, button);
} // }
} // }
} // }
return true; // return true;
} // }
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
/// @fn DrawLayers // /// @fn DrawLayers
/// // ///
/// @arg[in] context is the global drawing context for the screen // /// @arg[in] context is the global drawing context for the screen
/// // ///
/// @arg[in] delta is passed in from background draw // /// @arg[in] delta is passed in from background draw
/// // ///
/// @brief This is the primary drawing function so that all the texture // /// @brief This is the primary drawing function so that all the texture
/// draws can be done in one place in this class. We want as // /// draws can be done in one place in this class. We want as
/// little distance as possible between redraws when possible! // /// little distance as possible between redraws when possible!
/// // ///
/// @note Currently the foreground is not drawn in the custom screen // /// @note Currently the foreground is not drawn in the custom screen
/// manager. This is because the foreground features the general // /// manager. This is because the foreground features the general
/// inventory manager that this screen handler is based on and we // /// inventory manager that this screen handler is based on and we
/// do not want to see those text pop ups. // /// do not want to see those text pop ups.
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
public void DrawLayers(DrawContext context, float delta) { // public void DrawLayers(DrawContext context, float delta) {
for (Entry<Integer, ArrayList<GenericLayerT>> layerEntry : layers.entrySet()) { // for (Entry<Integer, ArrayList<GenericLayerT>> layerEntry : layers.entrySet()) {
var layerList = layerEntry.getValue(); // var layerList = layerEntry.getValue();
for (var layerListIterator = 0; layerListIterator < layerList.size(); layerListIterator++) { // for (var layerListIterator = 0; layerListIterator < layerList.size(); layerListIterator++) {
var layer = layerList.get(layerListIterator); // var layer = layerList.get(layerListIterator);
System.out.println("Drawing layer " + layerEntry.getKey() + " for class type " + layer.getClass().toString()); // System.out.println("Drawing layer " + layerEntry.getKey() + " for class type " + layer.getClass().toString());
layer.DrawLayer(context, layerEntry.getKey()); // layer.DrawLayer(context, layerEntry.getKey());
} // }
} // }
} // }
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
/// @fn InBounds // /// @fn InBounds
/// // ///
/// @arg[in] initX is initial position of X axis // /// @arg[in] initX is initial position of X axis
/// // ///
/// @arg[in] initY is initial position of Y axis // /// @arg[in] initY is initial position of Y axis
/// // ///
/// @arg[in] endX is the end position of X axis // /// @arg[in] endX is the end position of X axis
/// // ///
/// @arg[in] endY is the end position of Y axis // /// @arg[in] endY is the end position of Y axis
/// // ///
/// @arg[in] x is the current X value we are comparing in the X axis // /// @arg[in] x is the current X value we are comparing in the X axis
/// // ///
/// @arg[in] y is the current Y value we are comparing in the Y axis // /// @arg[in] y is the current Y value we are comparing in the Y axis
/// // ///
/// @brief Checks if an x,y coordinate position falls within the bounds // /// @brief Checks if an x,y coordinate position falls within the bounds
/// of a bounded box // /// of a bounded box
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
private boolean InBounds(int initX, int initY, int endX, int endY, int x, int y) { // private boolean InBounds(int initX, int initY, int endX, int endY, int x, int y) {
return (x >= initX && x <= endX) && (y >= initY && y <= endY); // return (x >= initX && x <= endX) && (y >= initY && y <= endY);
} // }
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
/// @fn drawBackground // /// @fn drawBackground
/// // ///
/// @arg[in] context is the drawing context of super class // /// @arg[in] context is the drawing context of super class
/// // ///
/// @arg[in] delta is the change in background draw // /// @arg[in] delta is the change in background draw
/// // ///
/// @arg[in] mouseX is the mouse x-axis position // /// @arg[in] mouseX is the mouse x-axis position
/// // ///
/// @arg[in] mouseY is the mouse y-axis position // /// @arg[in] mouseY is the mouse y-axis position
/// // ///
/// @brief This function is an abstract parent class and must be // /// @brief This function is an abstract parent class and must be
/// implemented. This is "hijacked" and just being used as our // /// implemented. This is "hijacked" and just being used as our
/// main drawing method of all the background images. There isn't // /// main drawing method of all the background images. There isn't
/// a huge difference of drawing our stuff in background vs the // /// a huge difference of drawing our stuff in background vs the
/// foreground - except possibly foreground is drawn first. // /// foreground - except possibly foreground is drawn first.
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
@Override // @Override
protected void drawBackground(DrawContext context, float delta, int mouseX, int mouseY) { // protected void drawBackground(DrawContext context, float delta, int mouseX, int mouseY) {
DrawLayers(context, delta); // DrawLayers(context, delta);
} // }
} // }

View File

@ -1,165 +1,165 @@
/* // /*
* // *
* TreeWidget // * TreeWidget
* // *
* Handles the skill tree widget // * Handles the skill tree widget
* // *
* // *
*/ // */
package jesse.keeblarcraft.gui.widgets; // package jesse.keeblarcraft.gui.widgets;
import jesse.keeblarcraft.Keeblarcraft; // import jesse.keeblarcraft.Keeblarcraft;
import jesse.keeblarcraft.Utils.CommonStructures.Position2d; // import jesse.keeblarcraft.Utils.CommonStructures.Position2d;
import jesse.keeblarcraft.gui.GenericLayerT; // import jesse.keeblarcraft.gui.GenericLayerT;
import net.minecraft.client.gui.DrawContext; // import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; // import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder;
import net.minecraft.text.Text; // import net.minecraft.text.Text;
import net.minecraft.util.Identifier; // import net.minecraft.util.Identifier;
public class TreeWidget extends GenericLayerT { // public class TreeWidget extends GenericLayerT {
private static Identifier BACKGROUND_TEXTURE = new Identifier(Keeblarcraft.MOD_ID + ":" + "textures/gui/attribute_tree_background.png"); // private static Identifier BACKGROUND_TEXTURE = new Identifier(Keeblarcraft.MOD_ID + ":" + "textures/gui/attribute_tree_background.png");
private static int maxHeight = 320; // private static int maxHeight = 320;
private static int maxLength = 640; // private static int maxLength = 640;
private int zoomScale = 1; // private int zoomScale = 1;
// private static Identifier FLIGHT_ATTRIBUTE = new Identifier(Keeblarcraft.MOD_ID + ":" + "textures/gui/attribute_flight.png"); // // private static Identifier FLIGHT_ATTRIBUTE = new Identifier(Keeblarcraft.MOD_ID + ":" + "textures/gui/attribute_flight.png");
///TODO: Make this THE root node in the attribute tree! Rename in future // ///TODO: Make this THE root node in the attribute tree! Rename in future
// private static Identifier EXAMPLE_NODE = new Identifier(Keeblarcraft.MOD_ID + ":" + "textures/gui/attribute_tree_example_node.png"); ///TODO: Make a way to make this programmatic (Proabably extend AbstractNode to carry this var) // // private static Identifier EXAMPLE_NODE = new Identifier(Keeblarcraft.MOD_ID + ":" + "textures/gui/attribute_tree_example_node.png"); ///TODO: Make a way to make this programmatic (Proabably extend AbstractNode to carry this var)
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
/// @fn TreeWidget // /// @fn TreeWidget
/// // ///
/// @brief Class constructor for constructing a tree widget. This will // /// @brief Class constructor for constructing a tree widget. This will
/// be deprecated in a future version but exists for testing // /// be deprecated in a future version but exists for testing
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
public TreeWidget() { // public TreeWidget() {
this(0, 0, 0, 0, Text.of("Test")); // this(0, 0, 0, 0, Text.of("Test"));
System.out.println("Calling empty tree constructor"); // System.out.println("Calling empty tree constructor");
} // }
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
/// @fn TreeWidget // /// @fn TreeWidget
/// // ///
/// @brief Class constructor for constructing a tree widget // /// @brief Class constructor for constructing a tree widget
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
public TreeWidget(int x, int y, int width, int height, Text message) { // public TreeWidget(int x, int y, int width, int height, Text message) {
super(x, y, width, height, message); // super(x, y, width, height, message);
this.startX = x; // this.startX = x;
this.startY = y; // this.startY = y;
this.endX = x + width; // this.endX = x + width;
this.endY = y + height; // this.endY = y + height;
} // }
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
/// @fn renderButton // /// @fn renderButton
/// // ///
/// @param[in] context is the drawing pane // /// @param[in] context is the drawing pane
/// // ///
/// @param[in] x is the X position to draw at // /// @param[in] x is the X position to draw at
/// // ///
/// @param[in] y is the Y position to draw at // /// @param[in] y is the Y position to draw at
/// // ///
/// @param[in] delta is unused in this version // /// @param[in] delta is unused in this version
/// // ///
/// @brief Primary call to draw the GUI for this widget // /// @brief Primary call to draw the GUI for this widget
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
@Override // @Override
public void renderButton(DrawContext context, int x, int y, float delta) { // public void renderButton(DrawContext context, int x, int y, float delta) {
context.drawTexture(BACKGROUND_TEXTURE, x, y, 0, 0, maxLength, maxHeight, maxLength, maxHeight); // context.drawTexture(BACKGROUND_TEXTURE, x, y, 0, 0, maxLength, maxHeight, maxLength, maxHeight);
} // }
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
/// @fn appendClickableNarrations // /// @fn appendClickableNarrations
/// // ///
/// @param[in] builder is the narration builder. This is pure virtual in // /// @param[in] builder is the narration builder. This is pure virtual in
/// the parent but is unused in this widget currently // /// the parent but is unused in this widget currently
/// // ///
/// @brief Handles the narrator // /// @brief Handles the narrator
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
@Override // @Override
protected void appendClickableNarrations(NarrationMessageBuilder builder) { // protected void appendClickableNarrations(NarrationMessageBuilder builder) {
return; // return;
} // }
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
/// @fn mouseClicked // /// @fn mouseClicked
/// // ///
/// @param[in] mouseX is where on the x-axis the mouse was clicked // /// @param[in] mouseX is where on the x-axis the mouse was clicked
/// // ///
/// @param[in] mouseY is where on the y-axis the mouse was clicked // /// @param[in] mouseY is where on the y-axis the mouse was clicked
/// // ///
/// @param[in] button is the button clicked with (think of a mouse...) // /// @param[in] button is the button clicked with (think of a mouse...)
/// // ///
/// @brief Handler for mouse click events // /// @brief Handler for mouse click events
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
@Override // @Override
public boolean mouseClicked(double mouseX, double mouseY, int button) { // public boolean mouseClicked(double mouseX, double mouseY, int button) {
return true; // return true;
} // }
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
/// @fn mouseDragged // /// @fn mouseDragged
/// // ///
/// @param[in] mouseX is where on the x-axis the mouse was dragged // /// @param[in] mouseX is where on the x-axis the mouse was dragged
/// // ///
/// @param[in] mouseY is where on the y-axis the mouse was dragged // /// @param[in] mouseY is where on the y-axis the mouse was dragged
/// // ///
/// @param[in] button is the button dragged with (think of a mouse...) // /// @param[in] button is the button dragged with (think of a mouse...)
/// // ///
/// @brief Handler for mouse drag events. delta's unused currently // /// @brief Handler for mouse drag events. delta's unused currently
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
@Override // @Override
public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { // public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) {
boolean ret = false; // boolean ret = false;
if (this.isValidClickButton(button)) { // if (this.isValidClickButton(button)) {
// Do camera panning magic stuff here // // Do camera panning magic stuff here
ret = true; // ret = true;
} // }
return ret; // return ret;
} // }
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
/// @fn mouseDragged // /// @fn mouseDragged
/// // ///
/// @param[in] mouseX is where on the x-axis the mouse was dragged // /// @param[in] mouseX is where on the x-axis the mouse was dragged
/// // ///
/// @param[in] mouseY is where on the y-axis the mouse was dragged // /// @param[in] mouseY is where on the y-axis the mouse was dragged
/// // ///
/// @param[in] amount represents scroll direction. If the value is negative // /// @param[in] amount represents scroll direction. If the value is negative
/// we scale out. If positive, we scale in // /// we scale out. If positive, we scale in
/// // ///
/// @brief Handler for mouse scroll events // /// @brief Handler for mouse scroll events
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
@Override // @Override
public boolean mouseScrolled(double mouseX, double mouseY, double amount) { // public boolean mouseScrolled(double mouseX, double mouseY, double amount) {
// Zooming INWARDS on scroll wheel produces 1.0 (which means zoom in) // // Zooming INWARDS on scroll wheel produces 1.0 (which means zoom in)
// Zooming BACKWARDS on scroll wheel produces -1.0 (which means zoom out) // // Zooming BACKWARDS on scroll wheel produces -1.0 (which means zoom out)
// We enforce a max scroll of 10 in either direction here // // We enforce a max scroll of 10 in either direction here
if (amount > 0 && zoomScale <= 10) { // if (amount > 0 && zoomScale <= 10) {
// Zoom in // // Zoom in
zoomScale++; // zoomScale++;
} else if (amount < 0 && zoomScale >= -10) { // } else if (amount < 0 && zoomScale >= -10) {
// Zoom out // // Zoom out
zoomScale--; // zoomScale--;
} // }
return true; // return true;
} // }
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
/// @fn DrawLayer // /// @fn DrawLayer
/// // ///
/// @param[in] context is the drawing pane // /// @param[in] context is the drawing pane
/// // ///
/// @param[in] layer is the layer in which this widget is being drawn in // /// @param[in] layer is the layer in which this widget is being drawn in
/// // ///
/// @brief This calls renderButton and gives it the valid drawing // /// @brief This calls renderButton and gives it the valid drawing
/// context to use. This function is called by a ScreenManager<T> // /// context to use. This function is called by a ScreenManager<T>
///////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////
@Override // @Override
public void DrawLayer(DrawContext context, int layer) { // public void DrawLayer(DrawContext context, int layer) {
Position2d pos = GetScreenCenter(); // Position2d pos = GetScreenCenter();
this.renderButton(context, pos.x - (maxLength / 2), pos.y - (maxHeight / 2), 0); // this.renderButton(context, pos.x - (maxLength / 2), pos.y - (maxHeight / 2), 0);
} // }
} // }

View File

@ -0,0 +1,17 @@
package jesse.keeblarcraft.mixin;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import net.minecraft.client.network.ClientPlayerInteractionManager;
@Mixin(ClientPlayerInteractionManager.class)
public abstract class ClientPlayerInteractionManagerMixin {
// This initial basically lets the player highlight the block at 10 blocks away. Does NOT let them break it, that is all handled in the new server mixin
// @Inject(method = "getReachDistance()F", at = @At ("HEAD"), cancellable = true)
// public void getReachDistance(CallbackInfoReturnable<Float> cir) {
// cir.setReturnValue(10.0f);
// }
}

View File

@ -1,3 +1,3 @@
// 1.20 2024-12-05T22:38:15.935314478 keeblarcraft/Keeblarcraft World Generation // 1.20.2 2025-01-01T19:10:14.65260685 keeblarcraft/Keeblarcraft World Generation
afc3340283d1101601bd4d2ca96341a58eceaf83 data/keeblarcraft/dimension_type/keeblarcraftdim_type.json afc3340283d1101601bd4d2ca96341a58eceaf83 data/keeblarcraft/dimension_type/keeblarcraftdim_type.json
4398eda2b0c28b2c754c45f5805534bf1921b243 data/keeblarcraft/worldgen/biome/test_biome.json 4398eda2b0c28b2c754c45f5805534bf1921b243 data/keeblarcraft/worldgen/biome/test_biome.json

View File

@ -10,13 +10,14 @@
package jesse.keeblarcraft.AttributeMgr; package jesse.keeblarcraft.AttributeMgr;
import java.util.HashMap; import java.util.HashMap;
import java.util.Set;
import jesse.keeblarcraft.Keeblarcraft; import jesse.keeblarcraft.Keeblarcraft;
import jesse.keeblarcraft.AttributeMgr.AttributeNodes.AbstractNode; import jesse.keeblarcraft.AttributeMgr.AttributeNodes.AbstractNode;
import jesse.keeblarcraft.AttributeMgr.AttributeNodes.AttributeFlight;
import jesse.keeblarcraft.AttributeMgr.AttributeNodes.AttributeMetalJacket; import jesse.keeblarcraft.AttributeMgr.AttributeNodes.AttributeMetalJacket;
import jesse.keeblarcraft.AttributeMgr.AttributeNodes.FactionNodes.FactionBeacon;
import jesse.keeblarcraft.AttributeMgr.AttributeNodes.FactionNodes.FactionFlight;
import jesse.keeblarcraft.ConfigMgr.ConfigManager; import jesse.keeblarcraft.ConfigMgr.ConfigManager;
import jesse.keeblarcraft.Utils.ChatUtil;
public class AttributeMgr { public class AttributeMgr {
ConfigManager config; ConfigManager config;
@ -46,13 +47,12 @@ public class AttributeMgr {
Keeblarcraft.LOGGER.error("Attempted to assign AbstractNode class type when registering object but could not call .newInstance()! Constructs must be empty"); Keeblarcraft.LOGGER.error("Attempted to assign AbstractNode class type when registering object but could not call .newInstance()! Constructs must be empty");
e.printStackTrace(); e.printStackTrace();
} }
ChatUtil.LoggerColored("Registring attribute called", ChatUtil.CONSOLE_COLOR.CYAN, Keeblarcraft.LOGGER);
try { try {
if (attributes.containsKey(verifyNode.GetNodeTitle())) { if (attributes.containsKey(verifyNode.GetNodeTitle())) {
Keeblarcraft.LOGGER.warn("Could not register attribute with duplicate name '" + verifyNode.GetNodeTitle() + "'"); Keeblarcraft.LOGGER.warn("Could not register attribute with duplicate name '" + verifyNode.GetNodeTitle() + "'");
} else { } else {
ChatUtil.LoggerColored("REGISTERING ATTRIBUTE " + verifyNode.GetNodeTitle(), ChatUtil.CONSOLE_COLOR.YELLOW, Keeblarcraft.LOGGER); Keeblarcraft.LOGGER.debug("REGISTERING ATTRIBUTE: " + verifyNode.GetNodeTitle());
attributes.put(verifyNode.GetNodeTitle(), classObj); attributes.put(verifyNode.GetNodeTitle(), classObj);
} }
} catch (Exception e) {} // Left empty since previous try-catch will throw error-message } catch (Exception e) {} // Left empty since previous try-catch will throw error-message
@ -70,6 +70,19 @@ public class AttributeMgr {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public static String ApplyAttribute(String uuid, String attributeName) { public static String ApplyAttribute(String uuid, String attributeName) {
String msg = ""; String msg = "";
// System.out.println("ApplyAttribute debug. UUID - NAME: " + uuid + " - " + attributeName);
// Set<String> keys = attributes.keySet();
// for (String key : keys) {
// System.out.println("ATTRI: " + key);
// }
// System.out.println("ACTIVE TREES: ");
// Set<String> names = activeTrees.keySet();
// for (String name : names) {
// System.out.println("N: " + name);
// }
if (attributes.containsKey(attributeName)) { if (attributes.containsKey(attributeName)) {
AttributeTree playerTree = activeTrees.get(uuid); AttributeTree playerTree = activeTrees.get(uuid);
AbstractNode node = null; AbstractNode node = null;
@ -79,7 +92,15 @@ public class AttributeMgr {
Keeblarcraft.LOGGER.error("Could not successfully apply attribute. String of attribute name could not be successfully cast to actual java object"); Keeblarcraft.LOGGER.error("Could not successfully apply attribute. String of attribute name could not be successfully cast to actual java object");
} }
if (playerTree != null && node != null) { // System.out.println("Is player tree null: " + (playerTree == null ? "YES" : "NO"));
// System.out.println("Is player node null: " + (node == null ? "YES" : "NO"));
// if (playerTree != null) {
// System.out.println("Does player have skill: " + (playerTree.ContainsAttribute(attributeName) ? "YES" : "NO"));
// }
// Ensure player tree isn't null; node isn't null; and the player doesn't already have this attribute
if (playerTree != null && node != null && !playerTree.ContainsAttribute(attributeName)) {
/////////// ///////////
// debug testing // debug testing
String isNull = (node == null ? "NULL" : "NOT NULL"); String isNull = (node == null ? "NULL" : "NOT NULL");
@ -92,13 +113,26 @@ public class AttributeMgr {
msg = "Applied attribute '" + attributeName + "' successfully"; msg = "Applied attribute '" + attributeName + "' successfully";
} else { } else {
msg = "Player tree not found!"; msg = "Player tree not found!";
// String debug = "PlayerTree is null";
// if (playerTree != null) {
// debug = playerTree.ContainsAttribute(attributeName) ? "YES":"NO";
// }
// System.out.println("APPLY ATTRIBUTE FAIL: TREE NULL, NODE NULL, OR PLAYER ALREADY HAS THIS ATTRIBUTE (DO THEY? " + debug + ")");
} }
} else { } else {
msg = "Could not apply attribute, attribute name does not exist!"; msg = "Could not apply attribute, attribute name does not exist!";
System.out.println("Attribute does not exist!");
} }
return msg; return msg;
} }
// Deletes an attribute from the node tree
public static void DisableAttribute(String uuid, String attributeName) {
if (activeTrees.containsKey(uuid) && activeTrees.get(uuid).ContainsAttribute(attributeName)) {
activeTrees.get(uuid).DeleteNode(attributeName);
}
}
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
/// @fn RegisterAttributes /// @fn RegisterAttributes
/// ///
@ -112,7 +146,8 @@ public class AttributeMgr {
/// TODO: Find a better way to do this more dynamically in the future /// TODO: Find a better way to do this more dynamically in the future
/// hint: make it an API for other modders to add to /// hint: make it an API for other modders to add to
RegisterAttributeClass(AttributeFlight.class);
RegisterAttributeClass(AttributeMetalJacket.class); RegisterAttributeClass(AttributeMetalJacket.class);
RegisterAttributeClass(FactionBeacon.class);
RegisterAttributeClass(FactionFlight.class);
} }
} }

View File

@ -1,68 +0,0 @@
/*
*
* AttributeFlight
*
* The flight attribute
*
*
*/
package jesse.keeblarcraft.AttributeMgr.AttributeNodes;
import java.util.HashMap;
import java.util.List;
import net.fabricmc.fabric.api.event.player.AttackBlockCallback;
import net.minecraft.block.BlockState;
import net.minecraft.util.ActionResult;
public class AttributeFlight extends AbstractNode {
Boolean registeredHitCallback = false;
public AttributeFlight() {
}
@Override
public String GetNodeTitle() {
return "attribute_low_health_flight";
}
@Override
public String GetNodeDescription() {
return "Gives player flight with low health";
}
@Override
public HashMap<String, List<String>> GetDetails() {
HashMap<String, List<String>> ret = new HashMap<String, List<String>>();
// Filling out description item stuff here
ret.put("Flight", List.of (
"Gives a player natural flight if they have less than or equal to two hearts remaining"
));
return ret;
}
@Override
public void RegisterCallbacks() {
// Register events here
if (registeredHitCallback == false) {
AttackBlockCallback.EVENT.register((player, world, hand, pos, direction) -> {
BlockState state = world.getBlockState(pos);
// Manual spectator check is necessary because AttackBlockCallbacks fire before the spectator check
if (!player.isSpectator() && player.getMainHandStack().isEmpty() && state.isToolRequired()) {
player.damage(world.getDamageSources().generic(), 1.0F);
}
return ActionResult.PASS;
});
}
registeredHitCallback = true;
}
}

View File

@ -8,6 +8,8 @@ import jesse.keeblarcraft.Armor.MetalJacketArmor;
import jesse.keeblarcraft.CustomItems.ItemManager; import jesse.keeblarcraft.CustomItems.ItemManager;
import net.minecraft.item.ArmorItem; import net.minecraft.item.ArmorItem;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
public final class AttributeMetalJacket extends AbstractNode { public final class AttributeMetalJacket extends AbstractNode {
// This is the custom armor set that players will receive if no armor is on & attribute is equipped // This is the custom armor set that players will receive if no armor is on & attribute is equipped

View File

@ -0,0 +1,50 @@
package jesse.keeblarcraft.AttributeMgr.AttributeNodes.FactionNodes;
import java.util.HashMap;
import java.util.List;
import jesse.keeblarcraft.AttributeMgr.AttributeNodes.AbstractNode;
import jesse.keeblarcraft.FactionMgr.Callbacks.PlayerInBaseCallback;
import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.entity.effect.StatusEffects;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.ActionResult;
public class FactionBeacon extends AbstractNode {
private int beaconStrength = 1; // Increases with faction power; 1 is default
private float absorptionAmnt = 0.2f * beaconStrength;
@Override
public String GetNodeTitle() {
return "faction_beacon";
}
@Override
public String GetNodeDescription() {
return "This is a great unlockable for any faction to have and is leveled up with higher faction power. Gives beacon-like abilities + more!";
}
@Override
public HashMap<String, List<String>> GetDetails() {
HashMap<String, List<String>> ret = new HashMap<String, List<String>>();
ret.put("Faction Beacon", List.of("Grants a ton of beacon-like effects on faction members inside the radius of the faction block"));
return ret;
}
private void ApplyEffects(ServerPlayerEntity player) {
// player.setAbsorptionAmount(absorptionAmnt);
StatusEffectInstance sei = new StatusEffectInstance(StatusEffects.REGENERATION, 1000, 1, true, true, true);
player.addStatusEffect(sei);
}
@Override
public void RegisterCallbacks() {
System.out.println("REGISTER CALLBACKS FOR FACTION BEACON CALLED");
PlayerInBaseCallback.EVENT.register((player, world) -> {
// Make sure player can fly while inside the border. We don't ever want to run this more than once!
// player.sendMessage(Text.of("Applying effects"));
ApplyEffects((ServerPlayerEntity) player);
return ActionResult.SUCCESS;
});
}
}

View File

@ -0,0 +1,148 @@
package jesse.keeblarcraft.AttributeMgr.AttributeNodes.FactionNodes;
import java.util.HashMap;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import jesse.keeblarcraft.AttributeMgr.AttributeNodes.AbstractNode;
import jesse.keeblarcraft.FactionMgr.Callbacks.PlayerCommandFlightCallback;
import jesse.keeblarcraft.FactionMgr.Callbacks.PlayerEnteredBaseCallback;
import jesse.keeblarcraft.FactionMgr.Callbacks.PlayerExitedBaseCallback;
import jesse.keeblarcraft.FactionMgr.Callbacks.PlayerInBaseCallback;
import net.minecraft.entity.player.PlayerAbilities;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import net.minecraft.util.ActionResult;
public class FactionFlight extends AbstractNode {
private final int flightSpeed = 1;
private ServerPlayerEntity player;
private float SPEED_SCALAR = 40.0f; // The value to scale this correctly to CREATIVE flight is '20.0f' however faction flight is slower than creative intentionally
private Boolean canFly = false;
private Boolean loginInBaseToggle = false; // Covers the unique case if player logs in inside the faction block border; in which case they need flight enabled!
private Integer leaveTimerMs = 5000;
@Override
public String GetNodeTitle() {
return "faction_flight";
}
@Override
public String GetNodeDescription() {
return "This is a temporary-unlock value when you are around your factions home base block and it has flight unlocked for members!";
}
@Override
public HashMap<String, List<String>> GetDetails() {
HashMap<String, List<String>> ret = new HashMap<String, List<String>>();
ret.put("Faction Flight", List.of("Grants flight when near faction base if faction has it unlocked"));
return ret;
}
public Boolean TurnOnFlight(ServerPlayerEntity player) {
Boolean isFlying = false;
PlayerAbilities abilities = player.getAbilities();
if (canFly && !abilities.allowFlying) {
abilities.allowFlying = true;
abilities.setFlySpeed((float) (flightSpeed / SPEED_SCALAR));
isFlying = true;
player.sendAbilitiesUpdate();
}
return isFlying;
}
public Boolean TurnOffFlight(ServerPlayerEntity player) {
Boolean isFlying = false;
PlayerAbilities abilities = player.getAbilities();
if (canFly && abilities.allowFlying) {
abilities.allowFlying = false;
abilities.flying = false;
abilities.setFlySpeed(0);
isFlying = false;
player.sendAbilitiesUpdate();
}
return isFlying;
}
public void ResetPlayer(ServerPlayerEntity player) {
// Disable flight
PlayerAbilities abilities = player.getAbilities();
abilities.flying = false;
abilities.allowFlying = false;
abilities.setFlySpeed(0);
player.sendAbilitiesUpdate();
}
@Override
public void RegisterCallbacks() {
PlayerEnteredBaseCallback.EVENT.register((player, world) -> {
player.sendMessage(Text.of("Faction flight enabled"));
canFly = true;
ServerPlayerEntity serverPlayer = (ServerPlayerEntity) player;
// Toggle flight
TurnOnFlight(serverPlayer);
return ActionResult.PASS;
});
PlayerInBaseCallback.EVENT.register((player, world) -> {
// Make sure player can fly while inside the border. We don't ever want to run this more than once!
if (!canFly && !loginInBaseToggle) {
player.sendMessage(Text.of("Faction flight enabled"));
loginInBaseToggle = true;
canFly = true;
ServerPlayerEntity serverPlayer = (ServerPlayerEntity) player;
TurnOnFlight(serverPlayer);
}
return ActionResult.PASS;
});
PlayerCommandFlightCallback.EVENT.register((player, world) -> {
ServerPlayerEntity serverPlayer = (ServerPlayerEntity) player;
Boolean isFlying = TurnOnFlight(serverPlayer);
// This is a toggle command; so first we get if the player is flying
PlayerAbilities abilities = player.getAbilities();
if (abilities.flying) {
TurnOffFlight((ServerPlayerEntity) player);
} else {
TurnOnFlight((ServerPlayerEntity) player);
}
System.out.println("abilities.flying: " + abilities.flying);
if(canFly && isFlying) {
serverPlayer.sendMessage(Text.of("Flight turned on"));
} else if (canFly && !isFlying) {
// Infers toggled off
serverPlayer.sendMessage(Text.of("Flight turned off"));
} else {
// Means player is not in fly-zone
serverPlayer.sendMessage(Text.of("You can only fly within the bounds of your faction base!"));
}
return ActionResult.PASS;
});
PlayerExitedBaseCallback.EVENT.register((player, world) -> {
Timer timer = new Timer();
canFly = false;
player.sendMessage(Text.of("You left the faction's perimeter! Flight will disable in 5 seconds..."));
timer.schedule(new TimerTask() {
@Override
public void run() {
// Cover the edge condition such that we leave the faction base (canFly = false) then
// the timer here starts and we come back into the base (canFly = true) - we want a NO-OP here
if (!canFly) {
player.sendMessage(Text.of("Faction flight disabled"));
ServerPlayerEntity serverPlayer = (ServerPlayerEntity) player;
ResetPlayer(serverPlayer);
}
}
}, leaveTimerMs);
return ActionResult.PASS;
});
}
}

View File

@ -17,15 +17,14 @@ import java.util.HashMap;
import jesse.keeblarcraft.Keeblarcraft; import jesse.keeblarcraft.Keeblarcraft;
import jesse.keeblarcraft.AttributeMgr.AttributeNodes.AbstractNode; import jesse.keeblarcraft.AttributeMgr.AttributeNodes.AbstractNode;
import jesse.keeblarcraft.ConfigMgr.ConfigManager; import jesse.keeblarcraft.ConfigMgr.ConfigManager;
import jesse.keeblarcraft.Utils.ChatUtil; import net.minecraft.server.network.ServerPlayerEntity;
import jesse.keeblarcraft.Utils.ChatUtil.CONSOLE_COLOR;
import jesse.keeblarcraft.Utils.CustomExceptions.FILE_WRITE_EXCEPTION;
public class AttributeTree { public class AttributeTree {
PlayerTree playerAttributeTree = new PlayerTree(); PlayerTree playerAttributeTree = new PlayerTree();
ConfigManager config = new ConfigManager(); ConfigManager config = new ConfigManager();
private AbstractNode root = new RootNode(); private AbstractNode root = new RootNode();
private ServerPlayerEntity player;
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
/// @class TreeNode /// @class TreeNode
@ -33,7 +32,7 @@ public class AttributeTree {
/// @brief This is an individual node that goes within the larger /// @brief This is an individual node that goes within the larger
/// PlayerTree class object /// PlayerTree class object
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
private class TreeNode { public class TreeNode {
public TreeNode(AbstractNode node, Integer maxLevel, List<String> parents, List<String> children) { public TreeNode(AbstractNode node, Integer maxLevel, List<String> parents, List<String> children) {
thisNode = node; thisNode = node;
parentNodes = parents; parentNodes = parents;
@ -42,15 +41,15 @@ public class AttributeTree {
currentNodeLevel = 1; currentNodeLevel = 1;
} }
AbstractNode thisNode; public AbstractNode thisNode;
Integer currentNodeLevel; public Integer currentNodeLevel;
Integer maxNodeLevel; public Integer maxNodeLevel;
// Store the names of the parent and children nodes; this lets a node have any number of parents and children // Store the names of the parent and children nodes; this lets a node have any number of parents and children
// NOTE TO DEVELOPERS: Be aware! The more nodes the harrier the tree will look in the GUI!!! Always test your // NOTE TO DEVELOPERS: Be aware! The more nodes the harrier the tree will look in the GUI!!! Always test your
// code before just adding stuff willy-nilly! // code before just adding stuff willy-nilly!
List<String> parentNodes; public List<String> parentNodes;
List<String> childrenNodes; public List<String> childrenNodes;
} }
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@ -61,10 +60,10 @@ public class AttributeTree {
/// stored inside the AttributeMgr class /// stored inside the AttributeMgr class
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
private class PlayerTree { private class PlayerTree {
String uuid; public String uuid;
// Key = name of AbstractNode // Key = name of AbstractNode
// Val = The attribute itself // Val = The attribute itself
HashMap<String, TreeNode> tree = new HashMap<String, TreeNode>(); public HashMap<String, TreeNode> tree = new HashMap<String, TreeNode>();
} }
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@ -172,6 +171,8 @@ public class AttributeTree {
playerAttributeTree.tree.put(newNode.GetNodeTitle(), new TreeNode(newNode, maxNodeLevel, parents, children)); playerAttributeTree.tree.put(newNode.GetNodeTitle(), new TreeNode(newNode, maxNodeLevel, parents, children));
// if the new nodes level is not 0 we need to manually register the callbacks // if the new nodes level is not 0 we need to manually register the callbacks
System.out.println("Node title: " + newNode.GetNodeTitle() + " has power level " +
playerAttributeTree.tree.get(newNode.GetNodeTitle()).currentNodeLevel);
if (playerAttributeTree.tree.get(newNode.GetNodeTitle()).currentNodeLevel != 0) { if (playerAttributeTree.tree.get(newNode.GetNodeTitle()).currentNodeLevel != 0) {
System.out.println("Registering new callback for new node"); System.out.println("Registering new callback for new node");
playerAttributeTree.tree.get(newNode.GetNodeTitle()).thisNode.RegisterCallbacks(); playerAttributeTree.tree.get(newNode.GetNodeTitle()).thisNode.RegisterCallbacks();
@ -212,6 +213,18 @@ public class AttributeTree {
FlashConfig(); FlashConfig();
} }
/////////////////////////////////////////////////////////////////////////////
/// @fn public Boolean ContainsAttribute(String nodeName) {
///
/// @arg[in] nodeName is the attribute node title
///
/// @brief Returns true if this player presently has the 'nodeName'
/// attribute unlocked
/////////////////////////////////////////////////////////////////////////////
public Boolean ContainsAttribute(String nodeName) {
return playerAttributeTree.tree.containsKey(nodeName);
}
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
/// @fn DeleteNode /// @fn DeleteNode
/// ///
@ -265,37 +278,35 @@ public class AttributeTree {
/// ///
/// @brief Constructor for class /// @brief Constructor for class
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
public AttributeTree(String uuid) { public AttributeTree(ServerPlayerEntity p) {
// DEVELOPER NOTE: this.player = p;
// If you are testing this part of the code, please be reminded that anonymous testing starts a new String uuid = player.getUuidAsString();
// player instance everytime you launch. This means the UUID CAN CHANGE when you launch the
// game! This is not an issue with proper registered accounts in production
Boolean existingFile = false; Boolean existingFile = false;
try { try {
playerAttributeTree = config.GetJsonObjectFromFile("attributes/" + uuid + ".json", PlayerTree.class); playerAttributeTree = config.GetJsonObjectFromFile("attributes/" + uuid + ".json", PlayerTree.class);
existingFile = true; existingFile = playerAttributeTree != null;
} catch (Exception e) { } catch (Exception e) {
System.out.println("Attribute tree file does not exist for this player");
// Do nothing. This means the file does not exist // Do nothing. This means the file does not exist
} }
// In the event the above code failed out, this means a new file has to be created for the player's uuid // In the event the above code failed out, this means a new file has to be created for the player's uuid
if (!existingFile) if (!existingFile)
{ {
System.out.println(ChatUtil.ColoredString("Trying to create new file", CONSOLE_COLOR.BLUE)); System.out.println("Trying to create new file");
try { try {
playerAttributeTree = new PlayerTree();
playerAttributeTree.uuid = uuid; playerAttributeTree.uuid = uuid;
FlashConfig(); FlashConfig();
} catch (Exception e) { } catch (Exception e) {
System.out.println(ChatUtil.ColoredString("Could not write to file", CONSOLE_COLOR.RED)); System.out.println("Could not write to file");
} }
} else {
System.out.println(ChatUtil.ColoredString("Moving on", CONSOLE_COLOR.BLUE));
} }
// It's possible the above code will return a blank class if a file doesn't exist. This will make // It's possible the above code will return a blank class if a file doesn't exist. This will make
// a new file with this players uuid // a new file with this players uuid
if ("".equals(playerAttributeTree.uuid)) { if ("".equals(playerAttributeTree.uuid)) {
System.out.println(ChatUtil.ColoredString("Assigning new config file for this uuid. No previous existing", CONSOLE_COLOR.BLUE));
playerAttributeTree.uuid = uuid; playerAttributeTree.uuid = uuid;
} }
@ -313,10 +324,7 @@ public class AttributeTree {
/// @brief Flashes the config to the disk /// @brief Flashes the config to the disk
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
public void FlashConfig() { public void FlashConfig() {
try { /// TODO: This is broken because of a 'java.util.Option#value it cannot write. Idk, fix soon'
config.WriteToJsonFile("attributes/" + playerAttributeTree.uuid + ".json", playerAttributeTree); // config.WriteToJsonFile("attributes/" + playerAttributeTree.uuid + ".json", playerAttributeTree);
} catch (FILE_WRITE_EXCEPTION e) {
System.out.println(ChatUtil.ColoredString("Could not flash notes configuration file", CONSOLE_COLOR.RED));
}
} }
} }

View File

@ -0,0 +1,9 @@
package jesse.keeblarcraft.BankMgr;
public class BankAccountType {
public enum ACCOUNT_TYPE {
CHECKING,
SAVINGS
}
}

View File

@ -5,8 +5,7 @@ import java.util.List;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Map.Entry; import java.util.Map.Entry;
import org.apache.logging.log4j.core.jmx.Server; import jesse.keeblarcraft.BankMgr.BankAccountType.ACCOUNT_TYPE;
import jesse.keeblarcraft.ConfigMgr.ConfigManager; import jesse.keeblarcraft.ConfigMgr.ConfigManager;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text; import net.minecraft.text.Text;
@ -26,7 +25,8 @@ public final class BankManager {
private class PlayerBankConfig { private class PlayerBankConfig {
List<String> activeBanks = new ArrayList<String>(); // List of all banks a player has accounts in List<String> activeBanks = new ArrayList<String>(); // List of all banks a player has accounts in
String defaultSelectedBank; String defaultSelectedBank = "";
String defaultSelectedAccount = "";
} }
// Key = player uuid // Key = player uuid
@ -44,7 +44,11 @@ public final class BankManager {
// Val = Bank routing number // Val = Bank routing number
private HashMap<String, Integer> bankNameFastMap = new HashMap<String, Integer>(); private HashMap<String, Integer> bankNameFastMap = new HashMap<String, Integer>();
public BankManager() {} public BankManager() {
if (playerConfigs == null) {
playerConfigs = new HashMap<String, PlayerBankConfig>();
}
}
// TODO: THIS NEEDS TO READ IN FROM A FILE TO STOP NUKING BANKS ON REBOOT // TODO: THIS NEEDS TO READ IN FROM A FILE TO STOP NUKING BANKS ON REBOOT
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@ -118,10 +122,14 @@ public final class BankManager {
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
public void ChangeDefaultPlayerAccount(ServerPlayerEntity player, String newDefaultAccount) { public void ChangeDefaultPlayerAccount(ServerPlayerEntity player, String newDefaultAccount) {
String bankName = AccountNumberGenerator.GetFinancialSymbolFromId(newDefaultAccount); String bankName = AccountNumberGenerator.GetFinancialSymbolFromId(newDefaultAccount);
System.out.println("ChangeDefaultPlayerAccount: Received bankName " + bankName);
System.out.println(bankNameFastMap);
// Verify bank exists first // Verify bank exists first
System.out.println(bankNameFastMap);
for(Entry<String, Integer> entry : bankNameFastMap.entrySet()) {
System.out.println("KEY: " + entry.getKey());
}
if (bankNameFastMap.containsKey(bankName)) { if (bankNameFastMap.containsKey(bankName)) {
Integer routNum = bankNameFastMap.get(bankName); Integer routNum = bankNameFastMap.get(bankName);
IndividualBank bank = banks.get(routNum); IndividualBank bank = banks.get(routNum);
@ -129,10 +137,29 @@ public final class BankManager {
// Verify this person has access to this account // Verify this person has access to this account
if(bank.IsAccountHolder(newDefaultAccount, player.getUuidAsString())) { if(bank.IsAccountHolder(newDefaultAccount, player.getUuidAsString())) {
// Finally update config to this account since checks pass // Finally update config to this account since checks pass
playerConfigs.get(player.getUuidAsString()).defaultSelectedBank = newDefaultAccount; playerConfigs.get(player.getUuidAsString()).defaultSelectedAccount = newDefaultAccount;
} }
} else { } else {
player.sendMessage(Text.of("Could not change default selected bank. Bank does not exist!")); player.sendMessage(Text.of("Could not change default selected account. Bank does not exist!"));
}
}
// This guarentees a player config exists; and so can be called from many areas. Does not erase pre-existing config
public boolean EnsurePlayerConfigExists(String uuid) {
if (!playerConfigs.containsKey(uuid)) {
playerConfigs.put(uuid, new PlayerBankConfig());
}
return true;
}
// Allows the player to select a bank
public void ChangeDefaultSelectedBank(ServerPlayerEntity player, String bankName) {
if (bankNameFastMap.containsKey(bankName) && EnsurePlayerConfigExists(player.getUuidAsString())) {
playerConfigs.get(player.getUuidAsString()).defaultSelectedBank = bankName;
player.sendMessage(Text.of("You have successfully selected the following financial institution: " + bankName));
player.sendMessage(Text.of("Please be aware the context of commands following this will likely be done under this financial institution"));
} else {
player.sendMessage(Text.of("That bank does not exist."));
} }
} }
@ -198,9 +225,9 @@ public final class BankManager {
/// ///
/// @brief Initiate a funds transfer between accounts or banks /// @brief Initiate a funds transfer between accounts or banks
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
public void InitiateBankFundsTransfer(ServerPlayerEntity fromPlayer, String toAccount, Integer amount) { public void InitiateBankFundsTransfer(ServerPlayerEntity fromPlayer, String toAccount, Integer amount, String reason) {
// Get player default selection // Get player default selection
String fromAccount = playerConfigs.get(fromPlayer.getUuidAsString()).defaultSelectedBank; String fromAccount = playerConfigs.get(fromPlayer.getUuidAsString()).defaultSelectedAccount;
String fromAccountSymbol = AccountNumberGenerator.GetFinancialSymbolFromId(fromAccount); String fromAccountSymbol = AccountNumberGenerator.GetFinancialSymbolFromId(fromAccount);
String toAccountSymbol = AccountNumberGenerator.GetFinancialSymbolFromId(toAccount); String toAccountSymbol = AccountNumberGenerator.GetFinancialSymbolFromId(toAccount);
@ -246,12 +273,21 @@ public final class BankManager {
String account = ""; String account = "";
if (playerConfigs.containsKey(playerUuid)) { if (playerConfigs.containsKey(playerUuid)) {
account = playerConfigs.get(playerUuid).defaultSelectedBank; account = playerConfigs.get(playerUuid).defaultSelectedAccount;
} }
return account; return account;
} }
public String GetPlayerSelectedBank(String playerUuid) {
String bank = "";
if (playerConfigs.containsKey(playerUuid)) {
bank = playerConfigs.get(playerUuid).defaultSelectedBank;
}
return bank;
}
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
/// @fn InitiateBankAccountCreation /// @fn InitiateBankAccountCreation
/// ///
@ -263,40 +299,18 @@ public final class BankManager {
/// ///
/// @brief Initiates a bank account creation with a bank /// @brief Initiates a bank account creation with a bank
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
public void InitiateBankAccountCreation(String bankIdentifier, ServerPlayerEntity player, String accountType) { public void InitiateBankAccountCreation(String bankIdentifier, ServerPlayerEntity player, ACCOUNT_TYPE accountType) {
Boolean success = false; Boolean success = false;
System.out.println("initiating bank creation"); IndividualBank bank = GetBankByName(bankIdentifier);
boolean defaultServerBank = bankIdentifier == null || bankIdentifier == "";
System.out.println("value of bankIdentifier is " + defaultServerBank);
System.out.println("The player name is " + player.getDisplayName().getString()); if (bank != null) {
success = bank.CreateAccount(player.getUuidAsString(), player.getEntityName(), accountType);
// DEBUG
System.out.println("BANK NAME: " + banks.get(KEEBLARCRAFT_SERVER_BANK_ID).GetBankName());
System.out.println("BANK BALANCE: " + banks.get(KEEBLARCRAFT_SERVER_BANK_ID).GetBankBalance());
// DEBUG END
// Create an account via the server-owned bank account
if (defaultServerBank) {
success = banks.get(KEEBLARCRAFT_SERVER_BANK_ID).CreateAccount(player.getUuidAsString(), player.getDisplayName().getString(), accountType);
} else {
System.out.println("Creating bank on non-server owned bank");
// Create an account via a specified bank identifier
Integer routingNumber = Integer.parseInt(bankIdentifier);
if (banks.containsKey(routingNumber)) {
banks.get(routingNumber).CreateAccount(player.getUuidAsString(), player.getDisplayName().getString(), accountType);
} else {
player.sendMessage(Text.of("That bank does not exist"));
}
} }
if (success) { if (success) {
player.sendMessage(Text.of("The banking operation was successful and your banking information has been updated")); player.sendMessage(Text.of("The banking operation was successful and your banking information has been updated"));
} else { } else {
player.sendMessage(Text.of("The banking operating FAILED. You may need to visit the bank for more information!")); player.sendMessage(Text.of("The banking operating FAILED. Make sure you selected this bank before creating it!"));
} }
} }
} }

View File

@ -2,6 +2,8 @@ package jesse.keeblarcraft.BankMgr;
import java.util.List; import java.util.List;
import jesse.keeblarcraft.BankMgr.BankAccountType.ACCOUNT_TYPE;
// Contains the information of an individuals player's bank account. // Contains the information of an individuals player's bank account.
// TODO: Add ability to store NBT data of items in the future so we can store not just money but items too // TODO: Add ability to store NBT data of items in the future so we can store not just money but items too
// like a safety deposit box // like a safety deposit box
@ -16,14 +18,14 @@ public class IndividualAccount {
private Integer accountBalance; private Integer accountBalance;
private Boolean allowNegativeBalance; private Boolean allowNegativeBalance;
private Boolean accountLocked; private Boolean accountLocked;
private Integer accountType; // TODO: Replace with enum in future. Valid is "checking" and "savings" right now private ACCOUNT_TYPE accountType;
public IndividualAccount() {} public IndividualAccount() {}
public IndividualAccount(String accountNumber, Integer routingNumber, List<String> holders, public IndividualAccount(String accountNumber, Integer routingNumber, List<String> holders,
List<String> accountHolderUuids, Boolean allowNegativeBalance, Integer initialBalance, List<String> accountHolderUuids, Boolean allowNegativeBalance, Integer initialBalance,
String alias, Integer accountType, String bankLetterIdentifier) { String alias, ACCOUNT_TYPE accountType, String bankLetterIdentifier) {
System.out.println("Called to create new IndividualAccount with following values: " + accountNumber + " " + routingNumber + " " + holders + " " + System.out.println("Called to create new IndividualAccount with following values: " + accountNumber + " " + routingNumber + " " + holders + " " +
accountHolderUuids + " " + allowNegativeBalance + " " + initialBalance + " " + alias + " " + accountType); accountHolderUuids + " " + allowNegativeBalance + " " + initialBalance + " " + alias + " " + accountType);

View File

@ -11,23 +11,22 @@ import static java.util.Map.entry;
import java.io.File; import java.io.File;
import jesse.keeblarcraft.ConfigMgr.ConfigManager; import jesse.keeblarcraft.ConfigMgr.ConfigManager;
import jesse.keeblarcraft.Utils.ChatUtil; import jesse.keeblarcraft.Keeblarcraft;
import jesse.keeblarcraft.Utils.ChatUtil.CONSOLE_COLOR; import jesse.keeblarcraft.BankMgr.BankAccountType.ACCOUNT_TYPE;
import jesse.keeblarcraft.Utils.CustomExceptions.FILE_WRITE_EXCEPTION;
// Contains the information of an individual bank // Contains the information of an individual bank
// //
// The bank will keep track of all accounts within its facilities. In addition to accounts, the bank // The bank will keep track of all accounts within its facilities. In addition to accounts, the bank
// maintains its own identifier which is unique and other misc things. // maintains its own identifier which is unique and other misc things.
public class IndividualBank { public class IndividualBank {
private Map<String, Integer> ACCOUNT_TYPES = Map.ofEntries( private Map<ACCOUNT_TYPE, Integer> ACCOUNT_TYPES = Map.ofEntries(
entry("checking", 0), entry(ACCOUNT_TYPE.CHECKING, 0),
entry("savings", 1) entry(ACCOUNT_TYPE.SAVINGS, 1)
); );
private ConfigManager config = new ConfigManager(); private ConfigManager config = new ConfigManager();
private Integer routingNumber; // this is the banks unique identifier private Integer routingNumber; // this is the banks unique identifier
private Integer numberOfAccounts; // Total number of accounts the bank has. This includes only active accounts inside accountsList. private Integer numberOfAccounts = 0; // Total number of accounts the bank has. This includes only active accounts inside accountsList.
private Integer maxBankAccounts = 100_000_000; // Making this simple for myself any one type of account has 8 random numbers genereated so 10^8 possible accounts private Integer maxBankAccounts = 100_000_000; // Making this simple for myself any one type of account has 8 random numbers genereated so 10^8 possible accounts
private String bankFourLetterIdentifier; private String bankFourLetterIdentifier;
private String registeredBankName; private String registeredBankName;
@ -36,13 +35,13 @@ public class IndividualBank {
// Think FDIC but from the servers account (keeblarcraft insurance corporation) // Think FDIC but from the servers account (keeblarcraft insurance corporation)
// KBIC will ensure an amount of money based on its trustworthiness to a bank and the number of holders it has. // KBIC will ensure an amount of money based on its trustworthiness to a bank and the number of holders it has.
private Integer kbicInsuredAmount; private Integer kbicInsuredAmount = 0;
private Boolean kbicInsured; private Boolean kbicInsured = false;
// bankMoney is the total amount of money the bank possesses itself. The bank itself is personally responsible // bankMoney is the total amount of money the bank possesses itself. The bank itself is personally responsible
// for backing the amount of money it claims it has and this is the balance that is withdrawn from for credits. // for backing the amount of money it claims it has and this is the balance that is withdrawn from for credits.
// A bank can have a sum of money that is less than the total amount of money of all its account holders // A bank can have a sum of money that is less than the total amount of money of all its account holders
private Integer bankMoney; private Integer bankMoney = 0;
// Key = ACCOUNT NUMBER // Key = ACCOUNT NUMBER
// Value = ACCOUNT // Value = ACCOUNT
@ -89,7 +88,7 @@ public class IndividualBank {
// TODO: REPLACE WITH SQL SERVER. DIRTY ITERATE OVER ALL FILES IN DIRECTORY TO LOAD STRUCTURE // TODO: REPLACE WITH SQL SERVER. DIRTY ITERATE OVER ALL FILES IN DIRECTORY TO LOAD STRUCTURE
File dir = new File(accountsListDir); File dir = new File(accountsListDir);
File[] allFiles = dir.listFiles(); File[] allFiles = dir.listFiles();
if (allFiles != null) { if (accounts != null && allFiles != null) {
for (File file : allFiles ) { for (File file : allFiles ) {
// First grab file identifier as KEY // First grab file identifier as KEY
String accountIdentifier = file.getName(); String accountIdentifier = file.getName();
@ -107,7 +106,6 @@ public class IndividualBank {
if (!existingFile) if (!existingFile)
{ {
System.out.println(ChatUtil.ColoredString("Trying to create new file", CONSOLE_COLOR.BLUE));
try { try {
// We assume the bank dir is created by server. Create this banks dir // We assume the bank dir is created by server. Create this banks dir
// config.CreateDirectory("bank/" + routingNumber); // config.CreateDirectory("bank/" + routingNumber);
@ -117,32 +115,35 @@ public class IndividualBank {
// Flash initial account configuration file for this bank // Flash initial account configuration file for this bank
FlashConfig("accounts"); FlashConfig("accounts");
} catch (Exception e) { } catch (Exception e) {
System.out.println(ChatUtil.ColoredString("Could not write to file", CONSOLE_COLOR.RED)); Keeblarcraft.LOGGER.error("Could not write to file in IndividualBank");
} }
} else {
System.out.println(ChatUtil.ColoredString("Moving on", CONSOLE_COLOR.BLUE));
} }
// A modified config reader is needed here for when each IndividualAccount is read in - the name is taken from that and is attached to the // A modified config reader is needed here for when each IndividualAccount is read in - the name is taken from that and is attached to the
// 'accountsListFromName' structure. This makes it no worse than O(n) to fill these two structures in. // 'accountsListFromName' structure. This makes it no worse than O(n) to fill these two structures in.
// NOTE: This is an *EXPENSIVE* operation! Future us might need to update this. Also note a method is needed for everytime a player opens a new account // NOTE: This is an *EXPENSIVE* operation! Future us might need to update this. Also note a method is needed for everytime a player opens a new account
// or gets put on one to update the map every time // or gets put on one to update the map every time
for (Entry<String, IndividualAccount> account : accounts.accountsList.entrySet()) { if (accounts != null) {
// We must loop over the string of holders for each account as well to make the flattened accountsListFromName map for (Entry<String, IndividualAccount> account : accounts.accountsList.entrySet()) {
List<String> accountHolders = account.getValue().GetAccountHolders(); // We must loop over the string of holders for each account as well to make the flattened accountsListFromName map
List<String> accountHolders = account.getValue().GetAccountHolders();
// Match each user to the secondary map & add to list-value if not existing // Match each user to the secondary map & add to list-value if not existing
for (Integer holderIndex = 0; holderIndex < accountHolders.size(); holderIndex++) { for (Integer holderIndex = 0; holderIndex < accountHolders.size(); holderIndex++) {
if (accounts.accountsListFromName.containsKey(accountHolders.get(holderIndex))) { if (accounts.accountsListFromName.containsKey(accountHolders.get(holderIndex))) {
// Case 1: User exists, update map entry // Case 1: User exists, update map entry
accounts.accountsListFromName.get(accountHolders.get(holderIndex)).add(account.getKey()); // Add a new account id to this person in the new flat map accounts.accountsListFromName.get(accountHolders.get(holderIndex)).add(account.getKey()); // Add a new account id to this person in the new flat map
} else { } else {
// Case 2: User does not already exist; add a new map entry // Case 2: User does not already exist; add a new map entry
accounts.accountsListFromName.put(accountHolders.get(holderIndex), List.of(account.getKey())); // Store name as key, and new List with the value of ACCOUNT # accounts.accountsListFromName.put(accountHolders.get(holderIndex), List.of(account.getKey())); // Store name as key, and new List with the value of ACCOUNT #
}
} }
} }
numberOfAccounts = accounts.accountsList.size();
} else {
accounts = new Accounts();
numberOfAccounts = 0;
} }
numberOfAccounts = accounts.accountsList.size();
} }
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@ -164,12 +165,9 @@ public class IndividualBank {
/// @return List of all bank accounts. List will be EMPTY if no accounts /// @return List of all bank accounts. List will be EMPTY if no accounts
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
public List<IndividualAccount> GetAccountsOfUser(String uuid) { public List<IndividualAccount> GetAccountsOfUser(String uuid) {
System.out.println("UUID passed in: " + uuid);
List<IndividualAccount> accountsFromUser = new ArrayList<IndividualAccount>(); List<IndividualAccount> accountsFromUser = new ArrayList<IndividualAccount>();
List<String> listOfAccounts = accounts.accountsListFromName.get(uuid); List<String> listOfAccounts = accounts.accountsListFromName.get(uuid);
System.out.println("Is list of accounts null? " + (listOfAccounts == null ? "YES" : "NO"));
System.out.println("List of account size: " + listOfAccounts.size());
if (listOfAccounts != null && listOfAccounts.size() > 0) { if (listOfAccounts != null && listOfAccounts.size() > 0) {
for (int i = 0; i < listOfAccounts.size(); i++) { for (int i = 0; i < listOfAccounts.size(); i++) {
accountsFromUser.add(accounts.accountsList.get(listOfAccounts.get(i))); accountsFromUser.add(accounts.accountsList.get(listOfAccounts.get(i)));
@ -370,17 +368,14 @@ public class IndividualBank {
/// ///
/// @return True if account can be created, false if it fails /// @return True if account can be created, false if it fails
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
public Boolean CreateAccount(String holderUuid, String holderName, String accountTypeStr) { public Boolean CreateAccount(String holderUuid, String holderName, ACCOUNT_TYPE accountType) {
Boolean success = false; Boolean success = false;
System.out.println("Attempting to create new bank account given args UUID / NAME / TYPE : " + holderUuid + " " + holderName + " " + accountTypeStr); if (accounts.accountsList.size() <= maxBankAccounts) {
System.out.println("accounts size is " + accounts.accountsList.size());
System.out.println("account string is { " + accountTypeStr + " }. Does this account type exist in this bank? => " + ACCOUNT_TYPES.containsKey(accountTypeStr.toLowerCase()));
if (accounts.accountsList.size() <= maxBankAccounts && ACCOUNT_TYPES.containsKey(accountTypeStr.toLowerCase())) {
// Verify this isn't a blacklisted user // Verify this isn't a blacklisted user
System.out.println("Is user bank locked? " + lockedUsers.contains(holderName)); System.out.println("Is user bank locked? " + lockedUsers.contains(holderName));
if (!lockedUsers.contains(holderName)) { if (!lockedUsers.contains(holderName)) {
Integer maxAttempts = 15; // Reasonably a unique bank account should pop up within 1000 generations. If not, the user may try again. Integer maxAttempts = 15; // Reasonably a unique bank account should pop up within 1000 generations. If not, the user may try again.
String accountId = AccountNumberGenerator.GenerateNewAccountNumber(bankFourLetterIdentifier, routingNumber, ACCOUNT_TYPES.get(accountTypeStr), holderName); String accountId = AccountNumberGenerator.GenerateNewAccountNumber(bankFourLetterIdentifier, routingNumber, ACCOUNT_TYPES.get(accountType), holderName);
System.out.println("Account generator came back with bank account id { " + accountId + " }"); System.out.println("Account generator came back with bank account id { " + accountId + " }");
System.out.println("4 letter bank: " + AccountNumberGenerator.GetFinancialSymbolFromId(accountId)); System.out.println("4 letter bank: " + AccountNumberGenerator.GetFinancialSymbolFromId(accountId));
@ -391,7 +386,7 @@ public class IndividualBank {
// TODO: Fix in future with a method that will guarentee a one-time necessary number generator. Statistically speaking; this will be okay for the // TODO: Fix in future with a method that will guarentee a one-time necessary number generator. Statistically speaking; this will be okay for the
// entire life time of the server. BUT, you never know! // entire life time of the server. BUT, you never know!
while (maxAttempts != 0 && !accounts.accountsList.containsKey(AccountNumberGenerator.GetAccountNumberFromId(accountId))) { while (maxAttempts != 0 && !accounts.accountsList.containsKey(AccountNumberGenerator.GetAccountNumberFromId(accountId))) {
accountId = AccountNumberGenerator.GenerateNewAccountNumber(bankFourLetterIdentifier, routingNumber, ACCOUNT_TYPES.get(accountTypeStr), holderName); accountId = AccountNumberGenerator.GenerateNewAccountNumber(bankFourLetterIdentifier, routingNumber, ACCOUNT_TYPES.get(accountType), holderName);
System.out.println("Account generator came back with bank account id { " + accountId + " }"); System.out.println("Account generator came back with bank account id { " + accountId + " }");
maxAttempts--; maxAttempts--;
} }
@ -402,7 +397,7 @@ public class IndividualBank {
if (!accounts.accountsList.containsKey(actualAccountNumber)) { if (!accounts.accountsList.containsKey(actualAccountNumber)) {
IndividualAccount newAccount = new IndividualAccount(actualAccountNumber, this.routingNumber, List.of(holderName), IndividualAccount newAccount = new IndividualAccount(actualAccountNumber, this.routingNumber, List.of(holderName),
List.of(holderUuid), false, 0, List.of(holderUuid), false, 0,
"", ACCOUNT_TYPES.get(accountTypeStr), bankFourLetterIdentifier); "", accountType, bankFourLetterIdentifier);
System.out.println("Updating accounts list for this bank"); System.out.println("Updating accounts list for this bank");
UpdateBankAccounts(holderName, holderUuid, actualAccountNumber, newAccount); UpdateBankAccounts(holderName, holderUuid, actualAccountNumber, newAccount);
success = true; success = true;
@ -564,12 +559,7 @@ public class IndividualBank {
} }
// Re-flash file // Re-flash file
try { config.WriteToJsonFile(dirName + "/" + accountNum + ".json", singleAccount.getValue());
config.WriteToJsonFile(dirName + "/" + accountNum + ".json", singleAccount.getValue());
} catch (FILE_WRITE_EXCEPTION e) {
System.out.println("Failed to flash configuration file properly. Printing stack trace");
e.printStackTrace();
}
} }
} }
} }

View File

@ -4,11 +4,13 @@ package jesse.keeblarcraft.BankMgr;
public class TransactionMetadata { public class TransactionMetadata {
enum TRANSACTION_TYPE { enum TRANSACTION_TYPE {
DEBIT, DEBIT,
CREDIT CREDIT,
WITHDRAWAL,
DEPOSIT
} }
public String fromParty; // Account ID public String fromParty; // Account ID
public String toParty; // Account ID public String toParty; // Account ID or party (like ATM/self,etc)
public Integer amount; public Integer amount;
public String transactionId; public String transactionId;
public TRANSACTION_TYPE transactionType; public TRANSACTION_TYPE transactionType;

View File

@ -0,0 +1,43 @@
package jesse.keeblarcraft.ChatStuff;
public class ChatFormatting {
// These are for Minecraft chat box
public static String COLOR_START = "§";
public static String COLOR_END = "§f";
public static enum COLOR_CODE {
BLUE,
GRAY,
GOLD,
RED,
GREEN
}
/////////////////////////////////////////////////////////////////////////////
/// @fn getColor
///
/// @param[in] code is the color code that is desired
///
/// @brief Returns the MINECRAFT color code in string form to help build
/// colored messages for players
///
/// @return String representation of color code
/////////////////////////////////////////////////////////////////////////////
public static String GetColor(COLOR_CODE code) {
String colorStr = COLOR_START;
switch(code) {
case BLUE:
return colorStr + "9";
case GRAY:
return colorStr + "7";
case GOLD:
return colorStr + "6";
case RED:
return colorStr + "4";
case GREEN:
return colorStr + "2";
}
// If this code is reachable, then someone has not properly handled the above switch-case
return colorStr;
}
}

View File

@ -0,0 +1,68 @@
package jesse.keeblarcraft.ChatStuff;
import java.util.ArrayList;
import java.util.List;
import jesse.keeblarcraft.ChatStuff.ChatFormatting.COLOR_CODE;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
// Create a "chat menu" which is just a menu in chat with pages that a user can click to display
// the next page.
public class ChatMenu {
private List<Text> msgList = new ArrayList<>();
private Text header;
private Text leftArrow;
private Text rightArrow;
private int pageLimit = 5; // Messages per page in this menu
private int pageCount = 1; // Calculated at runtime
private ChatMsg formatter = new ChatMsg();
public ChatMenu() {
// Initialize default header and arrows
header = Text.of("[----- HELP MENU -----]");
header = formatter.ColorMsg(header, COLOR_CODE.GOLD);
leftArrow = Text.of("<<");
leftArrow = formatter.ColorMsg(leftArrow, COLOR_CODE.GOLD);
rightArrow = Text.of(">>");
rightArrow = formatter.ColorMsg(rightArrow, COLOR_CODE.GOLD);
}
public void SetHeader(Text header) {
this.header = header;
}
public void SetLeftArrow(Text leftArrow) {
this.leftArrow = leftArrow;
}
public void SetRightArrow(Text rightArrow) {
this.rightArrow = rightArrow;
}
public void AddMsg(Text newMsg) {
msgList.add(newMsg);
}
public void AddMsg(String newMsg) {
AddMsg(Text.of(newMsg));
}
public void ClearList() {
msgList.clear();
pageCount = 1;
}
public void SetPageLimit(int limit) {
if (limit >= 1) {
pageLimit = limit;
}
}
public void SendMsg(ServerPlayerEntity target) {
// Calculate number of pages
pageCount = (int) Math.ceil(msgList.size() / (double) pageLimit);
}
}

View File

@ -1,54 +1,24 @@
package jesse.keeblarcraft.Utils; /*
*
* ChatMsg
*
* Helpful utility for pretty printing in chat in the game with different supported functions and levels
*
*/
package jesse.keeblarcraft.ChatStuff;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import jesse.keeblarcraft.ChatStuff.ChatFormatting.COLOR_CODE;
import net.minecraft.text.ClickEvent; import net.minecraft.text.ClickEvent;
import net.minecraft.text.HoverEvent; import net.minecraft.text.HoverEvent;
import net.minecraft.text.MutableText; import net.minecraft.text.MutableText;
import net.minecraft.text.Style; import net.minecraft.text.Style;
import net.minecraft.text.Text; import net.minecraft.text.Text;
public class HelpBuilder { public class ChatMsg {
private String COLOR_START = "§";
private String COLOR_END = "§f";
public enum COLOR_CODE {
BLUE,
GRAY,
GOLD,
RED,
GREEN
}
/////////////////////////////////////////////////////////////////////////////
/// @fn getColor
///
/// @param[in] code is the color code that is desired
///
/// @brief Returns the MINECRAFT color code in string form to help build
/// colored messages for players
///
/// @return String representation of color code
/////////////////////////////////////////////////////////////////////////////
private String getColor(COLOR_CODE code) {
String colorStr = COLOR_START;
switch(code) {
case BLUE:
return colorStr + "9";
case GRAY:
return colorStr + "7";
case GOLD:
return colorStr + "6";
case RED:
return colorStr + "4";
case GREEN:
return colorStr + "2";
}
// If this code is reachable, then someone has not properly handled the above switch-case
return colorStr;
}
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
/// @fn MakeCopyableTxt /// @fn MakeCopyableTxt
/// ///
@ -139,7 +109,28 @@ public class HelpBuilder {
/// @return Formatted string of colored text /// @return Formatted string of colored text
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
public String ColorMsg(Integer msg, COLOR_CODE color) { public String ColorMsg(Integer msg, COLOR_CODE color) {
return getColor(color) + msg + COLOR_END; return ChatFormatting.GetColor(color) + msg + ChatFormatting.COLOR_END;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn ColorMsg
///
/// @param[in] msg is an Text object
///
/// @param[in] color is the color option
///
/// @brief Creates a formatted string that will be colored at the
/// specification of the developer
///
/// @return Text object but with the minecraft color injected around
/// string
///
/// @note THIS WILL REMOVE FORMATTING ON THE TEXT. If you need to keep
/// formatting/other specialties, format a string with the color
/// first with functions inside this class.
/////////////////////////////////////////////////////////////////////////////
public Text ColorMsg(Text msg, COLOR_CODE color) {
return Text.of(ChatFormatting.GetColor(color) + msg.getString() + ChatFormatting.COLOR_END);
} }
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@ -160,7 +151,7 @@ public class HelpBuilder {
List<String> retList = new ArrayList<String>(); List<String> retList = new ArrayList<String>();
for (String str : msg) { for (String str : msg) {
retList.add(getColor(color) + str + COLOR_END); retList.add(ChatFormatting.GetColor(color) + str + ChatFormatting.COLOR_END);
} }
return retList; return retList;
@ -179,7 +170,7 @@ public class HelpBuilder {
/// @return Formatted string of colored text /// @return Formatted string of colored text
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
public String ColorMsg(String msg, COLOR_CODE color) { public String ColorMsg(String msg, COLOR_CODE color) {
return getColor(color) + msg + COLOR_END; return ChatFormatting.GetColor(color) + msg + ChatFormatting.COLOR_END;
} }
// Parses a help command and color codes it. assume everything up to first '.' is the // Parses a help command and color codes it. assume everything up to first '.' is the
@ -200,7 +191,7 @@ public class HelpBuilder {
/// @return Formatted string of colored text /// @return Formatted string of colored text
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
public String FormatMsg(String helpCmd, COLOR_CODE primaryColor, COLOR_CODE secondaryColor) { public String FormatMsg(String helpCmd, COLOR_CODE primaryColor, COLOR_CODE secondaryColor) {
String coloredStr = getColor(primaryColor); String coloredStr = ChatFormatting.GetColor(primaryColor);
List<String> splitStr = List.of(helpCmd.split("\\.")); List<String> splitStr = List.of(helpCmd.split("\\."));
Boolean isFirst = true; Boolean isFirst = true;
@ -208,12 +199,12 @@ public class HelpBuilder {
if (isFirst) { if (isFirst) {
coloredStr += str; coloredStr += str;
isFirst = false; isFirst = false;
coloredStr += getColor(secondaryColor); coloredStr += ChatFormatting.GetColor(secondaryColor);
} else { } else {
coloredStr += str; coloredStr += str;
} }
} }
return coloredStr + COLOR_END; return coloredStr + ChatFormatting.COLOR_END;
} }
} }

View File

@ -75,10 +75,7 @@ public class AttributeCommands {
public int ApplyAttribute(ServerPlayerEntity targetPlayer, String attributeName, CommandContext<ServerCommandSource> context) { public int ApplyAttribute(ServerPlayerEntity targetPlayer, String attributeName, CommandContext<ServerCommandSource> context) {
int ret = -1; int ret = -1;
System.out.println("Applying attribute");
if (context.getSource().isExecutedByPlayer()) { if (context.getSource().isExecutedByPlayer()) {
System.out.println("Executed by player");
String result = AttributeMgr.ApplyAttribute(targetPlayer.getUuidAsString(), attributeName); String result = AttributeMgr.ApplyAttribute(targetPlayer.getUuidAsString(), attributeName);
Keeblarcraft.LOGGER.info("[ApplyAttribute] -> " + result); Keeblarcraft.LOGGER.info("[ApplyAttribute] -> " + result);
context.getSource().getPlayer().sendMessage(Text.of(result)); context.getSource().getPlayer().sendMessage(Text.of(result));

View File

@ -1,20 +1,24 @@
package jesse.keeblarcraft.Commands; package jesse.keeblarcraft.Commands;
import com.mojang.brigadier.arguments.IntegerArgumentType;
import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.context.CommandContext;
import java.util.List; import java.util.List;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import static java.util.Map.entry; import static java.util.Map.entry;
import jesse.keeblarcraft.BankMgr.BankAccountType;
import jesse.keeblarcraft.BankMgr.BankManager; import jesse.keeblarcraft.BankMgr.BankManager;
import jesse.keeblarcraft.BankMgr.IndividualAccount; import jesse.keeblarcraft.BankMgr.IndividualAccount;
import jesse.keeblarcraft.BankMgr.IndividualBank; import jesse.keeblarcraft.BankMgr.IndividualBank;
import jesse.keeblarcraft.BankMgr.BankAccountType.ACCOUNT_TYPE;
import jesse.keeblarcraft.ChatStuff.ChatFormatting.COLOR_CODE;
import jesse.keeblarcraft.ChatStuff.ChatMsg;
import jesse.keeblarcraft.ConfigMgr.ConfigManager; import jesse.keeblarcraft.ConfigMgr.ConfigManager;
import jesse.keeblarcraft.Utils.HelpBuilder;
import jesse.keeblarcraft.Utils.HelpBuilder.COLOR_CODE;
import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerEntity;
@ -52,7 +56,7 @@ public class BankCommands {
private static String HELPCMD_ADMIN_ACCOUNTS_TRANSACTIONS = "admin-accounts-transactions"; private static String HELPCMD_ADMIN_ACCOUNTS_TRANSACTIONS = "admin-accounts-transactions";
private static String HELPCMD_ADMIN_ACCOUNTS_LOCK = "admin-accounts-lock"; private static String HELPCMD_ADMIN_ACCOUNTS_LOCK = "admin-accounts-lock";
HelpBuilder msgFormatter = new HelpBuilder(); ChatMsg msgFormatter = new ChatMsg();
private static Map<String, String> HELP_COMMANDS = Map.ofEntries( private static Map<String, String> HELP_COMMANDS = Map.ofEntries(
entry entry
@ -196,148 +200,206 @@ public class BankCommands {
/// @brief Registers all bank commands on the server /// @brief Registers all bank commands on the server
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
public void RegisterCommands() { public void RegisterCommands() {
// Bank help
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> { CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
// This is basically a small re-created SQL language but for bank commands. I recommend asking me for the drawn
// image to better understand what this is accomplishing if it is confusing. Essentially it is easy though, as it
// is just /bank ACTION-WORD [arguments...] [optionals]
var bankRoot = CommandManager.literal("bank").build(); var bankRoot = CommandManager.literal("bank").build();
var help = CommandManager.literal("help").build();
var helpTarget = CommandManager.argument("target", StringArgumentType.greedyString())
.executes(context -> HelpCommand(context.getSource().getPlayer(), StringArgumentType.getString(context, "target")))
.build();
var info = CommandManager.literal("info")
.executes(context -> ListBankInfo(context.getSource().getPlayer()))
.build();
bankRoot.addChild(info);
var create = CommandManager.literal("create").build();
var createAccount = CommandManager.literal("account").build();
var checking = CommandManager.literal("checking")
.executes(context -> CreateAccount(context.getSource().getPlayer(), ACCOUNT_TYPE.CHECKING))
.build();
var savings = CommandManager.literal("savings")
.executes(context -> CreateAccount(context.getSource().getPlayer(), ACCOUNT_TYPE.SAVINGS))
.build();
bankRoot.addChild(create);
create.addChild(createAccount);
createAccount.addChild(checking);
createAccount.addChild(savings);
var wireCmd = CommandManager.literal("wire").build();
var accountNum = CommandManager.argument("account", StringArgumentType.string()).build();
var wireAmount = CommandManager.argument("amount", IntegerArgumentType.integer()).build();
var wireReason = CommandManager.argument("reason", StringArgumentType.greedyString())
.executes(context -> WireCommand(
context.getSource().getPlayer(),
IntegerArgumentType.getInteger(context, "amount"),
StringArgumentType.getString(context, "account"),
StringArgumentType.getString(context, "reason")
))
.build();
bankRoot.addChild(wireCmd);
wireCmd.addChild(accountNum);
accountNum.addChild(wireAmount);
wireAmount.addChild(wireReason);
var list = CommandManager.literal("list")
.executes(context -> ListAllBanks(context.getSource().getPlayer()))
.build();
bankRoot.addChild(list);
var selectBankAccount = CommandManager.literal("select-default-account").build();
var selectBankAccountName = CommandManager.argument("global-account-id", StringArgumentType.string())
.executes(context -> SelectDefaultAccount(context.getSource().getPlayer(), StringArgumentType.getString(context, "global-account-id")))
.build();
bankRoot.addChild(selectBankAccount);
selectBankAccount.addChild(selectBankAccountName);
var selectBank = CommandManager.literal("select-bank").build();
var selectBankName = CommandManager.argument("global_bank_name", StringArgumentType.string())
.executes(context -> SelectBank(context.getSource().getPlayer(), StringArgumentType.getString(context, "global_bank_name")))
.build();
bankRoot.addChild(selectBank);
selectBank.addChild(selectBankName);
var close = CommandManager.literal("close").build();
var closeAccountId = CommandManager.argument("account", StringArgumentType.string())
.executes(context -> CloseCommand(context.getSource().getPlayer(), StringArgumentType.getString(context, "account")))
.build();
bankRoot.addChild(close);
close.addChild(closeAccountId);
var moveCmd = CommandManager.literal("move").build();
var moveAmount = CommandManager.argument("move_amount", IntegerArgumentType.integer()).build();
var fromAccount = CommandManager.argument("from_account", StringArgumentType.string()).build();
var toAccount = CommandManager.argument("to_account", StringArgumentType.string())
.executes(context -> MoveCommand(
context.getSource().getPlayer(),
IntegerArgumentType.getInteger(context, "move_amount"),
StringArgumentType.getString(context, "from_account"),
StringArgumentType.getString(context, "to_account")
))
.build();
bankRoot.addChild(moveCmd);
moveCmd.addChild(moveAmount);
moveAmount.addChild(fromAccount);
fromAccount.addChild(toAccount);
var admin = CommandManager.literal("admin").build();
// var accounts = CommandManager.literal("accounts").build();
var subtractMoney = CommandManager.literal("sub-money").build();
var subtractAmount = CommandManager.argument("sub_amount", IntegerArgumentType.integer()).build();
var subtractAccount = CommandManager.argument("sub_account", StringArgumentType.string()).build();
var subtractReason = CommandManager.argument("sub_reason", StringArgumentType.greedyString())
.executes(context -> AdminSubtractMoney(
context.getSource().getPlayer(),
IntegerArgumentType.getInteger(context, "sub_amount"),
StringArgumentType.getString(context, "sub_account"),
StringArgumentType.getString(context, "sub_reason")
))
.build();
var addMoney = CommandManager.literal("add-money").build();
var addAmount = CommandManager.argument("add_amount", IntegerArgumentType.integer()).build();
var addAccount = CommandManager.argument("add_account", StringArgumentType.string()).build();
var addReason = CommandManager.argument("add_reason", StringArgumentType.greedyString())
.executes(context -> AdminAddMoney(
context.getSource().getPlayer(),
IntegerArgumentType.getInteger(context, "add_amount"),
StringArgumentType.getString(context, "add_account"),
StringArgumentType.getString(context, "add_reason")
))
.build();
var setMoney = CommandManager.literal("set-bal").build();
var setAmnt = CommandManager.argument("set_amount", IntegerArgumentType.integer()).build();
var setAccount = CommandManager.argument("set_account", StringArgumentType.string()).build();
var setReason = CommandManager.argument("set_reason", StringArgumentType.greedyString())
.executes(context -> AdminSetMoney(
context.getSource().getPlayer(),
IntegerArgumentType.getInteger(context, "set_amount"),
StringArgumentType.getString(context, "set_account"),
StringArgumentType.getString(context, "set_reason")
))
.build();
var getBal = CommandManager.literal("get-bal").build();
var getBalTgt = CommandManager.argument("get_bal_target", StringArgumentType.string()).build();
var createBank = CommandManager.literal("create-bank").build();
var createBankName = CommandManager.argument("create_bank_name", StringArgumentType.string()).build();
var closeBank = CommandManager.literal("close-bank").build();
var closeBankName = CommandManager.argument("close_bank_name", StringArgumentType.string()).build();
var setServerBal = CommandManager.literal("set-server-bal").build();
var setServerBalAmnt = CommandManager.argument("set_server_bal_amount", StringArgumentType.string()).build();
var setServerAllowance = CommandManager.literal("set-server-allowance").build();
var setServerAllowanceAmount = CommandManager.argument("set_server_allowance", IntegerArgumentType.integer()).build();
bankRoot.addChild(admin);
admin.addChild(subtractMoney);
subtractMoney.addChild(subtractAmount);
subtractAmount.addChild(subtractAccount);
subtractAccount.addChild(subtractReason);
admin.addChild(addMoney);
addMoney.addChild(addAmount);
addAmount.addChild(addAccount);
addAccount.addChild(addReason);
admin.addChild(setMoney);
setMoney.addChild(setAmnt);
setAmnt.addChild(setAccount);
setAccount.addChild(setReason);
admin.addChild(getBal);
getBal.addChild(getBalTgt);
admin.addChild(createBank);
createBank.addChild(createBankName);
admin.addChild(closeBank);
admin.addChild(closeBankName);
admin.addChild(setServerBal);
setServerBal.addChild(setServerBalAmnt);
admin.addChild(setServerAllowance);
setServerAllowance.addChild(setServerAllowanceAmount);
// Removing "argList" and just running the entire list as an argList from actionWord makes `/bank help` possible
var argList = CommandManager.argument("ARG_LIST", StringArgumentType.greedyString())
.executes(context -> ParseBankCommand
(
context,
StringArgumentType.getString(context, "ARG_LIST"))
)
.build();
// Building the argument tree here // Building the argument tree here
dispatcher.getRoot().addChild(bankRoot); dispatcher.getRoot().addChild(bankRoot);
bankRoot.addChild(argList); bankRoot.addChild(help);
help.addChild(helpTarget);
}); });
} }
///////////////////////////////////////////////////////////////////////////// public int SelectBank(ServerPlayerEntity player, String bank) {
/// @fn RemoveFillerWords System.out.println("Select bank called");
/// BankManager.GetInstance().ChangeDefaultSelectedBank(player, bank);
/// @brief Takes in a list of arguments with the intention to remove
/// all words found in the filler list. This helps with dynamic
/// typing
///
/// @return List of arguments without filler words
/////////////////////////////////////////////////////////////////////////////
public List<String> RemoveFillerWords(List<String> argList) {
int index = 0;
for (String str : argList) {
if (FILLER_WORDS.contains(str)) {
argList.remove(index);
}
// Also make every word lower case
str = str.toLowerCase();
index++;
}
return argList;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn ParseBankCommand
///
/// @brief Parses the global bank command
/////////////////////////////////////////////////////////////////////////////
public int ParseBankCommand(CommandContext<ServerCommandSource> context, String unformattedArgList) {
List<String> formattedArgList = List.of(unformattedArgList.split("\\s+")); // REGEX is matching 1+ whitespace characters
System.out.println("After formatting the arg list, the size of arg list is size { " + formattedArgList.size() + " }");
formattedArgList = RemoveFillerWords(formattedArgList);
String actionWord = formattedArgList.get(0);
System.out.println("The action word for this operation is " + actionWord.toUpperCase());
System.out.println("Parsing bank command on action word { " + actionWord + " } with arg list { " + formattedArgList + " }");
switch(actionWord)
{
case "create":
System.out.println("Calling create command...");
CreateCommand(context.getSource().getPlayer(), formattedArgList.subList(1, formattedArgList.size()));
break;
case "close":
CloseCommand(context.getSource().getPlayer(), formattedArgList);
break;
case "select":
SelectCommand(context.getSource().getPlayer(), formattedArgList.subList(1, formattedArgList.size()));
break;
case "wire":
WireCommand(context.getSource().getPlayer(), formattedArgList.subList(1, formattedArgList.size()));
break;
case "balance":
BalanceCommand(context.getSource().getPlayer(), formattedArgList);
break;
case "help":
HelpCommand(context.getSource().getPlayer(), formattedArgList);
break;
case "move":
MoveCommand(context.getSource().getPlayer(), formattedArgList);
break;
case "alias":
AliasCommand(context.getSource().getPlayer(), formattedArgList);
break;
case "report":
ReportCommand(context.getSource().getPlayer(), formattedArgList);
break;
case "examples":
HelpCommand(context.getSource().getPlayer(), List.of(HELPCMD_EXAMPLES));
break;
case "syntax":
HelpCommand(context.getSource().getPlayer(), List.of(HELPCMD_SYNTAX));
break;
case "list":
ListAllBanks(context.getSource().getPlayer(), formattedArgList);
break;
case "account":
case "accounts":
ManageAccounts(context.getSource().getPlayer(), formattedArgList.subList(1, formattedArgList.size()));
break;
case "admin":
AdminCommand(context.getSource().getPlayer(), formattedArgList.subList(1, formattedArgList.size()));
break;
default:
if (context.getSource().isExecutedByPlayer()) {
context.getSource().getPlayer().sendMessage(Text.of("You have entered an improperly formatted message. Please reference the bank manual if you are confused how to form a command!"));
}
break;
}
return 0; return 0;
} }
/////////////////////////////////////////////////////////////////////////////
/// @fn ParseToInteger
///
/// @param[in] player is the player to send message to on failure
///
/// @param[in] possibleInt is string to be parsed
///
/// @param[in] helpCmd is help command to send player on failure to parse
///
/// @brief Helper is designed to parse a string to a number (helpful in
/// banking) and upon a failure of parse send a designated help
/// message for that command (this system is non-trivial to use)
///
/// @return The parsed integer if successful parse. If false, the server
/// should catch and a help command is sent
/////////////////////////////////////////////////////////////////////////////
public Integer ParseToInteger(ServerPlayerEntity player, String possibleInt, String helpCmd) {
Integer amount = 0;
try {
amount = Integer.parseInt(possibleInt);
} catch (NumberFormatException exception) {
HelpCommand(player, List.of(helpCmd));
}
System.out.println("ParseToInteger was called. The input was " + possibleInt + " and the parsed int is " + amount);
return amount;
}
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
/// @fn IsOperator /// @fn IsOperator
/// ///
@ -355,166 +417,19 @@ public class BankCommands {
} }
} }
// Possible code paths ({}=required, []=optionals, ()=explanation): public int AdminSubtractMoney(ServerPlayerEntity player, Integer amount, String account, String reason) {
// REQUIRED (path) = {SetBal|AddMoney|SubMoney} {LONG_ID|BANK_ID} {amount} (Depending on context, changes balance somehow from an account ID or bank) AdminBalanceChange(player, account, amount, "subtract", reason);
// REQUIRED (path) = {GetBal} {LONG_ID:BANK_ID} (Gets the balance of a bank account or bank) return 0;
// REQUIRED (path) = {accounts} {list} {PLAYER_NAME} (Returns summarized account information on a player) }
// REQUIRED (path) = {accounts} {move} {LONG_ID} to {BANK_ID} (Will move account to diff bank. May generate new account ID)
// REQUIRED (path) = {accounts} {force-close} {LOND_ID} (Forces an account to be closed. Money is returned to server bank account)
// REQUIRED (path) = {accounts} {add} to {PLAYER_NAME} [BANK_ID] (Adds an account to a player to server by default. Specify other for other)
// REQUIRED (path) = {accounts} {transactions} from {LONG_ID} (Gets transaction report from an account by ID)
// REQUIRED (path) = {accounts} {lock} {LONG_ID:USER} (Locks a specific bank account OR all bank accounts owned by $USER)
// REQUIRED (path) = {create-bank} {BANK_ID} (Create a new bank. Default is owned by server)
// REQUIRED (path) = {close-bank} {BANK_ID} (Closing a bank forces a close on all accounts. Banks money is returned to server bank)
// REQUIRED (path) = {lock-bank} {BANK_ID} (Freezes all activities through a bank)
// REQUIRED (path) = {unlock} {BANK_ID:ACCOUNT_ID:USER} (will unlock a bank, account, or all of a users accounts)
// REQUIRED (path) = {wire} {amount} from {ACCOUNT_ID} to {ACCOUNT_ID} (Forces a wire from one account to another. Overrides overdraft setting since it's administrative)
// REQUIRED (path) = {get-server-allowance} (Returns the rate of which the server adds money to itself magically & how much)
// REQUIRED (path) = {set-server-allowance} {amount} {interval} (Sets the magic allowance rate of server & period in which it does it to add money magically to server bank)
/////////////////////////////////////////////////////////////////////////////
/// @fn AdminCommand
///
/// @param[in] sourcePlayer is player running command
///
/// @param[in] argList is the argument list to be parsed
///
/// @brief Code paths should be read in above comment. Primary admin list
/// of commands that are possible to run
/////////////////////////////////////////////////////////////////////////////
public void AdminCommand(ServerPlayerEntity sourcePlayer, List<String> argList) {
// The player must be opped & the size must be at LEAST 2 (1 keyword + extra for sublist)
String pName = sourcePlayer.getDisplayName().toString();
System.out.println("Is player admin? " + (IsOperator(sourcePlayer) ? "YES" : "NO"));
if (IsOperator(sourcePlayer) && argList.size() >= 1) {
String arg = argList.get(0);
List<String> remainingArgs = argList.subList(1, argList.size());
switch (arg) {
case "account":
case "accounts":
break;
case "submoney":
case "subtract-money":
case "subtractmoney":
case "sub-money":
// Require account identifier + balance
if (remainingArgs.size() >= 2) {
String accountId = remainingArgs.get(0);
Integer amount = ParseToInteger(sourcePlayer, remainingArgs.get(1), HELPCMD_ADMIN_BALANCE_CHANGE);
String optionalReason = "";
if (remainingArgs.size() >= 3) {
optionalReason = remainingArgs.get(2);
}
AdminBalanceChange(sourcePlayer, accountId, amount, "subtract", optionalReason); public int AdminAddMoney(ServerPlayerEntity player, Integer amount, String account, String reason) {
} else { AdminBalanceChange(player, account, amount, "add", reason);
HelpCommand(sourcePlayer, List.of(HELPCMD_ADMIN_BALANCE_CHANGE)); return 0;
} }
break;
case "addmoney":
case "add-money":
// Require account identifier + balance
if (remainingArgs.size() >= 2) {
String accountId = remainingArgs.get(0);
Integer amount = ParseToInteger(sourcePlayer, remainingArgs.get(1), HELPCMD_ADMIN_BALANCE_CHANGE);
String optionalReason = "";
if (remainingArgs.size() >= 3) {
optionalReason = remainingArgs.get(2);
}
AdminBalanceChange(sourcePlayer, accountId, amount, "add", optionalReason); public int AdminSetMoney(ServerPlayerEntity player, Integer amount, String account, String reason) {
} else { AdminBalanceChange(player, account, amount, "set", reason);
HelpCommand(sourcePlayer, List.of(HELPCMD_ADMIN_BALANCE_CHANGE)); return 0;
}
break;
case "setbal":
case "set-bal":
case "setbalance":
case "set-balance":
// Require account identifier + balance
if (remainingArgs.size() >= 2) {
String accountId = remainingArgs.get(0);
Integer amount = ParseToInteger(sourcePlayer, remainingArgs.get(1), HELPCMD_ADMIN_BALANCE_CHANGE);
String optionalReason = "";
if (remainingArgs.size() >= 3) {
optionalReason = remainingArgs.get(2);
}
System.out.println("Running set-balance with amount " + amount);
if (amount != 0) {
AdminBalanceChange(sourcePlayer, accountId, amount, "set", optionalReason);
} else {
HelpCommand(sourcePlayer, List.of(HELPCMD_ADMIN_BALANCE_CHANGE));
}
} else {
HelpCommand(sourcePlayer, List.of(HELPCMD_ADMIN_BALANCE_CHANGE));
}
break;
case "getbal":
case "get-bal":
case "getbalance":
case "get-balance":
// Require account identifier
if (remainingArgs.size() >= 1) {
} else {
HelpCommand(sourcePlayer, List.of(HELPCMD_ADMIN_BALANCE_GET));
}
break;
case "createbank":
case "create-bank":
if (remainingArgs.size() >= 1) {
} else {
HelpCommand(sourcePlayer, List.of(HELPCMD_ADMIN_CREATE_BANK));
}
break;
case "closebank":
case "close-bank":
if (remainingArgs.size() >= 1) {
} else {
HelpCommand(sourcePlayer, List.of(HELPCMD_ADMIN_CLOSE_BANK));
}
break;
case "forcewire":
case "force-wire":
case "wiremoney":
case "wire-money":
case "wire":
if (remainingArgs.size() >= 3) {
} else {
HelpCommand(sourcePlayer, List.of(HELPCMD_ADMIN_FORCE_WIRE));
}
break;
case "lock-bank":
case "lockbank":
if (remainingArgs.size() >= 1) {
} else {
HelpCommand(sourcePlayer, List.of(HELPCMD_ADMIN_LOCK_BANK));
}
break;
case "get-server-allowance":
case "getserverallowance":
sourcePlayer.sendMessage(Text.of(GetServerAllowance()));
break;
case "setserverallowance":
case "set-server-allowance":
if (remainingArgs.size() >= 1) {
} else {
HelpCommand(sourcePlayer, List.of(HELPCMD_SET_SERVER_ALLOWANCE));
}
break;
default:
HelpCommand(sourcePlayer, List.of(HELPCMD_ADMIN_COMMANDS_LIST));
break;
}
} else {
sourcePlayer.sendMessage(Text.of("Only admins can use this command!"));
}
} }
public String GetServerAllowance() { public String GetServerAllowance() {
@ -538,7 +453,6 @@ public class BankCommands {
/// amount /// amount
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
public void AdminBalanceChange(ServerPlayerEntity player, String accountId, Integer amount, String type, String optionalReason) { public void AdminBalanceChange(ServerPlayerEntity player, String accountId, Integer amount, String type, String optionalReason) {
System.out.println("AdminChangeFunds on account " + accountId);
BankManager.GetInstance().AdminChangeFunds(player, accountId, amount, type, optionalReason); BankManager.GetInstance().AdminChangeFunds(player, accountId, amount, type, optionalReason);
} }
@ -582,49 +496,43 @@ public class BankCommands {
/// ///
/// @brief Change the balance of a designated account /// @brief Change the balance of a designated account
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
public void ManageAccounts(ServerPlayerEntity sourcePlayer, List<String> argList) { public int ListBankInfo(ServerPlayerEntity sourcePlayer) {
System.out.println("Manage accounts arg list is { " + argList + " }"); String bankName = BankManager.GetInstance().GetPlayerSelectedBank(sourcePlayer.getUuidAsString());
if (argList.size() > 0) { IndividualBank bank = BankManager.GetInstance().GetBankByName(bankName);
// TODO: For now we assume they reference the bank name and not routing #
String bankName = argList.get(0).toUpperCase();
IndividualBank bank = BankManager.GetInstance().GetBankByName(bankName);
System.out.println("Test print on memory");
Boolean isNull = bank == null;
System.out.println("isNull: " + isNull);
if (bank != null) { if (bank != null) {
System.out.println("Grabbing user account information"); System.out.println("Grabbing user account information");
List<IndividualAccount> userAccounts = bank.GetAccountsOfUser(sourcePlayer.getUuidAsString()); List<IndividualAccount> userAccounts = bank.GetAccountsOfUser(sourcePlayer.getUuidAsString());
sourcePlayer.sendMessage(Text.of("[BANK INFO FOR " + bankName.toUpperCase() + "]")); sourcePlayer.sendMessage(Text.of("[BANK INFO FOR " + bankName.toUpperCase() + "]"));
System.out.println("userAccounts size: " + userAccounts.size()); System.out.println("userAccounts size: " + userAccounts.size());
for (int i = 0; i < userAccounts.size(); i++) { for (int i = 0; i < userAccounts.size(); i++) {
String accountNumber = userAccounts.get(i).GetAccountNumber(); String accountNumber = userAccounts.get(i).GetAccountNumber();
String globalAccountNumber = userAccounts.get(i).GetGlobalAccountNumber(); String globalAccountNumber = userAccounts.get(i).GetGlobalAccountNumber();
List<String> accountHolders = userAccounts.get(i).GetAccountHolders(); List<String> accountHolders = userAccounts.get(i).GetAccountHolders();
Integer accountBalance = userAccounts.get(i).GetAccountBalance(); Integer accountBalance = userAccounts.get(i).GetAccountBalance();
String l1 = "ACCOUNT NUMBER: " + msgFormatter.ColorMsg(accountNumber, COLOR_CODE.BLUE); String l1 = "ACCOUNT NUMBER: " + msgFormatter.ColorMsg(accountNumber, COLOR_CODE.BLUE);
String l2 = "GLOBAL ACCOUNT NUMBER: " + msgFormatter.ColorMsg(globalAccountNumber, COLOR_CODE.BLUE); String l2 = "GLOBAL ACCOUNT NUMBER: " + msgFormatter.ColorMsg(globalAccountNumber, COLOR_CODE.BLUE);
String l3 = "HOLDERS: " + msgFormatter.ColorMsg(accountHolders, COLOR_CODE.GRAY); String l3 = "HOLDERS: " + msgFormatter.ColorMsg(accountHolders, COLOR_CODE.GRAY);
String l4 = "BALANCE: " + msgFormatter.ColorMsg(accountBalance, COLOR_CODE.GREEN); String l4 = "BALANCE: " + msgFormatter.ColorMsg(accountBalance, COLOR_CODE.GREEN);
sourcePlayer.sendMessage((Text) msgFormatter.MakeCopyableTxt(l1, "Click to copy", accountNumber)); sourcePlayer.sendMessage((Text) msgFormatter.MakeCopyableTxt(l1, "Click to copy", accountNumber));
sourcePlayer.sendMessage((Text) msgFormatter.MakeCopyableTxt(l2, "Click to copy", globalAccountNumber)); sourcePlayer.sendMessage((Text) msgFormatter.MakeCopyableTxt(l2, "Click to copy", globalAccountNumber));
sourcePlayer.sendMessage((Text) msgFormatter.MakeCopyableTxt(l3, "Click to copy", accountHolders)); sourcePlayer.sendMessage((Text) msgFormatter.MakeCopyableTxt(l3, "Click to copy", accountHolders));
sourcePlayer.sendMessage((Text) msgFormatter.MakeCopyableTxt(l4, "Click to copy", accountBalance)); sourcePlayer.sendMessage((Text) msgFormatter.MakeCopyableTxt(l4, "Click to copy", accountBalance));
sourcePlayer.sendMessage(Text.of("\n")); sourcePlayer.sendMessage(Text.of("\n"));
}
} else {
sourcePlayer.sendMessage(Text.of(msgFormatter.ColorMsg("That bank does not exist", COLOR_CODE.RED)));
} }
} else { } else {
sourcePlayer.sendMessage(Text.of("Unrecognized move command. Please use \"/bank help ACCOUNTS\" for more information.")); sourcePlayer.sendMessage(Text.of(msgFormatter.ColorMsg("That bank does not exist", COLOR_CODE.RED)));
} }
return 0;
} }
public void ListAllBanks(ServerPlayerEntity sourcePlayer, List<String> argList) { // TODO: make prettier
public int ListAllBanks(ServerPlayerEntity sourcePlayer) {
sourcePlayer.sendMessage(Text.of("Here is a list of available banks on the server: " + BankManager.GetInstance().GetAllBankNames())); sourcePlayer.sendMessage(Text.of("Here is a list of available banks on the server: " + BankManager.GetInstance().GetAllBankNames()));
return 0;
} }
// Possible code paths: // Possible code paths:
@ -640,39 +548,8 @@ public class BankCommands {
/// ///
/// @brief Command to move account. Read above comment for code paths /// @brief Command to move account. Read above comment for code paths
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
public void MoveCommand(ServerPlayerEntity sourcePlayer, List<String> argList) { public int MoveCommand(ServerPlayerEntity sourcePlayer, Integer amount, String fromAccount, String toAccount) {
if (argList.size() >= 2) { return 0;
String possibleExternalIdentifier = argList.get(1);
boolean isExternalTransfer = false;
/*
* CALL TO BANKMGR TO VERIFY IF ABOVE IS VALID BANK ID. IF NOT; THIS IS INTERNAL TRANSFER
*/
if (isExternalTransfer) {
// External move to another bank or faction
String targetMoveAccount = argList.get(0);
String destBankId = argList.get(1);
/*
* CALL TO BANKMGR TO MOVE ACCOUNTS HERE
*/
} else {
// Internal transfer to this players accounts within system
String optionalFromAccount = ""; /* CALL TO BANKMGR TO GET DEFAULT SELECTED ACCOUNT FOR `FROM` FIELD */
if (argList.size() == 3) {
optionalFromAccount = argList.get(1);
}
String transferAmount = argList.get(0);
String destinationTransfer = argList.get(2);
/*
* BANK MGR CALL HERE
*/
}
} else {
sourcePlayer.sendMessage(Text.of("Unrecognized move command. Please use \"/bank help MOVE\" for more information."));
}
} }
// Posible code paths: // Posible code paths:
@ -713,14 +590,14 @@ public class BankCommands {
/// @brief Shorthand function call-through to CreateCommand for generating /// @brief Shorthand function call-through to CreateCommand for generating
/// an account(s) report. /// an account(s) report.
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
public void ReportCommand(ServerPlayerEntity sourcePlayer, List<String> argList) { // public void ReportCommand(ServerPlayerEntity sourcePlayer, List<String> argList) {
if (argList.size() > 0) { // if (argList.size() > 0) {
argList.add(0, "report"); // Since we lose 'report' when we pass it as an alias/passthrough; we just shim it into the first spot // argList.add(0, "report"); // Since we lose 'report' when we pass it as an alias/passthrough; we just shim it into the first spot
CreateCommand(sourcePlayer, argList); // CreateCommand(sourcePlayer, argList);
} else { // } else {
sourcePlayer.sendMessage(Text.of("Unrecognized report command. Please run \"/bank help REPORT\" for more information.")); // sourcePlayer.sendMessage(Text.of("Unrecognized report command. Please run \"/bank help REPORT\" for more information."));
} // }
} // }
// Possible code paths: // Possible code paths:
// REQUIRED = {} // REQUIRED = {}
@ -746,88 +623,29 @@ public class BankCommands {
return 0; return 0;
} }
// Create command - valid arg list types:
// /... CREATE {CA/checking/savings/checking-account/savings-account/report}
/////////////////////////////////////////////////////////////////////////////
/// @fn CreateCommand
///
/// @param[in] player is player who ran command
///
/// @param[in] argList is the argument list to be parsed
///
/// @brief Create a bank account or create report on account
/////////////////////////////////////////////////////////////////////////////
public int CreateCommand(ServerPlayerEntity sourcePlayer, List<String> argList) {
System.out.println("Attempting account creation given arg list { " + argList + " }.");
System.out.println("argList size is " + argList.size());
if (argList.size() > 0) {
String action = argList.get(0).toLowerCase();
System.out.println("action word is " + action);
switch (action) {
// Checking & Savings are handled in the same function so we can just "alias" all of these to the same call!
case "ca":
case "checking":
case "checking-account":
case "sa":
case "savings":
case "savings-account":
System.out.println("Creating account. Removing index 0 in argList. New argList is { " + argList + " }");
CreateAccount(sourcePlayer, argList);
break;
case "rep":
case "report":
GenerateAccountReport(sourcePlayer, argList);
break;
default:
// Unrecognized creation type
}
} else {
sourcePlayer.sendMessage(Text.of("Unrecognized create command formed on bank. Please run \"/bank help CREATE\" for more information"));
}
return 0;
}
// Possible code paths: // Possible code paths:
// REQUIRED = {ACCOUNT ID|ALIAS} // REQUIRED = {ACCOUNT ID|ALIAS}
// OPTIONAL = [] // OPTIONAL = []
public int CloseCommand(ServerPlayerEntity sourcePlayer, List<String> argList) { public int CloseCommand(ServerPlayerEntity sourcePlayer, String account) {
if (argList.size() > 0) { // if (argList.size() > 0) {
String accountToClose = argList.get(0); // String accountToClose = argList.get(0);
/* // /*
* CALL TO BANKMGR TO DO STUFF // * CALL TO BANKMGR TO DO STUFF
*/ // */
} else { // } else {
sourcePlayer.sendMessage(Text.of("Unrecognized close command. Please see \"/bank help CLOSE\" for more information.")); // sourcePlayer.sendMessage(Text.of("Unrecognized close command. Please see \"/bank help CLOSE\" for more information."));
} // }
return 0; return 0;
} }
// Possible code paths: // Possible code paths:
// required = {account id | alias} // required = {account id | alias}
// optional = [default|secondary|backup] // optional = [default|secondary|backup]
public int SelectCommand(ServerPlayerEntity sourcePlayer, List<String> argList) { public int SelectDefaultAccount(ServerPlayerEntity sourcePlayer, String account) {
if (argList.size() > 0) { BankManager.GetInstance().ChangeDefaultPlayerAccount(sourcePlayer, account);
String requiredArg = argList.get(0);
// If the optional args exist; fetch them
String optionalArg = "";
if (argList.size() == 2) {
optionalArg = argList.get(1);
}
BankManager.GetInstance().ChangeDefaultPlayerAccount(sourcePlayer, requiredArg);
} else {
sourcePlayer.sendMessage(Text.of("Unrecognized select command. Please run /bank help select for more information."));
}
return 0; return 0;
} }
// Possible code paths:
// REQUIRED = {AMOUNT} {ACCOUNT_ID} [optional]
// OPTIONAL = [reason]
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
/// @fn WireCommand /// @fn WireCommand
/// ///
@ -837,22 +655,8 @@ public class BankCommands {
/// ///
/// @brief Create wire on bank account /// @brief Create wire on bank account
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
public int WireCommand(ServerPlayerEntity sourcePlayer, List<String> argList) { public int WireCommand(ServerPlayerEntity sourcePlayer, Integer amount, String destAccount, String reason) {
System.out.println("WireCommand called with arg size " + argList.size()); BankManager.GetInstance().InitiateBankFundsTransfer(sourcePlayer, destAccount, amount, reason);
if (argList.size() >= 2) {
Integer amountToWire = ParseToInteger(sourcePlayer, argList.get(0), HELPCMD_WIRE);
String destAccount = argList.get(1);
String optionalReason = "";
if (argList.size() >= 3) {
optionalReason = argList.get(3);
}
System.out.println("optional reason: " + optionalReason);
BankManager.GetInstance().InitiateBankFundsTransfer(sourcePlayer, destAccount, amountToWire);
} else {
sourcePlayer.sendMessage(Text.of("Unrecognized wire command. Please run /bank help wire for more information."));
}
return 0; return 0;
} }
@ -869,8 +673,10 @@ public class BankCommands {
/// @brief Builds a dynamic help list to the player to see all command /// @brief Builds a dynamic help list to the player to see all command
/// options on the server /// options on the server
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
public int HelpCommand(ServerPlayerEntity sourcePlayer, List<String> helpCommand) { public int HelpCommand(ServerPlayerEntity sourcePlayer, String helpCommandList) {
System.out.println("Running help command"); System.out.println("Running help command");
List<String> helpCommand = new ArrayList<String>(Arrays.asList(helpCommandList.split(" ")));
if (helpCommand.size() == 0) { if (helpCommand.size() == 0) {
// General help command // General help command
for (Entry<String, String> helpCmd : HELP_COMMANDS.entrySet()) { for (Entry<String, String> helpCmd : HELP_COMMANDS.entrySet()) {
@ -917,23 +723,14 @@ public class BankCommands {
/// ///
/// @brief Creates a bank account /// @brief Creates a bank account
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
public void CreateAccount(ServerPlayerEntity player, List<String> accountArgs) { public int CreateAccount(ServerPlayerEntity player, ACCOUNT_TYPE accountType) {
System.out.println("Attempting to create checking account with arg list { " + accountArgs + " }"); String bank = BankManager.GetInstance().GetPlayerSelectedBank(player.getUuidAsString());
if (accountArgs.size() > 0) { System.out.println("Received bank: " + bank);
String accountType = accountArgs.get(0);
String accountAlias = "NO_ALIAS";
// Set the optional account alias for ease-of-reference if (bank != "") {
if (accountArgs.size() >= 2) { BankManager.GetInstance().InitiateBankAccountCreation(bank, player, accountType);
accountAlias = accountArgs.get(1).toLowerCase();
}
System.out.println("ACCOUNT CREATION REQUESTED WITH TYPE " + accountType + " AND ALIAS " + accountAlias);
// FIXME: This is just a patch at the moment to let players make bank accounts in server bank
BankManager.GetInstance().InitiateBankAccountCreation(null, player, accountType);
} else {
player.sendMessage(Text.of("Unrecognized create account command. Please run /bank help create for more information"));
} }
return 0;
} }
// Possible code paths for /bank create report // Possible code paths for /bank create report

View File

@ -8,8 +8,8 @@
package jesse.keeblarcraft.Commands; package jesse.keeblarcraft.Commands;
import jesse.keeblarcraft.Utils.ChatUtil; import jesse.keeblarcraft.Keeblarcraft;
import jesse.keeblarcraft.Utils.ChatUtil.CONSOLE_COLOR; import jesse.keeblarcraft.ChatStuff.ChatMsg;
public class CustomCommandManager { public class CustomCommandManager {
// Intentionally empty constructor since at object definition time it may not be possible to register commands // Intentionally empty constructor since at object definition time it may not be possible to register commands
@ -24,14 +24,16 @@ public class CustomCommandManager {
AttributeCommands attributeCommands = new AttributeCommands(); AttributeCommands attributeCommands = new AttributeCommands();
FactionCommands factionCommands = new FactionCommands(); FactionCommands factionCommands = new FactionCommands();
MiscCommands miscCommands = new MiscCommands(); MiscCommands miscCommands = new MiscCommands();
MailCommands mailCommands = new MailCommands();
// REGISTER COMMANDS BELOW // REGISTER COMMANDS BELOW
System.out.println(ChatUtil.ColoredString("REGISTERING CUSTOM COMMAND EXTENSIONS BELOW", CONSOLE_COLOR.BLUE)); Keeblarcraft.LOGGER.info("Registering mod commands");
shortcuts.RegisterShortcutCommands(); shortcuts.RegisterShortcutCommands();
noteCommands.RegisterNoteCommands(); noteCommands.RegisterNoteCommands();
bankCommands.RegisterCommands(); bankCommands.RegisterCommands();
attributeCommands.RegisterCommands(); attributeCommands.RegisterCommands();
factionCommands.RegisterFactionCommands(); factionCommands.RegisterFactionCommands();
miscCommands.RegisterCommands(); miscCommands.RegisterCommands();
mailCommands.RegisterMailCommands();
} }
} }

View File

@ -2,15 +2,19 @@ package jesse.keeblarcraft.Commands;
import java.util.List; import java.util.List;
import com.mojang.brigadier.arguments.IntegerArgumentType;
import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.context.CommandContext;
import jesse.keeblarcraft.FactionMgr.FactionManager; import jesse.keeblarcraft.FactionMgr.FactionManager;
import jesse.keeblarcraft.FactionMgr.Callbacks.PlayerCommandFlightCallback;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.minecraft.command.argument.EntityArgumentType;
import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.ActionResult;
public class FactionCommands { public class FactionCommands {
@ -27,6 +31,13 @@ public class FactionCommands {
var disbandFaction = CommandManager.literal("disband").build(); var disbandFaction = CommandManager.literal("disband").build();
var promote = CommandManager.literal("promote").build(); var promote = CommandManager.literal("promote").build();
var demote = CommandManager.literal("demote").build(); var demote = CommandManager.literal("demote").build();
var kick = CommandManager.literal("kick").build();
var info = CommandManager.literal("info")
.executes(context -> GetFactionInformation(context.getSource().getPlayer()))
.build();
var invite = CommandManager.literal("invite").build();
var fly = CommandManager.literal("fly")
.executes(context -> ForwardFlightCallback(context)).build();
// The below nodes are duplicates but are necessary to make the execute path jump correctly // The below nodes are duplicates but are necessary to make the execute path jump correctly
var createFactionName = CommandManager.argument("faction_name", StringArgumentType.greedyString()) var createFactionName = CommandManager.argument("faction_name", StringArgumentType.greedyString())
@ -45,10 +56,22 @@ public class FactionCommands {
) )
).build(); ).build();
var promoteName = CommandManager.argument("target_name", EntityArgumentType.player())
.executes(context -> PromotePlayerInFaction(context, EntityArgumentType.getPlayer(context, "target_name")))
.build();
var demoteName = CommandManager.argument("target_name", EntityArgumentType.player())
.executes(context -> DemotePlayerInFaction(context, EntityArgumentType.getPlayer(context, "target_name")))
.build();
var kickName = CommandManager.argument("target_name", EntityArgumentType.player())
.executes(context -> KickPlayerFromFaction(context, EntityArgumentType.getPlayer(context, "target_name")))
.build();
var inviteName = CommandManager.argument("target_name", EntityArgumentType.player())
.executes(context -> InvitePlayerToFaction(context, EntityArgumentType.getPlayer(context, "target_name")))
.build();
var leaveFaction = CommandManager.literal("leave").executes(context -> LeaveFaction(context) var leaveFaction = CommandManager.literal("leave").executes(context -> LeaveFaction(context)
).build(); ).build();
var listAll = CommandManager.literal("list") var listAll = CommandManager.literal("list")
.executes(context -> ListAllFactions(context.getSource().getPlayer())).build(); .executes(context -> ListAllFactions(context.getSource().getPlayer())).build();
@ -61,10 +84,60 @@ public class FactionCommands {
factionNode.addChild(createFaction); factionNode.addChild(createFaction);
factionNode.addChild(disbandFaction); factionNode.addChild(disbandFaction);
factionNode.addChild(leaveFaction); factionNode.addChild(leaveFaction);
factionNode.addChild(promote);
factionNode.addChild(demote);
factionNode.addChild(kick);
factionNode.addChild(info);
factionNode.addChild(invite);
factionNode.addChild(fly);
promote.addChild(promoteName);
demote.addChild(demoteName);
kick.addChild(kickName);
invite.addChild(inviteName);
createFaction.addChild(createFactionName); createFaction.addChild(createFactionName);
disbandFaction.addChild(disbandFactionName); disbandFaction.addChild(disbandFactionName);
}); });
// I'll refactor the above one later! LOL
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
var factionNode = CommandManager.literal("faction").build();
var powerNode = CommandManager.literal("power")
.executes(context -> GetFactionPower(context.getSource().getPlayer()))
.build();
var setNode = CommandManager.literal("set").build();
var factionNameNode = CommandManager.argument("faction_name", StringArgumentType.string()).build();
var powerAmountNode = CommandManager.argument("power_amount", IntegerArgumentType.integer())
.executes(context -> SetFactionPower(context.getSource().getPlayer(), StringArgumentType.getString(context, "faction_name"), IntegerArgumentType.getInteger(context, "power_amount")))
.build();
dispatcher.getRoot().addChild(factionNode);
factionNode.addChild(powerNode);
powerNode.addChild(setNode);
setNode.addChild(factionNameNode);
setNode.addChild(powerAmountNode);
});
}
private int ForwardFlightCallback(CommandContext<ServerCommandSource> context) {
if (context.getSource().isExecutedByPlayer()) {
ActionResult result = PlayerCommandFlightCallback.EVENT.invoker().interact(context.getSource().getPlayer(), context.getSource().getWorld());
}
return 0;
}
public int SetFactionPower(ServerPlayerEntity caller, String faction, Integer amount) {
FactionManager.GetInstance().SetFactionPower(caller, faction, amount);
return 0;
}
public int GetFactionPower(ServerPlayerEntity player) {
FactionManager.GetInstance().GetFactionPower(player);
return 0;
} }
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@ -109,10 +182,9 @@ public class FactionCommands {
return retValue; return retValue;
} }
private int AddPlayerToFaction() { private int InvitePlayerToFaction(CommandContext<ServerCommandSource> context, ServerPlayerEntity player) {
int retValue = -1; FactionManager.GetInstance().InvitePlayerToFaction(context.getSource().getPlayer(), player.getUuidAsString(), player.getEntityName());
return 0;
return retValue;
} }
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@ -130,22 +202,26 @@ public class FactionCommands {
return 0; return 0;
} }
private int KickPlayerFromFaction() { private int GetFactionInformation(ServerPlayerEntity player) {
return 0;
}
private int KickPlayerFromFaction(CommandContext<ServerCommandSource> context, ServerPlayerEntity player) {
int retValue = -1; int retValue = -1;
return retValue; return retValue;
} }
private int PromotePlayerInFaction() { private int PromotePlayerInFaction(CommandContext<ServerCommandSource> context, ServerPlayerEntity player) {
int retValue = -1; ServerPlayerEntity caller = context.getSource().getPlayer();
FactionManager.GetInstance().PromotePlayer(caller, player.getUuidAsString(), player.getEntityName());
return retValue; return 0;
} }
private int DemotePlayerInFaction() { private int DemotePlayerInFaction(CommandContext<ServerCommandSource> context, ServerPlayerEntity player) {
int retValue = -1; ServerPlayerEntity caller = context.getSource().getPlayer();
FactionManager.GetInstance().DemotePlayer(caller, player.getUuidAsString(), player.getEntityName());
return retValue; return 0;
} }
private int SetPlayerRoleInFaction() { private int SetPlayerRoleInFaction() {

View File

@ -0,0 +1,61 @@
package jesse.keeblarcraft.Commands;
import com.mojang.brigadier.arguments.StringArgumentType;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.minecraft.server.command.CommandManager;
import net.minecraft.server.network.ServerPlayerEntity;
public class MailCommands {
public void RegisterMailCommands() {
// Mail send <player> msg...
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
var mailRoot = CommandManager.literal("mail").build();
var sendNode = CommandManager.literal("send").build();
var playerName = CommandManager.argument("target_name", StringArgumentType.string()).build();
var message = CommandManager.argument("mail_msg", StringArgumentType.greedyString())
.executes(context -> SendMail(context.getSource().getPlayer(), StringArgumentType.getString(context, "target_name"), StringArgumentType.getString(context, "mail_msg")))
.build();
dispatcher.getRoot().addChild(mailRoot);
mailRoot.addChild(sendNode);
sendNode.addChild(playerName);
playerName.addChild(message);
});
// Mail read
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
var mailRoot = CommandManager.literal("mail").build();
var readNode = CommandManager.literal("read")
.executes(context -> ReadMail(context.getSource().getPlayer()))
.build();
dispatcher.getRoot().addChild(mailRoot);
mailRoot.addChild(readNode);
});
// Mail clear
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
var mailRoot = CommandManager.literal("mail").build();
var clearNode = CommandManager.literal("clear")
.executes(context -> ClearMail(context.getSource().getPlayer()))
.build();
dispatcher.getRoot().addChild(mailRoot);
mailRoot.addChild(clearNode);
});
}
private int SendMail(ServerPlayerEntity source, String targetName, String mail) {
return 0;
}
private int ReadMail(ServerPlayerEntity player) {
return 0;
}
private int ClearMail(ServerPlayerEntity player) {
return 0;
}
}

View File

@ -1,35 +1,16 @@
package jesse.keeblarcraft.Commands; package jesse.keeblarcraft.Commands;
import org.apache.logging.log4j.core.jmx.Server;
import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.arguments.StringArgumentType;
import jesse.keeblarcraft.Keeblarcraft;
import jesse.keeblarcraft.ConfigMgr.ConfigManager; import jesse.keeblarcraft.ConfigMgr.ConfigManager;
import jesse.keeblarcraft.ConfigMgr.GeneralConfig; import jesse.keeblarcraft.ConfigMgr.GeneralConfig;
import jesse.keeblarcraft.EventMgr.DimensionLoadingEvent;
import jesse.keeblarcraft.Utils.DirectionalVec; import jesse.keeblarcraft.Utils.DirectionalVec;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.ChestBlock;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.command.argument.EntityArgumentType;
import net.minecraft.inventory.EnderChestInventory;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.nbt.NbtList;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.CommandManager;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld; import net.minecraft.server.world.ServerWorld;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraft.world.dimension.DimensionType;
public class MiscCommands { public class MiscCommands {
ConfigManager config = new ConfigManager(); ConfigManager config = new ConfigManager();
@ -75,6 +56,17 @@ public class MiscCommands {
dispatcher.getRoot().addChild(warp); dispatcher.getRoot().addChild(warp);
warp.addChild(warpLoc); warp.addChild(warpLoc);
}); });
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
var warp = CommandManager.literal("nick").build();
var warpLoc = CommandManager.argument("CUSTOM_NICKNAME", StringArgumentType.string())
.executes(context -> SetNickname(context.getSource().getPlayer(), StringArgumentType.getString(context, "CUSTOM_NICKNAME"))).build();
dispatcher.getRoot().addChild(warp);
warp.addChild(warpLoc);
});
} }
public int Warp(ServerPlayerEntity player, String location) { public int Warp(ServerPlayerEntity player, String location) {
@ -132,6 +124,12 @@ public class MiscCommands {
return 0; return 0;
} }
public int SetNickname(ServerPlayerEntity player, String name) {
player.setCustomName(Text.of(name));
player.setCustomNameVisible(true);
return 0;
}
public int GetEnderchestOfPlayer(ServerPlayerEntity cmdInitiator, ServerPlayerEntity targetPlayer) { public int GetEnderchestOfPlayer(ServerPlayerEntity cmdInitiator, ServerPlayerEntity targetPlayer) {
// if (cmdInitiator.hasPermissionLevel(4)) { // if (cmdInitiator.hasPermissionLevel(4)) {

View File

@ -6,13 +6,12 @@ import com.mojang.brigadier.context.CommandContext;
import jesse.keeblarcraft.ConfigMgr.ConfigManager; import jesse.keeblarcraft.ConfigMgr.ConfigManager;
import jesse.keeblarcraft.JsonClassObjects.PlayerNote; import jesse.keeblarcraft.JsonClassObjects.PlayerNote;
import jesse.keeblarcraft.Utils.ChatUtil; import jesse.keeblarcraft.ChatStuff.ChatMsg;
import jesse.keeblarcraft.Utils.ChatUtil.CONSOLE_COLOR;
import jesse.keeblarcraft.Utils.CustomExceptions.DIRECTORY_CREATE_EXCEPTION;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
public class NoteCommands { public class NoteCommands {
/// Class Variables /// Class Variables
@ -21,27 +20,8 @@ public class NoteCommands {
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
/// @fn NoteCommands /// @fn NoteCommands
///
/// @brief This classes non-trivial constructor. Ensures creation
// of notes directory exists before commands can be ran
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
public NoteCommands() { public NoteCommands() {}
// Check if directory exists
// if (notesConfig.DoesDirectoryExist(NOTES_GLOBAL_DIRECTORY) == false) {
// // Attempt to create the directory
// try {
// if (notesConfig.CreateDirectory(NOTES_GLOBAL_DIRECTORY) == true) {
// System.out.println(ChatUtil.ColoredString("Created notes directory successfully!", CONSOLE_COLOR.BLUE)); //TODO: Success!
// } else {
// System.out.println(ChatUtil.ColoredString("ERROR: Notes directory FAILED to create!! Either the directory already exists or we are missing permissions!", CONSOLE_COLOR.RED)); //TODO: Critical failure --not specfic enough to mark it as a red or blue
// }
// } catch (DIRECTORY_CREATE_EXCEPTION e) {
// System.out.println(ChatUtil.ColoredString("Directory creation failed", CONSOLE_COLOR.RED));
// }
// } else {
// System.out.println(ChatUtil.ColoredString("Notes directory already exists. Skipping creation...", CONSOLE_COLOR.BLUE)); //TODO: Success!
// }
}
//TODO: Rework note commands upon story mode release //TODO: Rework note commands upon story mode release
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@ -51,69 +31,69 @@ public class NoteCommands {
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
public void RegisterNoteCommands() { public void RegisterNoteCommands() {
// Command: "/addnote note goes here" // Command: "/addnote note goes here"
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
dispatcher.register(CommandManager.literal("addnote")
.then(CommandManager.argument("value", StringArgumentType.greedyString())
.executes(context -> AddNote(StringArgumentType.getString(context, "value"), context))));
});
// Command: "/delnote noteIdHere"
// CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> { // CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
// dispatcher.register(CommandManager.literal("addnote") // dispatcher.register(CommandManager.literal("delnote")
// .then(CommandManager.argument("value", StringArgumentType.greedyString()) // .then(CommandManager.argument("value", StringArgumentType.greedyString())
// .executes(context -> AddNote(StringArgumentType.getString(context, "value"), context)))); // .executes(context -> AddNote(StringArgumentType.getString(context, "value"), context))));
// }); // });
// // Command: "/delnote noteIdHere" // Command: "/purgenotes"
// // CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> { CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
// // dispatcher.register(CommandManager.literal("delnote") dispatcher.register(CommandManager.literal("purgenotes")
// // .then(CommandManager.argument("value", StringArgumentType.greedyString()) .executes(context -> PurgeAllNotes(context)));
// // .executes(context -> AddNote(StringArgumentType.getString(context, "value"), context)))); });
// // });
// // Command: "/purgenotes" // Command: "/modifynote noteIdHere new_note_string_here"
// CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> { // Alises: "/editnote"
// dispatcher.register(CommandManager.literal("purgenotes") CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
// .executes(context -> PurgeAllNotes(context))); final var mNote = dispatcher.register(CommandManager.literal("editnote")
// }); .then(CommandManager.argument("note_id", IntegerArgumentType.integer())
.then(CommandManager.argument("new_note", StringArgumentType.string())
.executes(context -> ModifyNote(
IntegerArgumentType.getInteger(context, "note_id"),
StringArgumentType.getString(context, "new_note"),
context)))));
// // Command: "/modifynote noteIdHere new_note_string_here" dispatcher.register(CommandManager.literal("editnote").redirect(mNote));
// // Alises: "/editnote" });
// CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
// final var mNote = dispatcher.register(CommandManager.literal("editnote")
// .then(CommandManager.argument("note_id", IntegerArgumentType.integer())
// .then(CommandManager.argument("new_note", StringArgumentType.string())
// .executes(context -> ModifyNote(
// IntegerArgumentType.getInteger(context, "note_id"),
// StringArgumentType.getString(context, "new_note"),
// context)))));
// dispatcher.register(CommandManager.literal("editnote").redirect(mNote)); // Command Root: "/delnote noteIdHere"
// }); // Aliases: "/rmnote", "/deletenote"
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
final var rootDeleteCmd = dispatcher.register(CommandManager.literal("delnote")
.then(CommandManager.argument("value", IntegerArgumentType.integer())
.executes(context -> DeleteNote(IntegerArgumentType.getInteger(context, "value"), context))));
// // Command Root: "/delnote noteIdHere" // Alias redirects
// // Aliases: "/rmnote", "/deletenote" dispatcher.register(CommandManager.literal("rmnote").redirect(rootDeleteCmd));
// CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> { dispatcher.register(CommandManager.literal("deletenote").redirect(rootDeleteCmd));
// final var rootDeleteCmd = dispatcher.register(CommandManager.literal("delnote") });
// .then(CommandManager.argument("value", IntegerArgumentType.integer())
// .executes(context -> DeleteNote(IntegerArgumentType.getInteger(context, "value"), context))));
// // Alias redirects // Command Root: "/notegui"
// dispatcher.register(CommandManager.literal("rmnote").redirect(rootDeleteCmd)); CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
// dispatcher.register(CommandManager.literal("deletenote").redirect(rootDeleteCmd)); dispatcher.register(CommandManager.literal("notegui")
// }); .executes(context -> { OpenNoteGui(context);
return 0;
}));
});
// // Command Root: "/notegui" // Command Root: "/notelist"
// CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> { // Aliases: "/listnotes"
// dispatcher.register(CommandManager.literal("notegui") CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
// .executes(context -> { OpenNoteGui(context); final var rootListNotes = dispatcher.register(CommandManager.literal("notelist")
// return 0; .executes(context -> { ListNotes(context);
// })); return 0;
// }); }));
// // Command Root: "/notelist" dispatcher.register(CommandManager.literal("listnotes").redirect(rootListNotes));
// // Aliases: "/listnotes" });
// CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
// final var rootListNotes = dispatcher.register(CommandManager.literal("notelist")
// .executes(context -> { ListNotes(context);
// return 0;
// }));
// dispatcher.register(CommandManager.literal("listnotes").redirect(rootListNotes));
// });
} }
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@ -137,11 +117,11 @@ public class NoteCommands {
// Note mgmt // Note mgmt
PlayerNote note = new PlayerNote(player.getUuidAsString()); PlayerNote note = new PlayerNote(player.getUuidAsString());
note.AddNote(value, 1, 1, 1, 1); note.AddNote(value, 1, 1, 1, 1);
ChatUtil.SendPlayerMsg(player, "New note logged to entry! View notes any time with /notegui"); player.sendMessage(Text.of("New note logged to entry! View notes any time with /notegui"));
ret = 0; ret = 0;
} else { } else {
System.out.println(ChatUtil.ColoredString("Only a player can execute this command!", CONSOLE_COLOR.RED)); System.out.println("Only a player can execute this command!");
} }
return ret; return ret;
@ -166,7 +146,7 @@ public class NoteCommands {
ServerPlayerEntity player = context.getSource().getPlayer(); ServerPlayerEntity player = context.getSource().getPlayer();
PlayerNote note = new PlayerNote(player.getUuidAsString()); PlayerNote note = new PlayerNote(player.getUuidAsString());
ChatUtil.SendPlayerMsg(player, "Deleted note entry. View notes any time with /notegui"); player.sendMessage(Text.of("Deleted note entry. View notes any time with /notegui"));
ret = 0; ret = 0;
note.DeleteNote(value); note.DeleteNote(value);
@ -206,7 +186,8 @@ public class NoteCommands {
note.ModifyNote(value, newNote, epochTime, storyChapter, storyPart); note.ModifyNote(value, newNote, epochTime, storyChapter, storyPart);
ChatUtil.SendPlayerMsg(player, "Modified note entry. View notes any time with /notegui"); player.sendMessage(Text.of("Modified note entry. View notes any time with /notegui"));
ret = 0; ret = 0;
} }
@ -232,7 +213,7 @@ public class NoteCommands {
PlayerNote note = new PlayerNote(player.getUuidAsString()); PlayerNote note = new PlayerNote(player.getUuidAsString());
note.PurgeAllNotes(); note.PurgeAllNotes();
ChatUtil.SendPlayerMsg(player, "Purged all notes. View notes any time with /notegui"); player.sendMessage(Text.of("Purged all notes. View notes any time with /notegui"));
ret = 0; ret = 0;
} else { } else {
@ -259,11 +240,10 @@ public class NoteCommands {
ServerPlayerEntity player = context.getSource().getPlayer(); ServerPlayerEntity player = context.getSource().getPlayer();
PlayerNote notes = new PlayerNote(player.getUuidAsString()); PlayerNote notes = new PlayerNote(player.getUuidAsString());
ChatUtil.SendPlayerMsg(player, "Listing all notes...");
for (int i = 0; i <= notes.GetNotebookSize(); i++) { for (int i = 0; i <= notes.GetNotebookSize(); i++) {
String individualNote = notes.GetNoteString(i); String individualNote = notes.GetNoteString(i);
if (individualNote != "") { if (individualNote != "") {
ChatUtil.SendPlayerMsg(player, "Note " + i + ": " + individualNote); player.sendMessage(Text.of("Note " + i + ": " + individualNote));
} }
} }

View File

@ -0,0 +1,18 @@
package jesse.keeblarcraft.Commands;
import com.mojang.brigadier.arguments.StringArgumentType;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.minecraft.server.command.CommandManager;
public class ShopCommands {
public void RegisterShopCommands() {
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
var shopCmd = CommandManager.literal("shop").build();
var shopCreate = CommandManager.literal("create").build();
dispatcher.getRoot().addChild(shopCmd);
});
}
}

View File

@ -13,9 +13,10 @@ package jesse.keeblarcraft.Commands;
import com.mojang.brigadier.arguments.IntegerArgumentType; import com.mojang.brigadier.arguments.IntegerArgumentType;
import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.context.CommandContext;
import jesse.keeblarcraft.Utils.ChatUtil; import jesse.keeblarcraft.Keeblarcraft;
import jesse.keeblarcraft.Utils.ChatUtil.CONSOLE_COLOR; import jesse.keeblarcraft.Utils.PlayerChecks;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.minecraft.command.argument.EntityArgumentType;
import net.minecraft.entity.player.PlayerAbilities; import net.minecraft.entity.player.PlayerAbilities;
import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.command.ServerCommandSource;
@ -24,8 +25,6 @@ import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text; import net.minecraft.text.Text;
public class ShortcutCommands { public class ShortcutCommands {
float DEFAULT_FLIGHT_SPEED = 0.05f; // Minecraft operates on a 0.0 -> 1.0 scale; with each .01 making a difference in speed. 0.05 is creative flight speed
float SPEED_SCALAR = 20.0f; // For clamping speed down to half of its max output (So 0.5 will be max speed on a system that goes up in 0.05'ths) float SPEED_SCALAR = 20.0f; // For clamping speed down to half of its max output (So 0.5 will be max speed on a system that goes up in 0.05'ths)
public void RegisterShortcutCommands() public void RegisterShortcutCommands()
@ -39,31 +38,31 @@ public class ShortcutCommands {
// Fly command // Fly command
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> { CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
dispatcher.register(CommandManager.literal("fly") var flightNode = CommandManager.literal("fly").executes(context -> FlightSpeedShortcut(null, context)).build();
.executes(context -> { FlightShortcut(context);
return 0; var flightSpeed = CommandManager.argument("value", IntegerArgumentType.integer())
})); .executes(context -> FlightSpeedShortcut(IntegerArgumentType.getInteger(context, "value"), context)).build();
dispatcher.getRoot().addChild(flightNode);
flightNode.addChild(flightSpeed);
}); });
// Fly command with speed
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> { CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
dispatcher.register(CommandManager.literal("fly") var healNode = CommandManager.literal("heal").executes(context -> HealShortcut(context, null)).build();
.then(CommandManager.argument("value", IntegerArgumentType.integer()) var targetPlayer = CommandManager.argument("targetPlayer", EntityArgumentType.player())
.executes(context -> FlightSpeedShortcut(IntegerArgumentType.getInteger(context, "value"), context)))); .executes(context -> HealShortcut(context, EntityArgumentType.getPlayer(context, "targetPlayer"))).build();
dispatcher.getRoot().addChild(healNode);
healNode.addChild(targetPlayer);
}); });
///TODO: Read TODO on function
// CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
// dispatcher.register(CommandManager.literal("walk")
// .then(CommandManager.argument("value", IntegerArgumentType.integer())
// .executes(context -> WalkSpeedShortcut(IntegerArgumentType.getInteger(context, "value"), context))));
// });
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> { CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
dispatcher.register(CommandManager.literal("heal") var feedNode = CommandManager.literal("feed").executes(context -> FeedShortcut(context, null)).build();
.executes(context -> { HealShortcut(context); var targetPlayer = CommandManager.argument("targetPlayer", EntityArgumentType.player())
return 0; .executes(context -> FeedShortcut(context, EntityArgumentType.getPlayer(context, "targetPlayer"))).build();
}));
dispatcher.getRoot().addChild(feedNode);
feedNode.addChild(targetPlayer);
}); });
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> { CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
@ -111,118 +110,79 @@ public class ShortcutCommands {
retValue = -1; retValue = -1;
break; break;
} }
} }
else { else {
player.sendMessage(Text.literal("\033[31m You do not have permissions to run this command! \033[0m")); player.sendMessage(Text.literal("\033[31m You do not have permissions to run this command! \033[0m"));
} }
} }
else { else {
System.out.println(ChatUtil.ColoredString("This command cannot be executed by a non-player entity!", CONSOLE_COLOR.RED)); Keeblarcraft.LOGGER.info("This command cannot be executed by a non-player entity!");
} }
return retValue; return retValue;
} }
private int FlightShortcut(CommandContext<ServerCommandSource> context) { private int FlightSpeedShortcut(Integer value, CommandContext<ServerCommandSource> context) {
int retValue = -1; if (PlayerChecks.HasPermission(context)) {
if (context.getSource().isExecutedByPlayer()) {
ServerPlayerEntity player = context.getSource().getPlayer(); ServerPlayerEntity player = context.getSource().getPlayer();
PlayerAbilities abilities = player.getAbilities();
if (player.hasPermissionLevel(4)) { // Disable flight
PlayerAbilities abilities = player.getAbilities(); if (abilities.flying && value == null) {
abilities.flying = !abilities.flying; // Toggle flying abilities.flying = false;
abilities.setFlySpeed(DEFAULT_FLIGHT_SPEED); // It seems flight speed is on a 0-1 scale abilities.allowFlying = false;
abilities.setFlySpeed(0);
player.sendMessage(Text.of("Disabled flight"));
player.sendAbilitiesUpdate(); player.sendAbilitiesUpdate();
ChatUtil.SendPlayerMsg(player, "You can now fly! Flight speed is " + abilities.getFlySpeed()); } else if (!abilities.flying && value == null) {
} else { value = 1;
player.sendMessage(Text.literal("You do not have permission for this command")); }
// Enable flight
if (value != null && value >= 1 && value <= 10) {
abilities.allowFlying = true;
abilities.setFlySpeed((float) (value / SPEED_SCALAR)); // Dividing by 20f yields max clamp value of 0.5 since MC does 0.0-> 1.0 flight. 0.1 flight is too fast!
player.sendAbilitiesUpdate();
player.sendMessage(Text.of("Flight speed set to " + value));
} else if (value != null) {
player.sendMessage(Text.literal("Only values from 1-10 are accepted"));
} }
} }
return retValue; return 0;
} }
private int FlightSpeedShortcut(int value, CommandContext<ServerCommandSource> context) { private int FeedShortcut(CommandContext<ServerCommandSource> context, ServerPlayerEntity target) {
int retValue = -1; if (PlayerChecks.HasPermission(context)) {
// if target is null, feed ourselves
if (context.getSource().isExecutedByPlayer()) { if (target == null) {
ServerPlayerEntity player = context.getSource().getPlayer(); ServerPlayerEntity player = context.getSource().getPlayer();
player.getHungerManager().setExhaustion(0.0f);
if (player.hasPermissionLevel(4)) { player.getHungerManager().setFoodLevel(20); // 20 is hardcoded inside class
PlayerAbilities abilities = player.getAbilities(); player.getHungerManager().setSaturationLevel(10.0f); // 5 is set in constructor, but let's try 10!
player.sendMessage(Text.of("You were just super fed!"));
if (value >= 1 && value <= 10) {
abilities.allowFlying = true;
abilities.setFlySpeed((float) (value / SPEED_SCALAR)); // Dividing by 20f yields max clamp value of 0.5 since MC does 0.0-> 1.0 flight. 0.1 flight is too fast!
player.sendAbilitiesUpdate();
ChatUtil.SendPlayerMsg(player, "Flight speed set to " + (value));
} else {
player.sendMessage(Text.literal("Only values from 1-10 are accepted"));
}
} else { } else {
player.sendMessage(Text.literal("You do not have permission for this command")); target.getHungerManager().setExhaustion(0.0f);
target.getHungerManager().setFoodLevel(20); // 20 is hardcoded inside class
target.getHungerManager().setSaturationLevel(10.0f); // 5 is set in constructor, but let's try 10!
target.sendMessage(Text.of("You were just super fed!"));
} }
} }
return 0;
return retValue;
} }
///TODO: There is a bug with walk speed that causes the players speed to behave weirdly despite the value. It's either a crawl or mach 10 private int HealShortcut(CommandContext<ServerCommandSource> context, ServerPlayerEntity target) {
///TODO: It's possible that the player may need to die first to reset speed; and reloading in the debugger does not count as resetting values. This
///TODO: code may actually work; but I just did not die first in between testing speed changes.
// private int WalkSpeedShortcut(int value, CommandContext<ServerCommandSource> context) {
// int retValue = -1;
// if (context.getSource().isExecutedByPlayer()) {
// ServerPlayerEntity player = context.getSource().getPlayer();
// if (player.hasPermissionLevel(4)) {
// PlayerAbilities abilities = player.getAbilities();
// if (value >= 1 && value <= 10) {
// abilities.setWalkSpeed((float) 1.0f);
// player.sendAbilitiesUpdate();
// ChatUtil.SendPlayerMsg(player, "Set walk speed to " + (value));
// } else {
// player.sendMessage(Text.literal("Only values from 1-10 are accepted"));
// }
// } else {
// player.sendMessage(Text.literal("You do not have permission for this command"));
// }
// }
// return retValue;
// }
// TODO: Add when we can find where in the API to fill players hunger level
// private int FeedShortcut(CommandContext<ServerCommandSource> context) {
// int retValue = -1;
// if (context.getSource().isExecutedByPlayer()) {
// ServerPlayerEntity player = context.getSource().getPlayer();
// if (player.hasPermissionLevel(4)) {
// } else {
// player.sendMessage(Text.literal("You do not have permission for this command"));
// }
// }
// return retValue;
// }
private int HealShortcut(CommandContext<ServerCommandSource> context) {
int retValue = -1; int retValue = -1;
if (context.getSource().isExecutedByPlayer()) { if (PlayerChecks.HasPermission(context)) {
ServerPlayerEntity player = context.getSource().getPlayer(); // If no player specified; then heal ourself full HP
if (target == null) {
if (player.hasPermissionLevel(4)) { context.getSource().getPlayer().setHealth(context.getSource().getPlayer().getMaxHealth());
player.setHealth(player.getMaxHealth()); context.getSource().getPlayer().sendMessage(Text.of("Healed!"));
ChatUtil.SendPlayerMsg(player, "Healed!");
} else { } else {
player.sendMessage(Text.literal("You do not have permission for this command")); target.setHealth(target.getMaxHealth());
target.sendMessage(Text.of("You were just healed!"));
context.getSource().getPlayer().sendMessage(Text.of("You healed " + target.getEntityName()));
} }
} }
return retValue; return retValue;
} }

View File

@ -15,6 +15,7 @@ import java.io.FileWriter;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Paths;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import com.google.common.io.Files; import com.google.common.io.Files;
@ -30,65 +31,110 @@ import org.apache.commons.io.FileUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import jesse.keeblarcraft.Utils.ChatUtil; import jesse.keeblarcraft.Keeblarcraft;
import jesse.keeblarcraft.Utils.ChatUtil.CONSOLE_COLOR;
import jesse.keeblarcraft.Utils.CustomExceptions.*;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtIo; import net.minecraft.nbt.NbtIo;
import net.minecraft.nbt.NbtList; import net.minecraft.nbt.NbtList;
public class ConfigManager { public class ConfigManager {
// Pedantic empty constructor // Pedantic empty constructor
private static final String GLOBAL_CONFIG = "config/keeblarcraft/";
public ConfigManager() {} public ConfigManager() {}
// CreateFile // Get a File reference to a file that is created on disk
// private File GetFile(String confFile) {
// Returns true if file is created, will return false if file cannot be created (returns true if already exists) File file = null;
public Boolean CreateFile(String fileName) throws FILE_CREATE_EXCEPTION { System.out.println("Get file called for " + GLOBAL_CONFIG + confFile);
Boolean ret = false; try {
File file = new File(fileName); System.out.println("GetFile Cur Dir: " + Paths.get("").toAbsolutePath().toString());
file = new File(GLOBAL_CONFIG + confFile);
// Check 1: Does the file already exist? } catch (Exception e) {}
ret = file.exists(); return file;
System.out.println(ChatUtil.ColoredString("Does file exist? ", CONSOLE_COLOR.BLUE) + (ret ? ChatUtil.ColoredString("YES", CONSOLE_COLOR.YELLOW) : ChatUtil.ColoredString("NO", CONSOLE_COLOR.YELLOW)));
// Check 2: If the file does not exist, attempt to create it
if (ret == false) {
try {
ret = file.createNewFile();
} catch (IOException e) {
// The file could not be created
throw new FILE_CREATE_EXCEPTION();
}
} else {
ret = true; // This might be a hot fix, but technically the file already exists so would this be true or false? --?this statement is wild?
System.out.println(ChatUtil.ColoredString("File (name: ", CONSOLE_COLOR.BLUE) + ChatUtil.ColoredString(fileName, CONSOLE_COLOR.YELLOW) + ChatUtil.ColoredString(" was determined to already exist. Exiting out", CONSOLE_COLOR.BLUE));
}
return ret;
} }
// DeleteFile // Returns the parent path to a given input.
// // Ex: /home/Downloads/file.txt will return /home/Downloads/
// Returns true if file is deleted, false if could not be deleted or does not exist // Ex: /home/Downloads will return /home/
public Boolean DeleteFile(String fileName) throws FILE_DELETE_EXCEPTION { // Ex: / will return /
Boolean ret = false; private String GetPathOfFile(String file) {
File file = new File(fileName); String pathToFile = "";
if (file != null) {
for (int i = file.length() - 1; i >= 0; i--) {
if (file.charAt(i) != File.separatorChar) {
continue;
}
else {
// Trim and break
pathToFile = file.substring(0, i);
break;
}
}
}
// Step 1: Does file exist? System.out.println("PathOfFile: " + pathToFile);
ret = file.exists(); return pathToFile;
}
// Step 2: If file exists, attempt to delete // Creates a directory and all necessary parent directories listed in dirname (under global config area)
if (ret == true) { public Boolean CreateDirectory(String dirName) {
Boolean success = false;
File directory = GetFile(dirName);
try {
if (directory != null) {
if (!directory.exists())
{
success = directory.mkdirs();
} else if (directory.isDirectory()) {
success = true;
} else {
System.out.println("Directory " + dirName + " is an already existing file!");
}
}
} catch (Exception e) {
System.out.println("Failed to create directory with name " + dirName);
e.printStackTrace();
}
return success;
}
// Create a file on the disk
public Boolean CreateFile(String fileName) {
Boolean success = false;
File file = GetFile(fileName);
String parentDir = GetPathOfFile(fileName);
// CreateDirectory will verify that the parent directories exist & at least the parent directory is in fact a directory
if (file != null && !file.exists() && CreateDirectory(parentDir)) {
try { try {
ret = file.delete(); success = file.createNewFile();
} catch (SecurityException e) { } catch (Exception e) {
throw new FILE_DELETE_EXCEPTION(); System.out.println("Failed to create file " + fileName);
e.printStackTrace();
} }
} else { } else {
System.out.println(ChatUtil.ColoredString("cannot delete file ", CONSOLE_COLOR.RED) + ChatUtil.ColoredString(fileName, CONSOLE_COLOR.YELLOW) + ChatUtil.ColoredString(" because file does not exist", CONSOLE_COLOR.BLUE)); System.out.println("CreateFile failed to finish. File may have been null (empty string input, unlikely), or parent directories could not be created/have overlapped name");
success = false;
} }
return ret; return success;
}
public Boolean DeleteFile(String fileName) {
Boolean success = false;
File file = GetFile(fileName);
success = !file.exists();
if (!success) {
try {
success = file.delete();
} catch (Exception e) {
System.out.println("Failed to delete file " + fileName);
e.printStackTrace();
}
}
return success;
} }
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@ -103,9 +149,9 @@ public class ConfigManager {
/// @brief Writes NbtList data to disk /// @brief Writes NbtList data to disk
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
public void WriteNbtListToFile(String fileName, String key, NbtList data) { public void WriteNbtListToFile(String fileName, String key, NbtList data) {
fileName = "config/keeblarcraft/" + fileName; // fileName = "config/keeblarcraft/" + fileName;
File file = new File(fileName); File file = GetFile(fileName);
if (!file.exists()) { if (!file.exists()) {
file.getParentFile().mkdirs(); file.getParentFile().mkdirs();
} }
@ -134,9 +180,9 @@ public class ConfigManager {
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
public HashMap<String, NbtList> ReadAllNbtListFromDirectory(String dir, int listType) { public HashMap<String, NbtList> ReadAllNbtListFromDirectory(String dir, int listType) {
HashMap<String, NbtList> list = new HashMap<String, NbtList>(); HashMap<String, NbtList> list = new HashMap<String, NbtList>();
dir = "config/keeblarcraft/" + dir; // dir = "config/keeblarcraft/" + dir;
File directory = new File(dir); File directory = GetFile(dir);
File[] files = directory.listFiles(); File[] files = directory.listFiles();
@ -190,7 +236,7 @@ public class ConfigManager {
FileWriter file; FileWriter file;
try { try {
file = new FileWriter(fileName); file = new FileWriter(GetFile(fileName));
switch(mode) { switch(mode) {
case "w": case "w":
file.write(data); file.write(data);
@ -201,13 +247,14 @@ public class ConfigManager {
ret = true; ret = true;
break; break;
default: default:
System.out.println(ChatUtil.ColoredString("Invalid mode to WriteToFile!", CONSOLE_COLOR.RED)); Keeblarcraft.LOGGER.debug("Invalid mode to WriteToFile!!");
break; break;
} }
file.close(); file.close();
} catch (IOException e) { } catch (IOException e) {
System.out.println(ChatUtil.ColoredString("Could not open file ", CONSOLE_COLOR.RED) + ChatUtil.ColoredString(fileName, CONSOLE_COLOR.YELLOW) + ChatUtil.ColoredString(" to write to it! Possibly permission issue?", CONSOLE_COLOR.RED)); e.printStackTrace();
Keeblarcraft.LOGGER.error("Could not open file " + fileName + " to write to it! Possible permissions issue??");
} }
return ret; return ret;
@ -223,17 +270,16 @@ public class ConfigManager {
// top-level key. // top-level key.
// //
// NOTE: THIS DOES NOT SAFE UPDATE THE KEY OBJECT. PRE-EXISTING DATA WILL BE DELETED FOREVER // NOTE: THIS DOES NOT SAFE UPDATE THE KEY OBJECT. PRE-EXISTING DATA WILL BE DELETED FOREVER
public void WriteToJsonFile(String fileName, Object data) throws FILE_WRITE_EXCEPTION { public void WriteToJsonFile(String fileName, Object data) {
Gson gson = new GsonBuilder().setPrettyPrinting().create(); Gson gson = new GsonBuilder().setPrettyPrinting().create();
fileName = "config/keeblarcraft/" + fileName;
try { try {
FileWriter writer = new FileWriter(fileName); FileWriter writer = new FileWriter(GetFile(fileName));
gson.toJson(data, writer); gson.toJson(data, writer);
writer.flush(); writer.flush();
writer.close(); writer.close();
} catch (JsonIOException | IOException e) { } catch (JsonIOException | IOException e) {
System.out.println(ChatUtil.ColoredString("Could not successfully write to json file [" + fileName + "]", CONSOLE_COLOR.RED)); Keeblarcraft.LOGGER.error("Could not successfully write to json file ["+fileName+"]");
throw new FILE_WRITE_EXCEPTION(); e.printStackTrace();
} }
} }
@ -243,80 +289,32 @@ public class ConfigManager {
public <T> T GetJsonObjectFromFile(String fileName, Class<T> classToConvertTo) throws JsonSyntaxException { public <T> T GetJsonObjectFromFile(String fileName, Class<T> classToConvertTo) throws JsonSyntaxException {
Gson gson = new Gson(); Gson gson = new Gson();
String ret = ""; String ret = "";
fileName = "config/keeblarcraft/" + fileName;
System.out.println("Call to GetJsonObjectFromFile with path + file being " + fileName);
// hot fix: Not sure how to return "false" for invalid conversion when I'm forced to convert or just catch... Look into a better // hot fix: Not sure how to return "false" for invalid conversion when I'm forced to convert or just catch... Look into a better
// return value in the future - but for now throw JsonSyntaxException no matter what exception is caught // return value in the future - but for now throw JsonSyntaxException no matter what exception is caught
try { try {
File file = new File(fileName); File file = GetFile(fileName);
ret = FileUtils.readFileToString(file, "UTF-8"); ret = FileUtils.readFileToString(file, "UTF-8");
} catch (NullPointerException e) { } catch (Exception e) {
System.out.println(ChatUtil.ColoredString("nullptr exception", CONSOLE_COLOR.RED)); e.printStackTrace();
throw new JsonSyntaxException(""); System.out.println("Caught an exception in retrieving JSON Object from file " + fileName);
} catch (FileNotFoundException e) { // throw new JsonSyntaxException("");
System.out.println(ChatUtil.ColoredString("file not found", CONSOLE_COLOR.RED));
throw new JsonSyntaxException("");
} catch (java.nio.charset.UnsupportedCharsetException e) {
System.out.println(ChatUtil.ColoredString("charset issue", CONSOLE_COLOR.RED));
throw new JsonSyntaxException("");
} catch (IOException e) {
System.out.println(ChatUtil.ColoredString("io exception", CONSOLE_COLOR.RED));
throw new JsonSyntaxException("");
} }
return gson.fromJson(ret, classToConvertTo); return gson.fromJson(ret, classToConvertTo);
} }
public Boolean DoesFileExist(String fileName) { public Boolean DoesFileExist(String fileName) {
return new File(fileName).exists(); // untested return GetFile(fileName) != null;
} }
public Boolean DoesDirectoryExist(String dirName) { public Boolean DoesDirectoryExist(String dirName) {
return new File(dirName).isDirectory(); // untested File file = GetFile(dirName);
return file != null && file.isDirectory();
} }
public Boolean CreateDirectory(String dirName) throws DIRECTORY_CREATE_EXCEPTION { public Boolean DeleteDirectory(String dirName) {
Boolean ret = false; return DeleteFile(dirName);
File dir = new File(dirName);
System.out.println("Attempting to create dir with name " + dirName);
try {
if ( ! dir.exists()) {
ret = dir.mkdirs();
}
} catch (Exception e) {
System.out.println(ChatUtil.ColoredString("Failed to make directory with name: ", CONSOLE_COLOR.RED) + ChatUtil.ColoredString(dirName, CONSOLE_COLOR.YELLOW));
ret = true; /// TODO: Hack to make Setup fn be fine with prev-created files! Make Setup more robust!
throw new DIRECTORY_CREATE_EXCEPTION();
}
return ret;
}
public Boolean DeleteDirectory(String dirName) throws DIRECTORY_DELETE_EXCEPTION {
Boolean ret = false;
File dir = new File(dirName);
try {
ret = dir.delete();
System.out.println(ChatUtil.ColoredString("Deleted directory ", CONSOLE_COLOR.GREEN) + ChatUtil.ColoredString(dirName, CONSOLE_COLOR.YELLOW));
} catch (Exception e) {
System.out.println(ChatUtil.ColoredString("Failed to delete directory: ", CONSOLE_COLOR.RED) + ChatUtil.ColoredString(dirName, CONSOLE_COLOR.YELLOW));
throw new DIRECTORY_DELETE_EXCEPTION();
}
return ret;
}
// AddToKey
//
// Adds new text to a key if found inside the config
public String AddToKey(String key, String newInfo) {
String ret = "";
return ret;
} }
// GetFile // GetFile
@ -324,11 +322,11 @@ public class ConfigManager {
// Returns a file as an arraylist of all the lines in the file. Generally only used for testing // Returns a file as an arraylist of all the lines in the file. Generally only used for testing
// //
// NOTE: Returns UTF-8 Encoding of file // NOTE: Returns UTF-8 Encoding of file
public List<String> GetFile(String fileName) { public List<String> GetFileLines(String fileName) {
List<String> ret = new ArrayList<String>(); List<String> ret = new ArrayList<String>();
try { try {
return Files.readLines(new File(fileName), Charsets.UTF_8); return Files.readLines(GetFile(fileName), Charsets.UTF_8);
} catch (IOException e) { } catch (IOException e) {
ret.clear(); ret.clear();
} }

View File

@ -4,7 +4,6 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import jesse.keeblarcraft.Utils.DirectionalVec; import jesse.keeblarcraft.Utils.DirectionalVec;
import jesse.keeblarcraft.Utils.CustomExceptions.FILE_WRITE_EXCEPTION;
public class GeneralConfig { public class GeneralConfig {
private static GeneralConfig static_inst; private static GeneralConfig static_inst;
@ -45,7 +44,6 @@ public class GeneralConfig {
try { try {
config = cfgMgr.GetJsonObjectFromFile("general.json", ImplementedConfig.class); config = cfgMgr.GetJsonObjectFromFile("general.json", ImplementedConfig.class);
System.out.println("Read in config. Random value: " + config.global_spawn.x);
existingFile = true; existingFile = true;
} catch(Exception e) { } catch(Exception e) {
System.out.println("FAILED TO READ IN GENERALCONFIG"); System.out.println("FAILED TO READ IN GENERALCONFIG");
@ -87,6 +85,27 @@ public class GeneralConfig {
FlashConfig(); FlashConfig();
} }
/////////////////////////////////////////////////////////////////////////////
/// @fn GetSQLPassword
///
/// @brief Returns the SQL password set in the text config
/////////////////////////////////////////////////////////////////////////////
public String GetSQLPassword() {
return config.sqlPassword;
}
public String GetSQLUsername() {
return config.sqlUsername;
}
public String GetSQLAddress() {
return config.sqlAddress;
}
public String GetSQLDatabase() {
return config.sqlDatabaseName;
}
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
/// @fn IsNewPlayer /// @fn IsNewPlayer
/// ///
@ -98,6 +117,7 @@ public class GeneralConfig {
/// @return True if player is new, false if not /// @return True if player is new, false if not
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
public Boolean IsNewPlayer(String uuid) { public Boolean IsNewPlayer(String uuid) {
System.out.println("Is config null? " + (config == null ? "YES" : "NO"));
System.out.println("IsNewPlayer called. List has: " + config.playerList); System.out.println("IsNewPlayer called. List has: " + config.playerList);
Boolean isNew = !config.playerList.contains(uuid); Boolean isNew = !config.playerList.contains(uuid);
@ -125,6 +145,10 @@ public class GeneralConfig {
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
private class ImplementedConfig { private class ImplementedConfig {
public String MOTD = "Welcome to the server! Have fun!"; public String MOTD = "Welcome to the server! Have fun!";
public String sqlAddress = "localhost";
public String sqlDatabaseName = "keeblarcraft";
public String sqlUsername = "SQL_USERNAME";
public String sqlPassword = "SQL_PASSWORD";
// This is lazy, but this will fill with every unique UUID that has joined the server. This is how I am checking // This is lazy, but this will fill with every unique UUID that has joined the server. This is how I am checking
// to see if a player has just joined the server for a first time or not // to see if a player has just joined the server for a first time or not
@ -139,10 +163,6 @@ public class GeneralConfig {
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
private void FlashConfig() { private void FlashConfig() {
System.out.println("Attempting to write generalconfig to file. Is null? " + (config == null ? "YES" : "NO")); System.out.println("Attempting to write generalconfig to file. Is null? " + (config == null ? "YES" : "NO"));
try { cfgMgr.WriteToJsonFile("general.json", config);
cfgMgr.WriteToJsonFile("general.json", config);
} catch (FILE_WRITE_EXCEPTION e) {
System.out.println("Caught FileWriteException from general config writing. uh oh!");
}
} }
} }

View File

@ -0,0 +1,184 @@
package jesse.keeblarcraft.ConfigMgr;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import jesse.keeblarcraft.ConfigMgr.SQLTypeSupport.VALID_SQL_TYPE;
import jesse.keeblarcraft.Utils.CommonStructures.Pair;
public class SQLConfig {
private static SQLConfig static_inst;
private String dbName;
private String dbUser;
private String dbPass;
private String dbAddr;
private Boolean connected = false;
private Connection conn = null; // Actual connection object
private enum SQL_RUN_TYPE {
GENERAL,
QUERY,
UPDATE
}
// Direct return object in relation to the SQL_RUN_TYPE of the SQL command that was used. Only one will
// be filled out properly for what you run - the other values will be null and not cleared!
private class SQLRunReturn {
Boolean generalRet;
ResultSet queryReturn;
Integer updateReturn;
}
public static SQLConfig GetInstance() {
if (static_inst == null) {
static_inst = new SQLConfig();
}
return static_inst;
}
public SQLConfig() {
connected = false;
try {
// According to some random online tutorial; this loads the driver!
Class.forName("com.mysql.cj.jdbc.Driver");
connected = true;
} catch (Exception e) {
System.out.println("Could not find the proper SQL JDBC Drivers. Cannot connect to SQL Config");
e.printStackTrace();
}
if (connected) {
try {
dbName = GeneralConfig.GetInstance().GetSQLDatabase();
dbUser = GeneralConfig.GetInstance().GetSQLUsername();
dbPass = GeneralConfig.GetInstance().GetSQLPassword();
dbAddr = "jdbc:mysql://" + GeneralConfig.GetInstance().GetSQLAddress() + "/" + dbName;
conn = DriverManager.getConnection(dbAddr, dbUser, dbPass);
} catch (SQLException e) {}
}
}
private SQLRunReturn RunCommand(String sqlCommand, SQL_RUN_TYPE type) {
SQLRunReturn sqlData = new SQLRunReturn();
// If conn is null; we may need to reconnect before running the command
if (conn == null) {
Connect();
}
if (conn != null) {
try {
Statement statement = conn.createStatement();
switch(type) {
case GENERAL:
sqlData.generalRet = statement.execute(sqlCommand);
break;
case QUERY:
sqlData.queryReturn = statement.executeQuery(sqlCommand);
break;
case UPDATE:
sqlData.updateReturn = statement.executeUpdate(sqlCommand);
break;
}
} catch (SQLException e) {
System.out.println(e.getSQLState());
}
}
return sqlData;
}
// Re-attempt the connection
public Boolean Connect() {
if (conn != null) {
try {
conn.close();
} catch (Exception e) {}
}
Boolean success = false;
try {
conn = DriverManager.getConnection(dbAddr, dbUser, dbPass);
success = true;
} catch (Exception e) {}
return success;
}
public Boolean IsConnected() {
return conn != null && this.connected;
}
// The case is converted to upper case automatically to be case insensitive
public Boolean DoesTableExist(String name) {
boolean tableExists = false;
if (conn != null) {
try (ResultSet rs = conn.getMetaData().getTables(null, null, name, null)) {
while (rs.next()) {
String tName = rs.getString("TABLE_NAME");
if (tName != null && tName.equals(name)) {
tableExists = true;
break;
}
}
} catch (SQLException e) {}
}
return tableExists;
}
public Boolean MakeNonNullable(String table, String columnName) {
return false;
}
public Integer AddPrimaryKey(String tableName, String primaryKeyColumn) {
SQLRunReturn success = new SQLRunReturn();
if (DoesTableExist(tableName)) {
String sqlCmd = "ALTER TABLE " + tableName + " ADD PRIMARY KEY (" + primaryKeyColumn + ");";
success = RunCommand(sqlCmd, SQL_RUN_TYPE.UPDATE);
}
return success.updateReturn;
}
public Integer AddForeignKey(String primaryTableName, String primaryColumnName, String foreignTableName, String foreignKeyColumn) {
SQLRunReturn success = new SQLRunReturn();
Boolean primaryTableExists = DoesTableExist(primaryTableName);
Boolean foreignTableExists = DoesTableExist(foreignTableName);
if (primaryTableExists && foreignTableExists) {
String sqlCmd = "ALTER TABLE " + primaryTableName + " ADD FOREIGN KEY (" + primaryColumnName + ") REFERENCES " + foreignTableName + " (" + foreignKeyColumn + ")";
success = RunCommand(sqlCmd, SQL_RUN_TYPE.UPDATE);
}
return success.updateReturn;
}
// Might fix heap pollution decay in future with enum types or something. For now we assume the user isn't horrifically stupid and will give a SQL-able type
public Boolean CreateTable(String tableName, Pair<String, VALID_SQL_TYPE>... columnPairs) {
Boolean success = false;
if (conn != null && !DoesTableExist(tableName.toUpperCase())) {
String sqlCommand = "CREATE TABLE " + tableName.toUpperCase() + "(";
for (Pair<String, VALID_SQL_TYPE> colPair : columnPairs) {
sqlCommand = sqlCommand + " " + colPair.GetKey() + " " + SQLTypeSupport.GetSqlStrForType(colPair.GetValue()) + ",";
}
// Strip the leading comma and append the ending ');' on the SQL statement
sqlCommand = sqlCommand.substring(0, sqlCommand.length() - 1) + ");";
SQLRunReturn rs = RunCommand(sqlCommand, SQL_RUN_TYPE.GENERAL);
try {
while (rs.queryReturn.next()) {
}
} catch (Exception e) {}
}
return success;
}
}

View File

@ -0,0 +1,51 @@
package jesse.keeblarcraft.ConfigMgr;
import jesse.keeblarcraft.ConfigMgr.SQLTypeSupport.VALID_SQL_TYPE;
import jesse.keeblarcraft.Utils.CommonStructures.Pair;
public class SQLInitServer {
// Initial run-time checks to make sure tables are all setup in advanced
public void Initialize() {
SetupTables();
}
@SuppressWarnings("unchecked")
private void SetupTables() {
// TABLE NAMES
String accountsTable = "ACCOUNTS";
String banksTable = "BANKS";
String customerTable = "CUSTOMER";
String transactionTable = "TRANSACTION";
// Create the ACCOUNTS table
Pair<String, VALID_SQL_TYPE> accountsGlobalId = new Pair<>("global_account_id", VALID_SQL_TYPE.VARCHAR);
Pair<String, VALID_SQL_TYPE> userUuid = new Pair<>("address", VALID_SQL_TYPE.VARCHAR);
Pair<String, VALID_SQL_TYPE> accountType = new Pair<>("account_type", VALID_SQL_TYPE.VARCHAR);
Pair<String, VALID_SQL_TYPE> balance = new Pair<>("balance", VALID_SQL_TYPE.BIGINT);
Pair<String, VALID_SQL_TYPE> openDate = new Pair<>("open_date", VALID_SQL_TYPE.VARCHAR);
SQLConfig.GetInstance().CreateTable(accountsTable, accountsGlobalId, userUuid, accountType, balance, openDate);
// Create the CUSTOMER table
Pair<String, VALID_SQL_TYPE> playerUuid = new Pair<>("player_uuid", VALID_SQL_TYPE.VARCHAR);
Pair<String, VALID_SQL_TYPE> playerName = new Pair<>("player_entity_name", VALID_SQL_TYPE.VARCHAR);
SQLConfig.GetInstance().CreateTable(customerTable, playerUuid, playerName);
// Create the BANKS table
Pair<String, VALID_SQL_TYPE> bankRouting = new Pair<>("routing", VALID_SQL_TYPE.BIGINT);
Pair<String, VALID_SQL_TYPE> bankName = new Pair<>("bank_name", VALID_SQL_TYPE.VARCHAR);
Pair<String, VALID_SQL_TYPE> bankSymbol = new Pair<>("bank_symbol", VALID_SQL_TYPE.VARCHAR);
Pair<String, VALID_SQL_TYPE> bankDateOpened = new Pair<>("date_opened", VALID_SQL_TYPE.VARCHAR);
SQLConfig.GetInstance().CreateTable(banksTable, bankRouting, bankName, bankSymbol, bankDateOpened);
// Create the TRANSACTION table
Pair<String, VALID_SQL_TYPE> transactionId = new Pair<>("transaction_id", VALID_SQL_TYPE.VARCHAR);
Pair<String, VALID_SQL_TYPE> transactionDate = new Pair<>("transaction_date", VALID_SQL_TYPE.VARCHAR);
Pair<String, VALID_SQL_TYPE> transactionType = new Pair<>("transaction_type", VALID_SQL_TYPE.VARCHAR);
Pair<String, VALID_SQL_TYPE> transactionAmount = new Pair<>("amount", VALID_SQL_TYPE.BIGINT);
Pair<String, VALID_SQL_TYPE> transactionFromAccount = new Pair<>("account_id", VALID_SQL_TYPE.VARCHAR);
Pair<String, VALID_SQL_TYPE> transactionDescription = new Pair<>("description", VALID_SQL_TYPE.TEXT);
Pair<String, VALID_SQL_TYPE> transactionDestination = new Pair<>("destination", VALID_SQL_TYPE.VARCHAR);
SQLConfig.GetInstance().CreateTable(transactionTable, transactionId, transactionDate, transactionType, transactionAmount,
transactionFromAccount, transactionDescription, transactionDestination);
}
}

View File

@ -0,0 +1,27 @@
package jesse.keeblarcraft.ConfigMgr;
public class SQLTypeSupport {
public enum VALID_SQL_TYPE {
VARCHAR,
BIGINT,
INT,
TEXT
}
// Produces the word that SQL would expect for the given datatype. In general it's usually just the word itself but in cases
// like 'varchar' you usually specify a size too. For now it defaults 255 but this can be expanded in the future
public static String GetSqlStrForType(VALID_SQL_TYPE type) {
switch(type) {
case VARCHAR:
return "VARCHAR(255)";
case BIGINT:
return "BIGINT";
case INT:
return "INT";
case TEXT:
return "TEXT";
}
return null; // This should never get hit
}
}

View File

@ -0,0 +1,38 @@
package jesse.keeblarcraft.ConfigMgr;
import jesse.keeblarcraft.ConfigMgr.SQLTypeSupport.VALID_SQL_TYPE;
import jesse.keeblarcraft.Utils.CommonStructures.Pair;
// Random commands to run to test the SQL class
public class SQLUnitTest {
public void RunTests() {
CreateTableTest();
ForeignKeyTest();
}
public void CreateTableTest() {
String tableName = "test_table";
Pair<String, VALID_SQL_TYPE> pairOne = new Pair<>("name", VALID_SQL_TYPE.VARCHAR);
Pair<String, VALID_SQL_TYPE> pairTwo = new Pair<>("address", VALID_SQL_TYPE.BIGINT);
Pair<String, VALID_SQL_TYPE> pairThree = new Pair<>("email", VALID_SQL_TYPE.TEXT);
SQLConfig.GetInstance().CreateTable(tableName, pairOne, pairTwo, pairThree);
}
public void DoesTableExistTest() {
String tableName = "test_table";
Boolean temp = SQLConfig.GetInstance().DoesTableExist(tableName.toUpperCase());
System.out.println("[SQL-UnitTest]: Does the table " + tableName + " exist? " + (temp ? "YES":"NO"));
}
public void ForeignKeyTest() {
String primTableName = "test_table";
String primColName = "name";
String foreTableName = "accounts";
String foreColName = "global_account_id";
Integer ret = SQLConfig.GetInstance().AddForeignKey(primTableName, primColName, foreTableName, foreColName);
System.out.println("[SQL-UnitTest]: Update foreign key test. Got return result number: " + ret);
}
}

View File

@ -0,0 +1,27 @@
package jesse.keeblarcraft.CustomBlocks.BlockEntities;
import jesse.keeblarcraft.Keeblarcraft;
import jesse.keeblarcraft.CustomBlocks.BlockManager;
import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
import net.minecraft.util.Identifier;
// EVENTUALLY THIS CLASS WILL GET COLLAPSED UNDER @ref BlockManager.java
// However; I don't have the time to figure out how to do this dynamically this second (I'm lazy and doing this
// all in one sitting)
public class BlockEntityRegistration {
// PLEASE STICK A COMMENT ABOVE EACH REGISTRATION FOR LATER REFERENCE
// FactionBlockEntity
public static final BlockEntityType<FactionBlockEntity> FACTION_BLOCK_ENTITY =
Registry.register(Registries.BLOCK_ENTITY_TYPE, new Identifier(Keeblarcraft.MOD_ID, "faction_block_entity"),
FabricBlockEntityTypeBuilder.create(FactionBlockEntity::new, BlockManager.GetBlock("faction_base_block")).build());
public static void RegisterBlockEntities() {
Keeblarcraft.LOGGER.info("Registering block entities for " + Keeblarcraft.MOD_ID);
}
}

View File

@ -0,0 +1,177 @@
package jesse.keeblarcraft.CustomBlocks.BlockEntities;
import java.util.ArrayList;
import jesse.keeblarcraft.AttributeMgr.AttributeMgr;
import jesse.keeblarcraft.AttributeMgr.AttributeTree;
import jesse.keeblarcraft.FactionMgr.Callbacks.PlayerEnteredBaseCallback;
import jesse.keeblarcraft.FactionMgr.Callbacks.PlayerExitedBaseCallback;
import jesse.keeblarcraft.FactionMgr.Callbacks.PlayerInBaseCallback;
import jesse.keeblarcraft.GuiMgr.FactionBlockScreenHandler;
import jesse.keeblarcraft.world.ImplementedInventory;
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.inventory.Inventories;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.screen.PropertyDelegate;
import net.minecraft.screen.ScreenHandler;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import net.minecraft.util.ActionResult;
import net.minecraft.util.collection.DefaultedList;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
public class FactionBlockEntity extends BlockEntity implements ExtendedScreenHandlerFactory, ImplementedInventory {
private final DefaultedList<ItemStack> inventory = DefaultedList.ofSize(7, ItemStack.EMPTY);
private static final int DEFENSE_SLOT_ONE = 0;
private static final int DEFENSE_SLOT_TWO = 1;
private static final int OFFENSE_SLOT_ONE = 2;
private static final int OFFENSE_SLOT_TWO = 3;
private static int factionPower = 0;
Boolean stopMobSpawn = true;
Boolean hasBuildFlight = true;
Boolean hasSuperBeacon = true;
private ArrayList<String> playersInRadius = new ArrayList<>();
protected final PropertyDelegate propertyDelegate;
public FactionBlockEntity(BlockPos pos, BlockState state) {
super(BlockEntityRegistration.FACTION_BLOCK_ENTITY, pos, state);
this.propertyDelegate = new PropertyDelegate() {
@Override
public int get(int index) {
// The only value we need to get/delegate is faction power
return switch(index) {
default -> factionPower;
};
}
@Override
public void set(int index, int value) {
switch(index) {
default -> factionPower = value;
};
}
@Override
public int size() {
// We are only sync'ing 1 integer - faction power
return 1;
}
};
}
@Override
public Text getDisplayName() {
return Text.literal("Faction Home Base Station"); // Replace with proper en_us format later
}
@Override
public ScreenHandler createMenu(int syncId, PlayerInventory playerInventory, PlayerEntity player) {
return new FactionBlockScreenHandler(syncId, playerInventory, this, this.propertyDelegate);
}
@Override
public void readNbt(NbtCompound nbt) {
super.readNbt(nbt);
Inventories.readNbt(nbt, inventory);
factionPower = nbt.getInt("faction_block_entity.power");
}
@Override
public void writeNbt(NbtCompound nbt) {
super.writeNbt(nbt);
// Write the inventory of the block
Inventories.writeNbt(nbt, inventory);
nbt.putInt("faction_block_entity.power", factionPower);
}
@Override
public DefaultedList<ItemStack> getItems() {
return inventory;
}
@Override
public void writeScreenOpeningData(ServerPlayerEntity player, PacketByteBuf buf) {
// Send position of this block entity from server->client->server etc
buf.writeBlockPos(this.pos);
}
private Boolean IsPlayerInBounds(PlayerEntity player, BlockPos pos) {
Boolean isNearBlock = false;
// Will check in range - assumes same world! 50 is a temporary value at the moment
Boolean xBounds = player.getX() <= pos.getX() + 50 && player.getX() >= pos.getX() - 50;
Boolean yBounds = player.getY() <= pos.getY() + 50 && player.getY() >= pos.getY() - 50;
Boolean zBounds = player.getZ() <= pos.getZ() + 50 && player.getZ() >= pos.getZ() - 50;
if (xBounds && yBounds && zBounds) {
isNearBlock = true;
}
return isNearBlock;
}
// Tick method is called 20 times a second
public void tick(World world, BlockPos pos, BlockState state) {
// For reasons unknown to me and only to Kaupenjoe (youtube video) - we never want to call this on a client.
if (world.isClient()) {
return;
}
// TODO: Optimize this block so that when it is placed the placers UUID is related to a faction and only pull from a list of those players not the entire server
for (PlayerEntity player : world.getPlayers()) {
Boolean isPlayerInFactionRadius = IsPlayerInBounds(player, pos);
if (isPlayerInFactionRadius) {
// Run individual faction modules for players here
// First time entry callback check
if (!playersInRadius.contains(player.getUuidAsString())) {
playersInRadius.add(player.getUuidAsString());
ActionResult result = PlayerEnteredBaseCallback.EVENT.invoker().interact(player, world);
}
// Invoke the flight attribute on this player
if (hasBuildFlight) {
AttributeMgr.ApplyAttribute(player.getUuidAsString(), "faction_flight");
ActionResult result = PlayerInBaseCallback.EVENT.invoker().interact(player, world);
}
if (hasSuperBeacon) {
AttributeMgr.ApplyAttribute(player.getUuidAsString(), "faction_beacon");
// ActionResult result = PlayerInBaseCallback.EVENT.invoker().interact(player, world);
}
} else if (!isPlayerInFactionRadius && playersInRadius.contains(player.getUuidAsString())) {
playersInRadius.remove(player.getUuidAsString());
ActionResult result = PlayerExitedBaseCallback.EVENT.invoker().interact(player, world);
}
}
// if (stopMobSpawn) {
// // Temporary for now
// // Sphere center point is going to be X,Y,Z
// Integer X = pos.getX();
// Integer y = pos.getY();
// Integer z = pos.getZ();
// Integer radius = 10;
// }
// if (hasBuildFlight) {
// for (PlayerEntity player : world.getPlayers()) {
// if (IsPlayerInBounds(player, pos)) {
// // Notify the attribute tree to enable this attribute!
// }
// }
// world.getBlockEntity(pos.east());
// }
}
}

View File

@ -1,7 +1,7 @@
package jesse.keeblarcraft.CustomBlocks; package jesse.keeblarcraft.CustomBlocks;
import jesse.keeblarcraft.CustomBlocks.Blocks.FactionBaseBlock;
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
import net.minecraft.block.AbstractBlock;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.Blocks; import net.minecraft.block.Blocks;
import net.minecraft.block.ExperienceDroppingBlock; import net.minecraft.block.ExperienceDroppingBlock;
@ -20,5 +20,6 @@ public class BlockList {
BlockManager.RegisterBlock("example_block_ore", new Block(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).sounds(BlockSoundGroup.AMETHYST_BLOCK).requiresTool().breakInstantly())); BlockManager.RegisterBlock("example_block_ore", new Block(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).sounds(BlockSoundGroup.AMETHYST_BLOCK).requiresTool().breakInstantly()));
BlockManager.RegisterBlock("example_block", new ExperienceDroppingBlock(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).sounds(BlockSoundGroup.ANCIENT_DEBRIS).requiresTool(), UniformIntProvider.create(4, 20))); BlockManager.RegisterBlock("example_block", new ExperienceDroppingBlock(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).sounds(BlockSoundGroup.ANCIENT_DEBRIS).requiresTool(), UniformIntProvider.create(4, 20)));
BlockManager.RegisterBlock("example_statue", new Block(FabricBlockSettings.copyOf(Blocks.BELL))); BlockManager.RegisterBlock("example_statue", new Block(FabricBlockSettings.copyOf(Blocks.BELL)));
BlockManager.RegisterBlock("faction_base_block", new FactionBaseBlock(FabricBlockSettings.copyOf(Blocks.IRON_BLOCK).nonOpaque()));
} }
} }

View File

@ -0,0 +1,76 @@
package jesse.keeblarcraft.CustomBlocks.Blocks;
import jesse.keeblarcraft.CustomBlocks.BlockEntities.BlockEntityRegistration;
import jesse.keeblarcraft.CustomBlocks.BlockEntities.FactionBlockEntity;
import net.minecraft.block.*;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.BlockEntityTicker;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.screen.NamedScreenHandlerFactory;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.ItemScatterer;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.shape.VoxelShape;
import net.minecraft.world.World;
public class FactionBaseBlock extends BlockWithEntity implements BlockEntityProvider {
// public static final VoxelShape SHAPE = Block.createCuboidShape(0, 0, 0, 16, 12, 16);
public FactionBaseBlock(Settings settings) {
super(settings);
}
// @Override
// protected VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
// return SHAPE;
// }
@Override
public BlockRenderType getRenderType(BlockState state) {
return BlockRenderType.MODEL;
}
@Override
public BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
return new FactionBlockEntity(pos, state);
}
// If block is destroyed; drop inventory
@Override
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) {
if (state.getBlock() != newState.getBlock()) {
BlockEntity blockEntity = world.getBlockEntity(pos);
if (blockEntity != null && blockEntity instanceof FactionBlockEntity) {
ItemScatterer.spawn(world, pos, (FactionBlockEntity) blockEntity);
world.updateComparators(pos, this);
}
super.onStateReplaced(state, world, pos, newState, moved);
}
}
// Open the inventory
// Calls ScreenHandler inside createMenu of entity class
@Override
public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
// Server side handling is different than that of client side handling; we MUST check if we are on a server first because then we must
// request information about this block entity from the server
System.out.println("onUse of faction base block called");
if (!world.isClient()) {
NamedScreenHandlerFactory screenHandlerFactory = (FactionBlockEntity) world.getBlockEntity(pos);
if (screenHandlerFactory != null) {
player.openHandledScreen(screenHandlerFactory);
}
}
return ActionResult.SUCCESS;
}
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(World world, BlockState state, BlockEntityType<T> type) {
return validateTicker(type, BlockEntityRegistration.FACTION_BLOCK_ENTITY,
(world1, pos, state1, blockEntity) -> blockEntity.tick(world1, pos, state1));
}
}

View File

@ -65,5 +65,4 @@ public class ItemManager {
// Item exampleItem = new Item(new FabricItemSettings()); // Item exampleItem = new Item(new FabricItemSettings());
// RegisterItem("metaljacket_helmet", exampleItem); // RegisterItem("metaljacket_helmet", exampleItem);
} }
} }

View File

@ -4,8 +4,7 @@ import java.util.HashMap;
import java.util.Map.Entry; import java.util.Map.Entry;
import jesse.keeblarcraft.ConfigMgr.ConfigManager; import jesse.keeblarcraft.ConfigMgr.ConfigManager;
import jesse.keeblarcraft.Utils.ChatUtil; import jesse.keeblarcraft.ChatStuff.ChatMsg;
import jesse.keeblarcraft.Utils.ChatUtil.CONSOLE_COLOR;
import jesse.keeblarcraft.world.dimension.ModDimensions; import jesse.keeblarcraft.world.dimension.ModDimensions;
import net.minecraft.nbt.NbtElement; import net.minecraft.nbt.NbtElement;
import net.minecraft.nbt.NbtList; import net.minecraft.nbt.NbtList;
@ -121,7 +120,7 @@ public class DimensionLoadingEvent {
} }
} }
} catch (Exception e) { } catch (Exception e) {
System.out.println(ChatUtil.ColoredString("Could not flash dimension loading configuration file", CONSOLE_COLOR.RED)); System.out.println("Could not flash dimension loading configuration file");
} }
} }
} }

View File

@ -1,7 +1,10 @@
package jesse.keeblarcraft.EventMgr; package jesse.keeblarcraft.EventMgr;
import java.util.HashMap;
import jesse.keeblarcraft.AttributeMgr.AttributeMgr; import jesse.keeblarcraft.AttributeMgr.AttributeMgr;
import jesse.keeblarcraft.AttributeMgr.AttributeTree; import jesse.keeblarcraft.AttributeMgr.AttributeTree;
import jesse.keeblarcraft.ConfigMgr.ConfigManager;
import jesse.keeblarcraft.ConfigMgr.GeneralConfig; import jesse.keeblarcraft.ConfigMgr.GeneralConfig;
import jesse.keeblarcraft.Utils.DirectionalVec; import jesse.keeblarcraft.Utils.DirectionalVec;
import net.fabricmc.fabric.api.networking.v1.PacketSender; import net.fabricmc.fabric.api.networking.v1.PacketSender;
@ -13,6 +16,13 @@ import net.minecraft.text.Text;
public class PlayerJoinListener { public class PlayerJoinListener {
private static PlayerJoinListener static_inst; private static PlayerJoinListener static_inst;
ConfigManager config = new ConfigManager();
String CACHED_PLAYER_LOGIN_CONFIG = "misc/cached_uuids.json";
private class CachedUUIDConfig {
HashMap<String, String> cached_uuids = new HashMap<String, String>();
}
CachedUUIDConfig cachedPlayerConfig;
// Get the static instance for this class // Get the static instance for this class
public static PlayerJoinListener GetInstance() { public static PlayerJoinListener GetInstance() {
@ -22,6 +32,28 @@ public class PlayerJoinListener {
return static_inst; return static_inst;
} }
public PlayerJoinListener() {
Boolean existingFile = false;
cachedPlayerConfig = new CachedUUIDConfig();
try {
cachedPlayerConfig = config.GetJsonObjectFromFile(CACHED_PLAYER_LOGIN_CONFIG, CachedUUIDConfig.class);
existingFile = cachedPlayerConfig != null;
} catch (Exception e) {
// intentionally empty
}
if (!existingFile) {
try {
cachedPlayerConfig = new CachedUUIDConfig();
config.CreateFile(CACHED_PLAYER_LOGIN_CONFIG);
FlashCachedConfig();
} catch (Exception e) {
System.out.println("Failed to parse or create cached uuid file");
}
}
}
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
/// @fn HandleServerJoinEvent /// @fn HandleServerJoinEvent
/// ///
@ -38,12 +70,13 @@ public class PlayerJoinListener {
// Handle skill tree map instance // Handle skill tree map instance
if (AttributeMgr.activeTrees.containsKey(player.getUuidAsString()) == false) { if (AttributeMgr.activeTrees.containsKey(player.getUuidAsString()) == false) {
AttributeMgr.activeTrees.put(player.getUuidAsString(), new AttributeTree(player.getUuidAsString())); AttributeMgr.activeTrees.put(player.getUuidAsString(), new AttributeTree(player));
} }
// Handle first time joining events (world spawn teleport, MOTD, etc) // Handle first time joining events (world spawn teleport, MOTD, etc)
System.out.println("Running first time login stuff"); System.out.println("Running first time login stuff");
IsFirstTimeLogin(player, server); IsFirstTimeLogin(player, server);
CachePlayersUuid(player.getUuidAsString(), player.getEntityName());
} }
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@ -74,4 +107,29 @@ public class PlayerJoinListener {
} }
} }
} }
public String TryGetPlayerUuidByName(String name) {
String uuid = "";
if (cachedPlayerConfig != null && cachedPlayerConfig.cached_uuids.containsKey(name)) {
uuid = cachedPlayerConfig.cached_uuids.get(name);
}
return uuid;
}
private void CachePlayersUuid(String uuid, String entityName) {
if (cachedPlayerConfig.cached_uuids.containsKey(entityName)) {
return;
} else {
cachedPlayerConfig.cached_uuids.put(entityName, uuid);
FlashCachedConfig();
}
}
private void FlashCachedConfig() {
try {
config.WriteToJsonFile(CACHED_PLAYER_LOGIN_CONFIG, cachedPlayerConfig);
} catch (Exception e) {
System.out.println("Encountered exception in writing cached uuid file!");
}
}
} }

View File

@ -0,0 +1,24 @@
package jesse.keeblarcraft.FactionMgr.Callbacks;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.ActionResult;
import net.minecraft.world.World;
public interface PlayerCommandFlightCallback {
Event<PlayerCommandFlightCallback> EVENT = EventFactory.createArrayBacked(PlayerCommandFlightCallback.class,
(listeners) -> (player, world) -> {
for (PlayerCommandFlightCallback listener : listeners) {
ActionResult result = listener.interact(player, world);
if (result != ActionResult.PASS) {
return result;
}
}
return ActionResult.PASS;
});
ActionResult interact(PlayerEntity player, World world);
}

View File

@ -0,0 +1,24 @@
package jesse.keeblarcraft.FactionMgr.Callbacks;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.ActionResult;
import net.minecraft.world.World;
public interface PlayerEnteredBaseCallback {
Event<PlayerEnteredBaseCallback> EVENT = EventFactory.createArrayBacked(PlayerEnteredBaseCallback.class,
(listeners) -> (player, world) -> {
for (PlayerEnteredBaseCallback listener : listeners) {
ActionResult result = listener.interact(player, world);
if (result != ActionResult.PASS) {
return result;
}
}
return ActionResult.PASS;
});
ActionResult interact(PlayerEntity player, World world);
}

View File

@ -0,0 +1,24 @@
package jesse.keeblarcraft.FactionMgr.Callbacks;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.ActionResult;
import net.minecraft.world.World;
public interface PlayerExitedBaseCallback {
Event<PlayerExitedBaseCallback> EVENT = EventFactory.createArrayBacked(PlayerExitedBaseCallback.class,
(listeners) -> (player, world) -> {
for (PlayerExitedBaseCallback listener : listeners) {
ActionResult result = listener.interact(player, world);
if (result != ActionResult.PASS) {
return result;
}
}
return ActionResult.PASS;
});
ActionResult interact(PlayerEntity player, World world);
}

View File

@ -0,0 +1,24 @@
package jesse.keeblarcraft.FactionMgr.Callbacks;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.ActionResult;
import net.minecraft.world.World;
public interface PlayerInBaseCallback {
Event<PlayerInBaseCallback> EVENT = EventFactory.createArrayBacked(PlayerInBaseCallback.class,
(listeners) -> (player, world) -> {
for (PlayerInBaseCallback listener : listeners) {
ActionResult result = listener.interact(player, world);
if (result != ActionResult.PASS) {
return result;
}
}
return ActionResult.PASS;
});
ActionResult interact(PlayerEntity player, World world);
}

View File

@ -91,6 +91,26 @@ public class FactionConfig {
return success; return success;
} }
// It is assumed that the person calling this function has verified that the person
// can in fact set faction power. This is generally just an admin command
public Boolean SetPower(String factionName, Integer amount) {
Boolean success = false;
if (IsValid(factionName)) {
allFactions.get(factionName).factionPower = amount;
success = true;
}
return success;
}
// The user should verify the faction exists prior to calling this. 0 is default
// return if faction does not exist (or the faction actually has a balance of 0)
public Integer GetPower(String factionName) {
Integer amount = 0;
if (IsValid(factionName)) {
amount = allFactions.get(factionName).factionPower;
}
return amount;
}
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
/// @fn DeleteFaction /// @fn DeleteFaction
@ -502,7 +522,6 @@ public class FactionConfig {
System.out.println("ListOfFactions - map size: " + allFactions.size()); System.out.println("ListOfFactions - map size: " + allFactions.size());
for (Entry<String, WriteableFaction> entry : allFactions.entrySet()) { for (Entry<String, WriteableFaction> entry : allFactions.entrySet()) {
System.out.println("Adding fac " + entry.getKey() + " to fac");
facs.add(entry.getKey()); facs.add(entry.getKey());
} }

View File

@ -12,14 +12,15 @@ package jesse.keeblarcraft.FactionMgr;
import java.util.List; import java.util.List;
import jesse.keeblarcraft.ConfigMgr.ConfigManager; import jesse.keeblarcraft.ConfigMgr.ConfigManager;
import jesse.keeblarcraft.Utils.ChatUtil; import jesse.keeblarcraft.MailSystem.MailMgr;
import jesse.keeblarcraft.Utils.ChatUtil.CONSOLE_COLOR; import jesse.keeblarcraft.Keeblarcraft;
import jesse.keeblarcraft.ChatStuff.ChatMsg;
import jesse.keeblarcraft.Utils.CustomExceptions.FILE_WRITE_EXCEPTION; import jesse.keeblarcraft.Utils.CustomExceptions.FILE_WRITE_EXCEPTION;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text; import net.minecraft.text.Text;
public class FactionManager { public class FactionManager {
private static String FACTION_CFG_FILE = "config/keeblarcraft/factions/factions.json"; private static String FACTION_CFG_FILE = "factions/factions.json";
ConfigManager config = new ConfigManager(); ConfigManager config = new ConfigManager();
private static FactionManager static_inst; private static FactionManager static_inst;
@ -62,7 +63,7 @@ public class FactionManager {
config.CreateDirectory(FACTION_CFG_FILE); config.CreateDirectory(FACTION_CFG_FILE);
FlashConfig(); FlashConfig();
} catch (Exception e) { } catch (Exception e) {
System.out.println(ChatUtil.ColoredString("Could not write to file", CONSOLE_COLOR.RED)); Keeblarcraft.LOGGER.error("Could not write to file");
} }
} }
@ -91,8 +92,9 @@ public class FactionManager {
String playerFac = factionConfig.factions.FindFactionOfPlayer(player.getUuidAsString()); String playerFac = factionConfig.factions.FindFactionOfPlayer(player.getUuidAsString());
if (playerFac != "") { if (playerFac != "") {
success = factionConfig.factions.LeaveFaction(playerFac, player.getUuidAsString(), player.getDisplayName().toString()); success = factionConfig.factions.LeaveFaction(playerFac, player.getUuidAsString(), player.getEntityName());
player.sendMessage(Text.of("[Factions]: You left your faction!")); player.sendMessage(Text.of("[Factions]: You left your faction!"));
FlashConfig();
} else { } else {
player.sendMessage(Text.of("[Factions]: You are not in a faction!")); player.sendMessage(Text.of("[Factions]: You are not in a faction!"));
} }
@ -116,7 +118,11 @@ public class FactionManager {
String facOfPlayer = factionConfig.factions.FindFactionOfPlayer(creator.getUuidAsString()); String facOfPlayer = factionConfig.factions.FindFactionOfPlayer(creator.getUuidAsString());
if (facOfPlayer == "") { if (facOfPlayer == "") {
success = factionConfig.factions.CreateFaction(factionName, creator.getUuidAsString(), creator.getDisplayName().toString()); creator.sendMessage(Text.of("Your display name: " + creator.getDisplayName().toString()));
creator.sendMessage(Text.of("Your name: " + creator.getName()));
creator.sendMessage(Text.of("Your custom name: " + creator.getCustomName()));
creator.sendMessage(Text.of("Your entity name: " + creator.getEntityName()));
success = factionConfig.factions.CreateFaction(factionName, creator.getUuidAsString(), creator.getEntityName());
if (!success) { if (!success) {
creator.sendMessage(Text.of("[Factions]: Could not create faction - faction already exists.")); creator.sendMessage(Text.of("[Factions]: Could not create faction - faction already exists."));
@ -180,6 +186,45 @@ public class FactionManager {
return factionConfig.factions.FindFactionOfPlayer(playerUuid); return factionConfig.factions.FindFactionOfPlayer(playerUuid);
} }
public Boolean InvitePlayerToFaction(ServerPlayerEntity caller, String inviteeUuid, String inviteeDisplayName) {
String playerFaction = factionConfig.factions.FindFactionOfPlayer(caller.getUuidAsString());
Boolean success = false;
if (!playerFaction.equals("")) {
success = factionConfig.factions.InvitePlayerToFaction(playerFaction, caller.getUuidAsString(), inviteeUuid);
} else {
caller.sendMessage(Text.of("You aren't in a faction!"));
}
if (success) {
String mailMsg = "You receive a faction invite from " + caller.getEntityName() + "! You can join with /faction join " + playerFaction;
MailMgr.GetInstance().SendMail(inviteeUuid, mailMsg);
}
return success;
}
public Boolean SetFactionPower(ServerPlayerEntity caller, String factionName, Integer amount) {
Boolean success = false;
if (caller.hasPermissionLevel(4)) {
factionConfig.factions.SetPower(factionName, amount);
} else {
caller.sendMessage(Text.of("You do not have permission to use this command"));
}
return success;
}
public Integer GetFactionPower(ServerPlayerEntity caller) {
Integer amount = 0;
String playerFaction = factionConfig.factions.FindFactionOfPlayer(caller.getUuidAsString());
if (!playerFaction.equals("")) {
amount = factionConfig.factions.GetPower(playerFaction);
caller.sendMessage(Text.of("[" + playerFaction + " - POWER]: " + Integer.toString(amount)));
}
return amount;
}
public Boolean PromotePlayer(ServerPlayerEntity caller, String promoteeUuid, String promoteeDisplayName) { public Boolean PromotePlayer(ServerPlayerEntity caller, String promoteeUuid, String promoteeDisplayName) {
Boolean success = factionConfig.factions.PromotePlayer(GetFactionOfPlayer(caller.getUuidAsString()), caller.getUuidAsString(), promoteeUuid, promoteeDisplayName); Boolean success = factionConfig.factions.PromotePlayer(GetFactionOfPlayer(caller.getUuidAsString()), caller.getUuidAsString(), promoteeUuid, promoteeDisplayName);
@ -223,10 +268,6 @@ public class FactionManager {
/// @brief Update the faction configuration file on disk /// @brief Update the faction configuration file on disk
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
public void FlashConfig() { public void FlashConfig() {
try { config.WriteToJsonFile(FACTION_CFG_FILE, factionConfig);
config.WriteToJsonFile(FACTION_CFG_FILE, factionConfig);
} catch (FILE_WRITE_EXCEPTION e) {
System.out.println("config writing of faction file failed. oh well!");
}
} }
} }

View File

@ -0,0 +1,110 @@
package jesse.keeblarcraft.GuiMgr;
import jesse.keeblarcraft.CustomBlocks.BlockEntities.FactionBlockEntity;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.inventory.Inventory;
import net.minecraft.item.ItemStack;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.screen.ArrayPropertyDelegate;
import net.minecraft.screen.PropertyDelegate;
import net.minecraft.screen.ScreenHandler;
import net.minecraft.screen.slot.Slot;
public class FactionBlockScreenHandler extends ScreenHandler {
private final Inventory inventory;
private final PropertyDelegate propertyDelegate;
public final FactionBlockEntity blockEntity;
public int factionPower = 0;
public FactionBlockScreenHandler(int syncId, PlayerInventory inventory, PacketByteBuf buf) {
this(syncId, inventory, inventory.player.getWorld().getBlockEntity(buf.readBlockPos()), new ArrayPropertyDelegate(7));
}
public FactionBlockScreenHandler(int syncId, PlayerInventory playerInventory, BlockEntity blockEntity, PropertyDelegate arrayPropertyDelegate) {
super(ScreenHandlerRegistration.FACTION_BLOCK_SCREEN_HANDLER, syncId);
checkSize((Inventory) blockEntity, 7);
this.inventory = (Inventory) blockEntity;
inventory.onOpen(playerInventory.player);
this.propertyDelegate = arrayPropertyDelegate;
this.blockEntity = (FactionBlockEntity) blockEntity;
// Need a better way of storing these coordinates...
this.addSlot(new Slot(inventory, 0, 20, 11)); // top row
this.addSlot(new Slot(inventory, 1, 20, 39));
this.addSlot(new Slot(inventory, 2, 49, 11));
this.addSlot(new Slot(inventory, 3, 49, 39));
this.addSlot(new Slot(inventory, 4, 78, 11));
this.addSlot(new Slot(inventory, 5, 78, 39));
this.addSlot(new Slot(inventory, 6, 128, 26));
addPlayerInventory(playerInventory);
addPlayerHotbar(playerInventory);
// Need to reference Kaupendim tutorial again; but we could theoretically just add the player inventory
// right here so that they can drag items in and whatnot (I assume). I am unsure if I am taking that
// direction with this block RIGHT NOW - so for now I am NOT doing that
// Remainder stuff
addProperties(arrayPropertyDelegate);
}
public Integer GetFactionPower() {
factionPower = this.propertyDelegate.get(0);
return factionPower;
}
// This is just for SHIFT+CLICK moving
@Override
public ItemStack quickMove(PlayerEntity player, int invSlot) {
ItemStack newStack = ItemStack.EMPTY;
Slot slot = this.slots.get(invSlot);
if (slot != null && slot.hasStack()) {
ItemStack originalStack = slot.getStack();
newStack = originalStack.copy();
// TODO: This is from the YT video and it looks atrocious. Refactor this later
if ( (invSlot < this.inventory.size() && !this.insertItem(originalStack, this.inventory.size(), this.slots.size(), true) ) ||
(!this.insertItem(originalStack, 0, this.inventory.size(), false))) {
return ItemStack.EMPTY;
}
if (originalStack.isEmpty()) {
slot.setStack(ItemStack.EMPTY);
} else {
slot.markDirty();;
}
}
return newStack;
}
// From Kaupenjoe video
private void addPlayerInventory(PlayerInventory playerInventory) {
for (int i = 0; i < 3; ++i) { // Rows
for (int l = 0; l < 9; ++l) { // Columns
// The fancy math (expanded from kaupen video for clarity for me for later) seems to just specify a few things
int index = l + i * 9 + 9; // l = col, i*9 = the row to be on (scaling by 9 bc slots are 1-(9*3) in amount), +9 = where on that row to be!
int x = 8 + l * 18; // Texture draw position on image
int y = 84 + i * 18; // Texture draw position on image
this.addSlot(new Slot(playerInventory, index, x, y));
}
}
}
// From Kaupenjoe video
private void addPlayerHotbar(PlayerInventory playerInventory) {
for (int i = 0; i < 9; ++i) {
int index = i; // Index of hotbar (only 9 slots long in vanilla)
int x = 8 + i * 18; // Texture draw position
int y = 142; // Texture draw position
this.addSlot(new Slot(playerInventory, index, x, y));
}
}
@Override
public boolean canUse(PlayerEntity player) {
return this.inventory.canPlayerUse(player);
}
}

View File

@ -0,0 +1,18 @@
package jesse.keeblarcraft.GuiMgr;
import jesse.keeblarcraft.Keeblarcraft;
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerType;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.util.Identifier;
public class ScreenHandlerRegistration {
public static final ScreenHandlerType<FactionBlockScreenHandler> FACTION_BLOCK_SCREEN_HANDLER =
Registry.register(Registries.SCREEN_HANDLER, new Identifier(Keeblarcraft.MOD_ID, "faction_block"),
new ExtendedScreenHandlerType<>(FactionBlockScreenHandler::new));
public static void registerScreenHandlers() {
Keeblarcraft.LOGGER.info("Registering screen handlers for " + Keeblarcraft.MOD_ID);
}
}

View File

@ -11,9 +11,8 @@ import java.util.HashMap;
import java.util.Map.Entry; import java.util.Map.Entry;
import jesse.keeblarcraft.ConfigMgr.ConfigManager; import jesse.keeblarcraft.ConfigMgr.ConfigManager;
import jesse.keeblarcraft.Utils.ChatUtil; import jesse.keeblarcraft.Keeblarcraft;
import jesse.keeblarcraft.Utils.ChatUtil.CONSOLE_COLOR; import jesse.keeblarcraft.ChatStuff.ChatMsg;
import jesse.keeblarcraft.Utils.CustomExceptions.FILE_WRITE_EXCEPTION;
public class PlayerNote { public class PlayerNote {
/// Class variables /// Class variables
@ -86,21 +85,18 @@ public class PlayerNote {
// In the event the above code failed out, this means a new file has to be created for the player's uuid // In the event the above code failed out, this means a new file has to be created for the player's uuid
if (!existingFile) if (!existingFile)
{ {
System.out.println(ChatUtil.ColoredString("Trying to create new file", CONSOLE_COLOR.BLUE));
try { try {
thisNote.uuid = uuid; thisNote.uuid = uuid;
FlashConfig(); FlashConfig();
} catch (Exception e) { } catch (Exception e) {
System.out.println(ChatUtil.ColoredString("Could not write to file", CONSOLE_COLOR.RED)); Keeblarcraft.LOGGER.warn("Could not write to the player notes file");
} }
} else {
System.out.println(ChatUtil.ColoredString("Moving on", CONSOLE_COLOR.BLUE));
} }
// It's possible the above code will return a blank class if a file doesn't exist. This will make // It's possible the above code will return a blank class if a file doesn't exist. This will make
// a new file with this players uuid // a new file with this players uuid
if ("".equals(thisNote.uuid)) { if ("".equals(thisNote.uuid)) {
System.out.println(ChatUtil.ColoredString("Assigning new config file for this uuid. No previous existing", CONSOLE_COLOR.BLUE)); System.out.println("Assigning new config file for this uuid. No previous existing");
thisNote.uuid = uuid; thisNote.uuid = uuid;
} }
} }
@ -230,10 +226,6 @@ public class PlayerNote {
/// @brief Writes to the configuration file /// @brief Writes to the configuration file
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
public void FlashConfig() { public void FlashConfig() {
try { config.WriteToJsonFile("notes/" + thisNote.uuid + ".json", thisNote);
config.WriteToJsonFile("notes/" + thisNote.uuid + ".json", thisNote);
} catch (FILE_WRITE_EXCEPTION e) {
System.out.println(ChatUtil.ColoredString("Could not flash notes configuration file", CONSOLE_COLOR.RED));
}
} }
} }

View File

@ -13,45 +13,36 @@ package jesse.keeblarcraft;
import net.fabricmc.api.ModInitializer; import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.entity.event.v1.ServerEntityWorldChangeEvents; import net.fabricmc.fabric.api.entity.event.v1.ServerEntityWorldChangeEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerEntityEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents.ServerStopping;
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
import net.kyrptonaught.customportalapi.api.CustomPortalBuilder; import net.kyrptonaught.customportalapi.api.CustomPortalBuilder;
import net.minecraft.block.AbstractBlock;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks; import net.minecraft.block.Blocks;
import net.minecraft.block.entity.BlockEntityType; import net.minecraft.entity.mob.HostileEntity;
import net.minecraft.entity.EntityDimensions;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.item.Items; import net.minecraft.item.Items;
import net.minecraft.registry.Registries; import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry; import net.minecraft.registry.Registry;
import net.minecraft.resource.featuretoggle.FeatureSet; import net.minecraft.resource.featuretoggle.FeatureSet;
import net.minecraft.screen.ScreenHandlerType; import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import jesse.keeblarcraft.AttributeMgr.AttributeMgr; import jesse.keeblarcraft.AttributeMgr.AttributeMgr;
import jesse.keeblarcraft.AttributeMgr.AttributeTree;
import jesse.keeblarcraft.BankMgr.BankManager; import jesse.keeblarcraft.BankMgr.BankManager;
import jesse.keeblarcraft.Commands.CustomCommandManager; import jesse.keeblarcraft.Commands.CustomCommandManager;
import jesse.keeblarcraft.ConfigMgr.SQLUnitTest;
import jesse.keeblarcraft.CustomBlocks.BlockList; import jesse.keeblarcraft.CustomBlocks.BlockList;
// import jesse.keeblarcraft.CustomBlocks.BlockEntities.MagicChestBlockEntity; import jesse.keeblarcraft.CustomBlocks.BlockEntities.BlockEntityRegistration;
// import jesse.keeblarcraft.CustomBlocks.Blocks.MagicChestBlock;
import jesse.keeblarcraft.CustomItems.ItemManager; import jesse.keeblarcraft.CustomItems.ItemManager;
import jesse.keeblarcraft.EventMgr.DimensionLoadingEvent; import jesse.keeblarcraft.EventMgr.DimensionLoadingEvent;
import jesse.keeblarcraft.EventMgr.PlayerJoinListener; import jesse.keeblarcraft.EventMgr.PlayerJoinListener;
import jesse.keeblarcraft.EventMgr.ServerTickListener; import jesse.keeblarcraft.EventMgr.ServerTickListener;
import jesse.keeblarcraft.GuiMgr.ScreenHandlerRegistration;
import jesse.keeblarcraft.GuiMgr.TreeHandler; import jesse.keeblarcraft.GuiMgr.TreeHandler;
import jesse.keeblarcraft.Utils.CustomExceptions.SETUP_FAILED_EXCEPTION; import jesse.keeblarcraft.Utils.CustomExceptions.SETUP_FAILED_EXCEPTION;
import jesse.keeblarcraft.Utils.ChatUtil;
import jesse.keeblarcraft.Utils.Setup; import jesse.keeblarcraft.Utils.Setup;
import jesse.keeblarcraft.Utils.ChatUtil.CONSOLE_COLOR;
public class Keeblarcraft implements ModInitializer { public class Keeblarcraft implements ModInitializer {
public static String MOD_ID = "keeblarcraft"; public static String MOD_ID = "keeblarcraft";
@ -74,28 +65,14 @@ public class Keeblarcraft implements ModInitializer {
@Override @Override
public void onInitialize() { public void onInitialize() {
// This code runs as soon as Minecraft is in a mod-load-ready state.
// However, some things (like resources) may still be uninitialized.
// Proceed with mild caution.
ChatUtil.LoggerColored("Hello Fabric world!", CONSOLE_COLOR.CYAN, LOGGER);
if (setup != null) { if (setup != null) {
try { try {
// Run setup. If setup fails; it throws SETUP_FAILED_EXCEPTION // Run setup. If setup fails; it throws SETUP_FAILED_EXCEPTION
LOGGER.info("\033[34m Running setup stage \033[0m"); LOGGER.info("Running setup");
setup.RunSetup(); setup.RunSetup();
// This is a very special case where this must be in this classes' initializer /// TODO: Move callbacks somewhere else
// method
ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> { ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> {
// var player = handler.player;
// Keeblarcraft.LOGGER.info("Player " + player.getName() + " has logged in. Creating tree...");
// player.sendMessage(Text.of("Welcome to the Keeblcraft RPG Server!"));
// if (AttributeMgr.activeTrees.containsKey(player.getUuidAsString()) == false) {
// AttributeMgr.activeTrees.put(player.getUuidAsString(), new AttributeTree(player.getUuidAsString()));
// }
System.out.println("ServerPlayConnectionEvents.JOIN called"); System.out.println("ServerPlayConnectionEvents.JOIN called");
PlayerJoinListener.GetInstance().HandleServerJoinEvent(handler, sender, server); PlayerJoinListener.GetInstance().HandleServerJoinEvent(handler, sender, server);
}); });
@ -114,12 +91,22 @@ public class Keeblarcraft implements ModInitializer {
DimensionLoadingEvent.GetInstance().HandleWorldMove(player, origin, destination); DimensionLoadingEvent.GetInstance().HandleWorldMove(player, origin, destination);
}); });
ServerLifecycleEvents.SERVER_STOPPING.register((server) ->{ ServerLifecycleEvents.SERVER_STOPPING.register((server) -> {
// Stuff here // Stuff here
System.out.println("SERVER_STOPPING callback called."); System.out.println("SERVER_STOPPING callback called.");
DimensionLoadingEvent.GetInstance().SaveInventories(); DimensionLoadingEvent.GetInstance().SaveInventories();
}); });
ServerEntityEvents.ENTITY_LOAD.register((entity, world) -> {
// System.out.println("ENTITY LOAD EVENT INFORMATION");
// System.out.println("Name: " + entity.getEntityName());
// System.out.println("World: " + world.asString());
// System.out.println("COORDS: " + entity.getX() + " " + entity.getY() + " " + entity.getZ());
// System.out.println("TYPE: " + entity.getType());
// System.out.println("SPAWN GROUP: " + entity.getType().getSpawnGroup().asString());
// System.out.println("Is hostile? " + (entity instanceof HostileEntity ? "YES":"NO"));
});
// Initialize our ticks!! // Initialize our ticks!!
ServerTickListener.InitializeServerTicks(); ServerTickListener.InitializeServerTicks();
@ -133,6 +120,10 @@ public class Keeblarcraft implements ModInitializer {
// Register the banking system // Register the banking system
BankManager.GetInstance().InitializeBanks(); BankManager.GetInstance().InitializeBanks();
System.out.println("Attempting SQL Registration call");
SQLUnitTest sqlTests = new SQLUnitTest();
sqlTests.RunTests();
/// THE BELOW ITEMS MUST BE DONE LAST IN THE STEPS /// THE BELOW ITEMS MUST BE DONE LAST IN THE STEPS
// Register items // Register items
@ -140,6 +131,7 @@ public class Keeblarcraft implements ModInitializer {
// Register blocks // Register blocks
BlockList.RegisterBlocks(); BlockList.RegisterBlocks();
BlockEntityRegistration.RegisterBlockEntities();
// World generation // World generation
@ -152,14 +144,17 @@ public class Keeblarcraft implements ModInitializer {
.tintColor(234, 183, 8) .tintColor(234, 183, 8)
.registerPortal(); .registerPortal();
// Screen handlers
ScreenHandlerRegistration.registerScreenHandlers();
} catch (SETUP_FAILED_EXCEPTION e) { } catch (SETUP_FAILED_EXCEPTION e) {
System.out.println(ChatUtil.ColoredString("ERROR. Setup failed to initialize environment. Mod likely does not have read/write permissions inside area. Mod will now close out.", CONSOLE_COLOR.RED)); Keeblarcraft.LOGGER.error("ERROR. Setup failed to initialize environment. Mod likely does not have read/write permissions inside area. Mod will now close out.");
e.printStackTrace(); e.printStackTrace();
} }
} else { } else {
// Program exit. Dual definition of setup somehow happened! // Program exit. Dual definition of setup somehow happened!
System.out.println(ChatUtil.ColoredString("Dual definition of singleton attempted! Out of order initialization? How did this even happen?", CONSOLE_COLOR.RED)); Keeblarcraft.LOGGER.error("Dual definition of singleton attempted! Out of order initialization? How did this even happen?");
} }
} }
} }

View File

@ -0,0 +1,81 @@
package jesse.keeblarcraft.MailSystem;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import jesse.keeblarcraft.ConfigMgr.ConfigManager;
public class MailMgr {
ConfigManager config = new ConfigManager();
MailConfigClass mailConfig;
String CONFIG_FILE = "mail/player_mail.json";
private static MailMgr static_inst;
public static MailMgr GetInstance() {
if (static_inst == null) {
static_inst = new MailMgr();
}
return static_inst;
}
private class MailConfigClass {
private HashMap<String, ArrayList<String>> mailList = new HashMap<String, ArrayList<String>>();
}
public MailMgr() {
System.out.println("Mail manager called");
Boolean existingFile = false;
try {
mailConfig = config.GetJsonObjectFromFile(CONFIG_FILE, MailConfigClass.class);
existingFile = true;
} catch (Exception e) {
System.out.println("Mail config could not correctly parse json file or it did not exist");
}
if (!existingFile) {
try {
config.CreateFile(CONFIG_FILE);
} catch (Exception e) {
System.out.println("Failed to correctly make or parse mail config file");
}
}
}
public void SendMail(String playerUuid, String mail) {
if (mailConfig != null) {
if (mailConfig.mailList.containsKey(playerUuid)) {
mailConfig.mailList.get(playerUuid).add(mail);
} else {
mailConfig.mailList.put(playerUuid, new ArrayList<>(Arrays.asList(mail)));
}
} else {
System.out.println("Mail config is null. Cannot send");
}
}
public List<String> GetMail(String playerUuid) {
List<String> mail = null;
if (mailConfig.mailList.containsKey(playerUuid)) {
mail = mailConfig.mailList.get(playerUuid);
}
return mail;
}
public void ClearMail(String playerUuid) {
if (mailConfig != null && mailConfig.mailList.containsKey(playerUuid)) {
mailConfig.mailList.remove(playerUuid);
}
}
public void FlashConfig() {
if (mailConfig != null) {
try {
config.WriteToJsonFile(CONFIG_FILE, mailConfig);
} catch (Exception e) {
System.out.println("Could not flash mail config");
}
}
}
}

View File

@ -1,152 +0,0 @@
/*
*
* ChatUtil
*
* Helpful utility for pretty printing in chat in the game with different supported functions and levels
*
*/
package jesse.keeblarcraft.Utils;
import org.slf4j.Logger;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
public class ChatUtil {
//This is a private class only used internally to get ANSI colors
private static class ConsoleColor {
public static String getColor(CONSOLE_COLOR color) {
String ret = "";
switch(color) {
case RED:
ret = "31";
break;
case GREEN:
ret = "32";
break;
case YELLOW:
ret = "33";
break;
case BLUE:
ret = "34";
break;
case MAGENTA:
ret = "35";
break;
case CYAN:
ret = "36";
break;
}
return ret;
}
}
public static enum CONSOLE_COLOR {
RED,
GREEN,
YELLOW,
BLUE,
MAGENTA,
CYAN;
}
static int CHATBOX_WIDTH_CHARS = 80; // Maximum length of the textbox in individual characters
// Helpful print wrapper function
static public void SendPlayerMsg(ServerPlayerEntity player, String text) {
player.sendMessage(Text.literal(text));
}
/// TODO: Add this back in later under a chat ticket
// Prints a table of data in chat
// static public void ChatBlock(ServerPlayerEntity player, HashMap<Text, List<Text>> table) {
// ///DEBUG
// for (Entry<Text, List<Text>> entry : table.entrySet()) {
// for (int debug = 0; debug < entry.getValue().size(); debug++) {
// System.out.println("KEY: " + entry.getKey().toString() + " VALUE: " + entry.getValue().get(debug).toString());
// }
// }
// // The user will likely pass in text strings longer than the character limit for num of columns; therefore
// // we are required to split these into this finalPrintList structure
// HashMap<Text, ArrayList<Text>> finalPrintList = new HashMap<Text, ArrayList<Text>>();
// int maxColumnWidth = CHATBOX_WIDTH_CHARS / table.size(); // Represents max char allowance per data column
// maxColumnWidth -= table.size(); // Represents a separating '|' between each column
// // This first behemoth of a loop is to take the given table hashmap and look at
// // the Text values & split them
// // should their size exceed the maxColumnWidth given for each entry key
// System.out.println("Entry data is size " + table.size());
// for (Entry<Text, List<Text>> entry : table.entrySet()) {
// // Each text line found cannot be longer than "maxColumnWidth" or else it must
// // wrap which splits it
// // into two texts; thus adding an additional row that is required for iteration.
// // Each split text must
// // maintain the same formatting as the root text it is split from
// finalPrintList.put(entry.getKey(), new ArrayList<Text>()); // Instantiate the key & array
// System.out.println("Map size is " + finalPrintList.size());
// System.out.println("Entry value size is " + entry.getValue().size());
// for (Text item : entry.getValue()) {
// int numItems = (int) Math.ceil((item.getString().length() / maxColumnWidth));
// int strOffset = numItems; // Represents number of items per string
// System.out.println("numItems: " + numItems);
// System.out.println("strOffset: " + strOffset);
// for (int offset = 0; offset <= numItems; offset++) { /// TODO: might need to be <=
// int start = strOffset * offset; // Multiple from start of string to needed point
// int end = start + strOffset; // The original start offset + the width spacer
// String substr = item.toString().substring(start, end); // Contains the string to be Textified
// MutableText newText = Text.literal(substr).setStyle(item.getStyle());
// finalPrintList.get(entry.getKey()).add(newText); // Add back into list
// System.out.println("SPLIT DEBUG: " + newText.toString());
// }
// }
// }
// // This loop does the printing of the table in chat
// int tempPreventInfiniteLoops = 10;
// while (finalPrintList.size() != 0) {
// // This is a one time print
// MutableText line = Text.literal("");
// for (Entry<Text, ArrayList<Text>> entry : finalPrintList.entrySet()) {
// if (entry.getValue().size() != 0) {
// line.append(entry.getValue().get(0));
// System.out.println("new line is now " + line.toString());
// line.append("|");
// } else {
// finalPrintList.remove(entry.getKey()); // Clear the key; as we are done with this column for
// // printing
// }
// player.sendMessage(line);
// String debugPrint = line.toString();
// System.out.println("Debug line to be printed: " + debugPrint);
// line = Text.literal("");
// break;
// }
// tempPreventInfiniteLoops--;
// if (tempPreventInfiniteLoops <= 0) {
// return;
// }
// }
// }
// Returns a string with the proper ANSI encoding for the specified CONSOLE_COLOR
static public String ColoredString(String msg, CONSOLE_COLOR color) {
return "\033[" + ConsoleColor.getColor(color) + "m" + msg + "\033[0m";
}
// Takes in a (already initialized) logger object and prints to console
static public void LoggerColored(String msg, CONSOLE_COLOR color, Logger logger) {
logger.info(ColoredString(msg, color));
}
}

View File

@ -0,0 +1,26 @@
package jesse.keeblarcraft.Utils.CommonStructures;
public class Pair<KEY, VALUE> {
KEY key;
VALUE value;
public Pair(KEY key, VALUE val) {
this.key = key;
this.value = val;
}
public KEY GetKey() {
return key;
}
public VALUE GetValue() {
return value;
}
public void SetKey(KEY newKey) {
this.key = newKey;
}
public void SetValue(VALUE newValue) {
this.value = newValue;
}
}

View File

@ -0,0 +1,26 @@
package jesse.keeblarcraft.Utils;
import com.mojang.brigadier.context.CommandContext;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
public class PlayerChecks {
public static Boolean HasPermission(CommandContext<ServerCommandSource> context) {
if (context.getSource().isExecutedByPlayer() && HasPermission(context.getSource().getPlayer())) {
return true;
} else {
return false;
}
}
public static Boolean HasPermission(ServerPlayerEntity player) {
if (player.hasPermissionLevel(4)) {
return true;
} else {
player.sendMessage(Text.of("You do not have permission to use this command."));
return false;
}
}
}

View File

@ -14,9 +14,8 @@ import java.util.List;
import java.util.ArrayList; import java.util.ArrayList;
import jesse.keeblarcraft.Keeblarcraft;
import jesse.keeblarcraft.ConfigMgr.ConfigManager; import jesse.keeblarcraft.ConfigMgr.ConfigManager;
import jesse.keeblarcraft.Utils.ChatUtil.CONSOLE_COLOR;
import jesse.keeblarcraft.Utils.CustomExceptions.DIRECTORY_CREATE_EXCEPTION;
import jesse.keeblarcraft.Utils.CustomExceptions.SETUP_FAILED_EXCEPTION; import jesse.keeblarcraft.Utils.CustomExceptions.SETUP_FAILED_EXCEPTION;
// Singleton class is designed to help the mod set itself up and create all the important things. It does two things: // Singleton class is designed to help the mod set itself up and create all the important things. It does two things:
@ -32,9 +31,7 @@ public final class Setup {
private static Setup static_inst; private static Setup static_inst;
private static String GLOBAL_CONFIG = "config/keeblarcraft/"; private static String GLOBAL_CONFIG = "config/keeblarcraft/";
public Setup() { public Setup() {}
System.out.println(ChatUtil.ColoredString("Running system setup and checks...", CONSOLE_COLOR.BLUE));
}
// Returns the singleton object // Returns the singleton object
public static Setup GetInstance() { public static Setup GetInstance() {
@ -51,24 +48,23 @@ public final class Setup {
// First time setup variables // First time setup variables
private static final List<String> DIRECTORY_LIST = new ArrayList<String>() {{ private static final List<String> DIRECTORY_LIST = new ArrayList<String>() {{
add(GLOBAL_CONFIG); // inside config dir add("notes"); // Expect 1 file per player!
add(GLOBAL_CONFIG + "notes"); // Expect 1 file per player! add("factions"); // Expect 1 file per faction!
add(GLOBAL_CONFIG + "factions"); // Expect 1 file per faction! add("story"); // Expect 1 file per story chapter!
add(GLOBAL_CONFIG + "story"); // Expect 1 file per story chapter! add("commands"); // Expect 1 file per command that's configurable!
add(GLOBAL_CONFIG + "commands"); // Expect 1 file per command that's configurable! add("events"); // Expect 1 file per event that is configurable!
add(GLOBAL_CONFIG + "events"); // Expect 1 file per event that is configurable! add("bank");
add(GLOBAL_CONFIG + "bank"); add("attributes");
add(GLOBAL_CONFIG + "attributes"); add("misc");
add(GLOBAL_CONFIG + "misc");
}}; }};
// These will be top-level config files above the directories this mod creates // These will be top-level config files above the directories this mod creates
private static final List<String> FILE_LIST = new ArrayList<String>() {{ private static final List<String> FILE_LIST = new ArrayList<String>() {{
add(GLOBAL_CONFIG + "story/general_story_config.json"); // Big config file, determines when players can do certain things at different story levels add("story/general_story_config.json"); // Big config file, determines when players can do certain things at different story levels
add(GLOBAL_CONFIG + "factions/general_factions_config.json"); // General configuration file for factions stuff add("factions/general_factions_config.json"); // General configuration file for factions stuff
add(GLOBAL_CONFIG + "events/general_event_config.json"); // General configuration file for story events! add("events/general_event_config.json"); // General configuration file for story events!
add(GLOBAL_CONFIG + "general.json"); // The super general configuration file! (May be removed) add("general.json"); // The super general configuration file! (May be removed)
add(GLOBAL_CONFIG + "attributes/general_attribute_config.json"); add("attributes/general_attribute_config.json");
}}; }};
// RunChecks() // RunChecks()
@ -80,45 +76,32 @@ public final class Setup {
ConfigManager conf = new ConfigManager(); ConfigManager conf = new ConfigManager();
// Create directory check // Create directory check
try { has_write = conf.CreateDirectory("test_dir");
has_write = conf.CreateDirectory("test_dir");
System.out.println(ChatUtil.ColoredString("test_dir created! has write: ", CONSOLE_COLOR.GREEN) + (has_write ? ChatUtil.ColoredString("YES", CONSOLE_COLOR.YELLOW) : ChatUtil.ColoredString("NO", CONSOLE_COLOR.YELLOW)));
} catch (DIRECTORY_CREATE_EXCEPTION e) {
System.out.println(ChatUtil.ColoredString("Failed to create test directory or it already exists", CONSOLE_COLOR.MAGENTA));
has_write = false;
}
// Write to disk then read that data back if (!has_write) {
if (has_write) { Keeblarcraft.LOGGER.error("Uh oh! It appears we could not successfully identify that we have write permissions. Attempt to create a directory failed.");
try { } else {
has_write = conf.CreateFile("test_dir/test_note.txt"); has_write = conf.CreateFile("test_dir/test_note.txt");
has_write = conf.WriteToFile("test_dir/test_note.txt", "test_write_read", "w"); has_write = conf.WriteToFile("test_dir/test_note.txt", "test_write_read", "w");
List<String> lines = conf.GetFile("test_dir/test_note.txt"); List<String> lines = conf.GetFileLines("test_dir/test_note.txt");
if (lines.size() == 0) { if (lines.size() == 0) {
has_read = false;
} else {
has_read = true;
}
} catch (Exception e) {
System.out.println(ChatUtil.ColoredString("Failed to create or write to test dir file ", CONSOLE_COLOR.RED));
has_read = false; has_read = false;
} else {
has_read = true;
}
has_write = conf.DeleteFile("test_dir/test_note.txt");
has_write = conf.DeleteDirectory("test_dir");
if (!has_write) {
Keeblarcraft.LOGGER.error("Uh oh! It appears we lost the ability to write or delete files after making one. Something is seriously wrong!");
} }
} }
// Delete directory if created (it's a temporary dir) Keeblarcraft.LOGGER.debug("CHECKS DEBUG: Value of has_write: "+has_write.toString()+". Value of has_read: "+has_read.toString());
if (has_write) { // return has_write && has_read;
try { return true; /// TODO: ConfigManager has been rewritten so much that the above code is out dated. Fix later return true for now
has_write = conf.DeleteFile("test_dir/test_note.txt");
has_write = conf.DeleteDirectory("test_dir");
} catch (Exception e) {
System.out.println(ChatUtil.ColoredString("Lost access to writing mid-way", CONSOLE_COLOR.RED));
has_write = false;
}
}
//need to be able to take in raw booleans for coloredstrings functions
System.out.println(ChatUtil.ColoredString("CHECKS DEBUG: Value of has_write: ", CONSOLE_COLOR.BLUE) + ChatUtil.ColoredString(has_write.toString(), CONSOLE_COLOR.YELLOW) + ChatUtil.ColoredString(". Value of has_read: ", CONSOLE_COLOR.BLUE) + ChatUtil.ColoredString(has_read.toString(), CONSOLE_COLOR.YELLOW));
return has_write && has_read;
} }
// RunSetup // RunSetup
@ -135,9 +118,9 @@ public final class Setup {
for (Integer i = 0; i < DIRECTORY_LIST.size(); i++) { for (Integer i = 0; i < DIRECTORY_LIST.size(); i++) {
if ( ! conf.DoesDirectoryExist(DIRECTORY_LIST.get(i))) { if ( ! conf.DoesDirectoryExist(DIRECTORY_LIST.get(i))) {
conf.CreateDirectory(DIRECTORY_LIST.get(i)); conf.CreateDirectory(DIRECTORY_LIST.get(i));
System.out.println(ChatUtil.ColoredString("Creating directory ", CONSOLE_COLOR.GREEN) + ChatUtil.ColoredString(DIRECTORY_LIST.get(i), CONSOLE_COLOR.YELLOW) + ChatUtil.ColoredString("...", CONSOLE_COLOR.GREEN)); Keeblarcraft.LOGGER.debug("Creating directory " + DIRECTORY_LIST.get(i));
} else { } else {
System.out.println(ChatUtil.ColoredString("Directory ", CONSOLE_COLOR.BLUE) + conf.DoesDirectoryExist(DIRECTORY_LIST.get(i)) + ChatUtil.ColoredString(" already exists. Skipping... ", CONSOLE_COLOR.BLUE)); Keeblarcraft.LOGGER.debug(DIRECTORY_LIST.get(i) + " already exists. Skipping creation.");
} }
} }
@ -145,20 +128,20 @@ public final class Setup {
for (Integer i = 0; i < FILE_LIST.size(); i++) { for (Integer i = 0; i < FILE_LIST.size(); i++) {
if ( ! conf.DoesFileExist(FILE_LIST.get(i))) { if ( ! conf.DoesFileExist(FILE_LIST.get(i))) {
conf.CreateFile(FILE_LIST.get(i)); conf.CreateFile(FILE_LIST.get(i));
System.out.println(ChatUtil.ColoredString("Creating file ", CONSOLE_COLOR.GREEN) + ChatUtil.ColoredString(FILE_LIST.get(i), CONSOLE_COLOR.YELLOW) + ChatUtil.ColoredString("...", CONSOLE_COLOR.GREEN)); Keeblarcraft.LOGGER.debug("Creating file " + DIRECTORY_LIST.get(i));
} else { } else {
System.out.println(ChatUtil.ColoredString("File ", CONSOLE_COLOR.BLUE) + conf.DoesDirectoryExist(FILE_LIST.get(i)) + ChatUtil.ColoredString(" already exists. Skipping...", CONSOLE_COLOR.BLUE)); Keeblarcraft.LOGGER.debug(DIRECTORY_LIST.get(i) + " already exists. Skipping creation.");
} }
} }
} catch (Exception e) { } catch (Exception e) {
throw new SETUP_FAILED_EXCEPTION(); throw new SETUP_FAILED_EXCEPTION();
} }
} else { } else {
System.out.println(ChatUtil.ColoredString("RunChecks() failed in its process. This mod has deemed it does not have read or write privileges in its hosted area and will now exit.", CONSOLE_COLOR.RED)); Keeblarcraft.LOGGER.error("The setup phase failed in its processing and has determined it does not have necessary read or write priviliges in this hosted area and will now exit.");
throw new SETUP_FAILED_EXCEPTION(); throw new SETUP_FAILED_EXCEPTION();
} }
System.out.println(ChatUtil.ColoredString("DID SETUP COMPLETE SUCCESSFULLY? ", CONSOLE_COLOR.YELLOW) + (ret ? ChatUtil.ColoredString("YES", CONSOLE_COLOR.YELLOW) : ChatUtil.ColoredString("NO", CONSOLE_COLOR.YELLOW))); Keeblarcraft.LOGGER.debug("DID SETUP COMPLETE SUCCESSFULLY? " + (ret ? "YES":"NO"));
return ret; return ret;
} }

View File

@ -0,0 +1,25 @@
package jesse.keeblarcraft.datagen;
import jesse.keeblarcraft.CustomBlocks.BlockManager;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricModelProvider;
import net.minecraft.data.client.BlockStateModelGenerator;
import net.minecraft.data.client.ItemModelGenerator;
public class KeeblarModelProvider extends FabricModelProvider {
public KeeblarModelProvider(FabricDataOutput output) {
super(output);
}
@Override
public void generateBlockStateModels(BlockStateModelGenerator blockStateModelGenerator) {
blockStateModelGenerator.registerSimpleState(BlockManager.GetBlock("faction_base_block"));
}
@Override
public void generateItemModels(ItemModelGenerator itemModelGenerator) {
}
}

View File

@ -0,0 +1,30 @@
package jesse.keeblarcraft.mixin;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import net.minecraft.entity.Entity;
import net.minecraft.network.packet.c2s.play.PlayerInteractEntityC2SPacket;
import net.minecraft.server.network.ServerPlayNetworkHandler;
@Mixin(targets = "net.minecraft.server.network.ServerPlayNetworkHandler$1")
public abstract class PlayerEntityInteractionHandler implements PlayerInteractEntityC2SPacket.Handler {
// Unsure what @Shadow is doing, but I'm sure fabric wiki can explain
// @Shadow(aliases = "field_28963") @Final private ServerPlayNetworkHandler field_28963; // I assume this is just a bad named field which is the ServerPlayNetworkHandler
// @Shadow(aliases = "field_28962") @Final private Entity field_28962; // I assume this is just a bad named field which is the Entity in question depending on the function
// // Probably not required for a tool since this is hitting, but you would need to check this if you DID want to make a longer reaching sword or something. Attack is
// // in PlayerEntity but this mixin targets the server handler because the server dictates hitting between stuff
// @Inject(method = "attack()V", at = @At("HEAD"), require = 1, allow = 1, cancellable = true)
// private void isActuallyInHitRange(final CallbackInfo callback) {
// // All we are doing in this class is telling the 'attack' function to return false immediately if the two entities are not within a squared distance of each other.
// // 100 hard coded because value of hit range is hard coded '10' in the ClientPlayerInteractionManagerMixin in the client section (10^2)
// if (!(this.field_28963.player.squaredDistanceTo(this.field_28962) <= 100)) { // 10^2 becauses 10 blocks chosen in Client mixin
// callback.cancel();
// }
// }
}

View File

@ -0,0 +1,56 @@
package jesse.keeblarcraft.mixin;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import jesse.keeblarcraft.Keeblarcraft;
import net.minecraft.entity.ItemEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
// MIXIN CHEAT SHEET:
// https://wiki.fabricmc.net/tutorial:mixin_examples
// Tutorial I referenced for this knowledge (outside fabric wiki): https://www.youtube.com/watch?v=HQUkWjMWTik
// MAKE SURE YOU READ fabric_mod.json and the keeblarcraft.mixin.json!! These injections are not instantiated anywhere else because mixins are special
// because all this code is essentially injected (pasted) into their respective areas during compilation.
//
// PLEASE SEE https://wiki.fabricmc.net/tutorial:mixin_injects FOR ALL THE PARAMETER TYPES OF INJECTION (you will likely have a question about all the types after reading
// bullet point #3 in the below injection explanation because I only explain 'Z' in that case)
@Mixin(PlayerEntity.class)
// *THIS* CLASS MUST BE ABSTRACT - BUT NOT TRUE FOR EVERY MIXIN
public abstract class PlayerMixin {
// Example 0: Base injection (HEAD)
// EXPLANATION OF THI MAGIC STRING:
// This string MUST be written as so; BUT - it's not so bad! It has logic to it - obviously. Some known, some still a bit not
// 1. 'dropItem' is the method we are overriding, and then we are just specifying exactly (which is required) where that method is at
// 2. 'Lnet/minecraft/item/ItemStack' -> First argument inside method we are injecting in. In this case, the argument is an object 'ItemStack' so we specify
// that this is the net/minecraft/item/ItemStack type. WHY THE 'L' AT START? Don't know - but it's used in EVERY example
// so it can be assumed you always need it. It's consistently there, so not a huge deal.
// 3. The 'ZZ' here are the other parameters inside the method which are java defaults - 'Z' happens to stand for boolean. It seems semicolons aren't needed
// between defaults since it just goes 'ZZ' and the parameter finishes with two booleans. Please CTRL+CLICK into the PlayerEntity class and search for 'dropItem' to
// familiarize yourself with the signature of the function.
// 4. The appending 'Lnet/minecraft/entity/ItemEntity' is the RETURN TYPE of this method
// 5. WHAT IS THE 'at = @At' syntax? Well; it is VERY Helpful to familiarize yourself with some areas on the fabric cheat sheet (https://wiki.fabricmc.net/tutorial:mixin_examples)
// but to give a brief explanation of it - it's just WHERE you are injecting your code at inside this function. 'HEAD' means the very top. 'TAIL' means at the end. There also
// is ways to inject by some offset into the function, and whatever a 'slice' is but I'm not looking at those right now. You get the idea
// 6. WHAT IS THE 'cancellable = true'
@Inject(method = "dropItem(Lnet/minecraft/item/ItemStack;ZZ)Lnet/minecraft/entity/ItemEntity;", at = @At("HEAD"), cancellable = true)
// THE METHOD CAN BE CALLED WHATEVER - But make sure it takes in the same parameters as the method you are mixing into ('mixin')
// 1. What's the 'CallbackInfoReturnable<ItemEntity> cir' here? This can be the item we return with inside our injection. You need to picture the code in this
// function as literally being copied+pasted into what you are injecting into (at the 'HEAD', in this case).
// 2. Why is this function 'void' if dropItem is not? -> The last parameter actually covers this case if we need to return but it's not required - remember this is a copy and
// paste of code into the function itself so it's not really relevant that our MIXIN function here returns anything
public void dropItem0(ItemStack stack, boolean throwRandomly, boolean retainOwnership, CallbackInfoReturnable<ItemEntity> cir) {
// WHY THE CAST LIKE THIS?
// This is the starting work required to get 'this' from the perspective of PlayerEntity
// 1. Remember that 'this' is actually NOT the PlayerEntity class, but we want to use the methods and functions from that class
// 2. Casting (Object) 'this' gets us the 'PlayerMixin' class as a general object that we can cast into anything else
// 3. Casting '(Object) this' into 'PlayerEntity' gets us to the mixin inject - and NOW we can store the result of this cast into the type we want as a reference
// which is the 'PlayerEntity' on the left hand side. Now we can access stuff from that class AS IF WE ARE CODING INSIDE OF THAT CLASS :)))
PlayerEntity player = (PlayerEntity) (Object) this;
Keeblarcraft.LOGGER.info("PLAYER MIXIN: " + player.getEntityName());
}
}

View File

@ -0,0 +1,40 @@
package jesse.keeblarcraft.mixin;
import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Constant;
import org.spongepowered.asm.mixin.injection.ModifyConstant;
import org.spongepowered.asm.mixin.injection.Redirect;
import net.minecraft.network.listener.ServerPlayPacketListener;
import net.minecraft.server.network.ServerPlayNetworkHandler;
@Mixin(ServerPlayNetworkHandler.class)
public abstract class ServerPlayNetworkHandlerMixin implements ServerPlayPacketListener {
// Truth be told not required for a pickaxe or tool probably
// @Redirect(
// method = "onPlayerInteractEntity(Lnet/minecraft/network/packet/c2s/play/PlayerInteractEntityC2SPacket;)V",
// at = @At(value = "FIELD", target = "Lnet/minecraft/server/network/ServerPlayNetworkHandler;MAX_BREAK_SQUARED_DISTANCE:D", opcode = Opcodes.GETSTATIC))
// private double getActualAttackRange() {
// return 100; // 10^2 becauses 10 blocks chosen in Client mixin
// }
// // Essentially replaces the 'MAX_BREAK_SQUARED_DISTANCE' value with the value we have in the function (100), or 10 blocks which bc 10^2
// @Redirect(
// method = "onPlayerInteractBlock(Lnet/minecraft/network/packet/c2s/play/PlayerInteractBlockC2SPacket;)V",
// at = @At(value = "FIELD", target = "Lnet/minecraft/server/network/ServerPlayNetworkHandler;MAX_BREAK_SQUARED_DISTANCE:D", opcode = Opcodes.GETSTATIC))
// private double getActualReachDistance() {
// return 100; // 10^2 becauses 10 blocks chosen in Client mixin
// }
// // Search '64' inside the same onPlayerInteractBlock, would also need to replace that value maybe. This is in the github reference for that block breaking
// // im not 100% sure what this is doing. If it's squared then sqrt(64) = 8 blocks but I'm not sure what 8 would represent here.
// @ModifyConstant(
// method = "onPlayerInteractBlock(Lnet/minecraft/network/packet/c2s/play/PlayerInteractBlockC2SPacket;)V",
// require = 1, allow = 1, constant = @Constant(doubleValue = 64.0))
// private double getActualReachDistance(final double reachDistance) {
// return 100; // 10^2 becauses 10 blocks chosen in Client mixin
// }
}

View File

@ -0,0 +1,24 @@
package jesse.keeblarcraft.mixin;
import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.network.ServerPlayerInteractionManager;
// This class is needed to validate the actual block breaking
@Mixin(ServerPlayerInteractionManager.class)
public abstract class ServerPlayerInteractionManagerMixin {
// @Shadow @Final protected ServerPlayerEntity player;
// @Redirect(
// method = "processBlockBreakingAction",
// at = @At(value = "FIELD", target = "Lnet/minecraft/server/network/ServerPlayNetworkHandler;MAX_BREAK_SQUARED_DISTANCE:D", opcode = Opcodes.GETSTATIC))
// private double getActualReachDistance() {
// return 100; // 10^2 becauses 10 blocks chosen in Client mixin
// }
}

View File

@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "keeblarcraft:block/faction_base_block"
}
}
}

View File

@ -9,6 +9,7 @@
"block.keeblarcraft.example_block": "Keeblarcraft example block", "block.keeblarcraft.example_block": "Keeblarcraft example block",
"block.keeblarcraft.example_block_ore": "Keeblarcraft example block ore", "block.keeblarcraft.example_block_ore": "Keeblarcraft example block ore",
"block.keeblarcraft.example_statue": "Keeblarcraft example statue", "block.keeblarcraft.example_statue": "Keeblarcraft example statue",
"block.keeblarcraft.faction_base_block": "Factions Base Block",
"category.keeblarcraft.test": "Keeblarcraft bindings", "category.keeblarcraft.test": "Keeblarcraft bindings",
"key.keeblarcraft.treemap": "Tree GUI", "key.keeblarcraft.treemap": "Tree GUI",

View File

@ -0,0 +1,232 @@
{
"credit": "Made with Blockbench",
"texture_size": [64, 64],
"textures": {
"0": "keeblarcraft:block/faction_base_block",
"particle": "keeblarcraft:block/faction_base_block"
},
"elements": [
{
"from": [12, 0, 2],
"to": [14, 3, 14],
"rotation": {"angle": 0, "axis": "y", "origin": [2, 0, 2]},
"faces": {
"north": {"uv": [2, 6, 2.5, 6.75], "texture": "#0"},
"east": {"uv": [2.5, 2, 5.5, 2.75], "texture": "#0"},
"south": {"uv": [6, 3.25, 6.5, 4], "texture": "#0"},
"west": {"uv": [2.5, 2.75, 5.5, 3.5], "texture": "#0"},
"up": {"uv": [3, 8, 2.5, 5], "texture": "#0"},
"down": {"uv": [3.5, 5, 3, 8], "texture": "#0"}
}
},
{
"from": [2, 0, 2],
"to": [4, 3, 14],
"rotation": {"angle": 0, "axis": "y", "origin": [-8, 0, 2]},
"faces": {
"north": {"uv": [5.75, 6, 6.25, 6.75], "texture": "#0"},
"east": {"uv": [2.5, 3.5, 5.5, 4.25], "texture": "#0"},
"south": {"uv": [0, 6.25, 0.5, 7], "texture": "#0"},
"west": {"uv": [0, 4.25, 3, 5], "texture": "#0"},
"up": {"uv": [4, 8, 3.5, 5], "texture": "#0"},
"down": {"uv": [4.5, 5, 4, 8], "texture": "#0"}
}
},
{
"from": [7, 0, 5],
"to": [9, 2, 11],
"rotation": {"angle": 0, "axis": "y", "origin": [-3, 0, 3]},
"faces": {
"north": {"uv": [1.5, 6.25, 2, 6.75], "texture": "#0"},
"east": {"uv": [4.5, 5, 6, 5.5], "texture": "#0"},
"south": {"uv": [6.25, 4.5, 6.75, 5], "texture": "#0"},
"west": {"uv": [5.5, 2, 7, 2.5], "texture": "#0"},
"up": {"uv": [6, 4, 5.5, 2.5], "texture": "#0"},
"down": {"uv": [5, 5.5, 4.5, 7], "texture": "#0"}
}
},
{
"from": [3, 5, 4],
"to": [13, 7, 12],
"rotation": {"angle": 0, "axis": "y", "origin": [7, 5, 7]},
"faces": {
"north": {"uv": [5, 0, 7.5, 0.5], "texture": "#0"},
"east": {"uv": [5, 1, 7, 1.5], "texture": "#0"},
"south": {"uv": [5, 0.5, 7.5, 1], "texture": "#0"},
"west": {"uv": [5, 1.5, 7, 2], "texture": "#0"},
"up": {"uv": [2.5, 2, 0, 0], "texture": "#0"},
"down": {"uv": [2.5, 2, 0, 4], "texture": "#0"}
}
},
{
"from": [3, 1, 4],
"to": [13, 5, 7],
"rotation": {"angle": 0, "axis": "y", "origin": [7, 2, 5]},
"faces": {
"north": {"uv": [2.5, 0, 5, 1], "texture": "#0"},
"east": {"uv": [5.5, 4, 6.25, 5], "texture": "#0"},
"south": {"uv": [2.5, 1, 5, 2], "texture": "#0"},
"west": {"uv": [5, 5.5, 5.75, 6.5], "texture": "#0"},
"up": {"uv": [5.5, 5, 3, 4.25], "texture": "#0"},
"down": {"uv": [2.5, 5, 0, 5.75], "texture": "#0"}
}
},
{
"from": [3, 7, 4],
"to": [13, 8, 5],
"rotation": {"angle": 0, "axis": "y", "origin": [5, 7, 3]},
"faces": {
"north": {"uv": [0, 4, 2.5, 4.25], "texture": "#0"},
"east": {"uv": [2, 7.25, 2.25, 7.5], "texture": "#0"},
"south": {"uv": [0, 5.75, 2.5, 6], "texture": "#0"},
"west": {"uv": [2.25, 7.25, 2.5, 7.5], "texture": "#0"},
"up": {"uv": [8.25, 5.75, 5.75, 5.5], "texture": "#0"},
"down": {"uv": [8.25, 5.75, 5.75, 6], "texture": "#0"}
}
},
{
"from": [3.001, 6.999, 4.001],
"to": [4.001, 7.999, 9.001],
"rotation": {"angle": 0, "axis": "y", "origin": [5, 7, 6]},
"faces": {
"north": {"uv": [4.5, 7.25, 4.75, 7.5], "texture": "#0"},
"east": {"uv": [6, 5, 7.25, 5.25], "texture": "#0"},
"south": {"uv": [7.25, 4.5, 7.5, 4.75], "texture": "#0"},
"west": {"uv": [6, 5.25, 7.25, 5.5], "texture": "#0"},
"up": {"uv": [0.75, 7.5, 0.5, 6.25], "texture": "#0"},
"down": {"uv": [1, 6.25, 0.75, 7.5], "texture": "#0"}
}
},
{
"from": [11.99, 6.999, 4.001],
"to": [12.99, 7.999, 9.001],
"rotation": {"angle": 0, "axis": "y", "origin": [14, 7, 6]},
"faces": {
"north": {"uv": [4.75, 7.25, 5, 7.5], "texture": "#0"},
"east": {"uv": [6.25, 4, 7.5, 4.25], "texture": "#0"},
"south": {"uv": [7.25, 4.75, 7.5, 5], "texture": "#0"},
"west": {"uv": [6.25, 4.25, 7.5, 4.5], "texture": "#0"},
"up": {"uv": [1.25, 7.5, 1, 6.25], "texture": "#0"},
"down": {"uv": [1.5, 6.25, 1.25, 7.5], "texture": "#0"}
}
},
{
"from": [5, 7, 6],
"to": [7, 8, 8],
"rotation": {"angle": 0, "axis": "y", "origin": [7, 7, 5]},
"faces": {
"north": {"uv": [6.5, 3.75, 7, 4], "texture": "#0"},
"east": {"uv": [6.75, 6, 7.25, 6.25], "texture": "#0"},
"south": {"uv": [6.75, 6.25, 7.25, 6.5], "texture": "#0"},
"west": {"uv": [6.75, 6.5, 7.25, 6.75], "texture": "#0"},
"up": {"uv": [6.75, 6.5, 6.25, 6], "texture": "#0"},
"down": {"uv": [7, 3.25, 6.5, 3.75], "texture": "#0"}
}
},
{
"from": [9, 7, 6],
"to": [11, 8, 8],
"rotation": {"angle": 0, "axis": "y", "origin": [11, 7, 5]},
"faces": {
"north": {"uv": [6.75, 6.75, 7.25, 7], "texture": "#0"},
"east": {"uv": [0, 7, 0.5, 7.25], "texture": "#0"},
"south": {"uv": [7, 1, 7.5, 1.25], "texture": "#0"},
"west": {"uv": [7, 1.25, 7.5, 1.5], "texture": "#0"},
"up": {"uv": [5.5, 7, 5, 6.5], "texture": "#0"},
"down": {"uv": [6.75, 6.5, 6.25, 7], "texture": "#0"}
}
},
{
"from": [9, 7, 9],
"to": [11, 8, 11],
"rotation": {"angle": 0, "axis": "y", "origin": [11, 7, 8]},
"faces": {
"north": {"uv": [7, 1.5, 7.5, 1.75], "texture": "#0"},
"east": {"uv": [7, 1.75, 7.5, 2], "texture": "#0"},
"south": {"uv": [7, 2, 7.5, 2.25], "texture": "#0"},
"west": {"uv": [7, 2.25, 7.5, 2.5], "texture": "#0"},
"up": {"uv": [2, 7.25, 1.5, 6.75], "texture": "#0"},
"down": {"uv": [2.5, 6.75, 2, 7.25], "texture": "#0"}
}
},
{
"from": [5, 7, 9],
"to": [7, 8, 11],
"rotation": {"angle": 0, "axis": "y", "origin": [7, 7, 8]},
"faces": {
"north": {"uv": [7, 3.25, 7.5, 3.5], "texture": "#0"},
"east": {"uv": [7, 3.5, 7.5, 3.75], "texture": "#0"},
"south": {"uv": [7, 3.75, 7.5, 4], "texture": "#0"},
"west": {"uv": [4.5, 7, 5, 7.25], "texture": "#0"},
"up": {"uv": [7.25, 5, 6.75, 4.5], "texture": "#0"},
"down": {"uv": [6, 6.75, 5.5, 7.25], "texture": "#0"}
}
},
{
"from": [11, 7, 2],
"to": [12, 8, 4],
"rotation": {"angle": 0, "axis": "y", "origin": [10, 6, 2]},
"faces": {
"north": {"uv": [5, 7.25, 5.25, 7.5], "texture": "#0"},
"east": {"uv": [5, 7, 5.5, 7.25], "texture": "#0"},
"south": {"uv": [7.25, 5, 7.5, 5.25], "texture": "#0"},
"west": {"uv": [6, 7, 6.5, 7.25], "texture": "#0"},
"up": {"uv": [6.75, 7.5, 6.5, 7], "texture": "#0"},
"down": {"uv": [7, 7, 6.75, 7.5], "texture": "#0"}
}
},
{
"from": [4, 7, 2],
"to": [5, 8, 4],
"rotation": {"angle": 0, "axis": "y", "origin": [3, 6, 2]},
"faces": {
"north": {"uv": [5.25, 7.25, 5.5, 7.5], "texture": "#0"},
"east": {"uv": [7, 7, 7.5, 7.25], "texture": "#0"},
"south": {"uv": [7.25, 5.25, 7.5, 5.5], "texture": "#0"},
"west": {"uv": [0, 7.25, 0.5, 7.5], "texture": "#0"},
"up": {"uv": [1.75, 7.75, 1.5, 7.25], "texture": "#0"},
"down": {"uv": [2, 7.25, 1.75, 7.75], "texture": "#0"}
}
},
{
"from": [4, 7, 1],
"to": [12, 8, 2],
"rotation": {"angle": 0, "axis": "y", "origin": [6, 6, 0]},
"faces": {
"north": {"uv": [0, 6, 2, 6.25], "texture": "#0"},
"east": {"uv": [5.5, 6.5, 5.75, 6.75], "texture": "#0"},
"south": {"uv": [6, 2.5, 8, 2.75], "texture": "#0"},
"west": {"uv": [6, 6.75, 6.25, 7], "texture": "#0"},
"up": {"uv": [8, 3, 6, 2.75], "texture": "#0"},
"down": {"uv": [8, 3, 6, 3.25], "texture": "#0"}
}
}
],
"display": {
"thirdperson_righthand": {
"rotation": [-138.53, -0.13, 178.31],
"translation": [-0.25, 2.75, -2.5],
"scale": [0.77734, 0.5625, 0.76172]
},
"thirdperson_lefthand": {
"rotation": [-173.23, 0.42, -179.8],
"translation": [0.25, 0, -3.5],
"scale": [0.60156, 0.42188, 0.58984]
},
"gui": {
"rotation": [44.5, 31.22, -19.39],
"translation": [1.75, 3, 0],
"scale": [0.88281, 0.87109, 1.02539]
},
"head": {
"rotation": [180, 0.5, 180],
"translation": [0, 10, 0],
"scale": [1.94141, 1.45703, 2.06641]
},
"fixed": {
"rotation": [90, 40, -180],
"translation": [0, 0, -7],
"scale": [1.17188, 1, 1]
}
}
}

View File

@ -0,0 +1,3 @@
{
"parent": "keeblarcraft:block/faction_base_block"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

View File

@ -28,6 +28,9 @@
"jesse.keeblarcraft.world.biome.ModTerrablenderAPI" "jesse.keeblarcraft.world.biome.ModTerrablenderAPI"
] ]
}, },
"mixins": [
"keeblarcraft.mixins.json"
],
"depends": { "depends": {
"fabricloader": ">=0.15.11", "fabricloader": ">=0.15.11",
"minecraft": "~1.20", "minecraft": "~1.20",

View File

@ -0,0 +1,18 @@
{
"required": true,
"minVersion": "0.8",
"package": "jesse.keeblarcraft.mixin",
"compatibilityLevel": "JAVA_17",
"mixins": [
"PlayerMixin",
"ServerPlayNetworkHandlerMixin",
"PlayerEntityInteractionHandler",
"ServerPlayerInteractionManagerMixin"
],
"client": [
"ClientPlayerInteractionManagerMixin"
],
"injectors": {
"defaultRequire": 1
}
}