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/
classes/
remappedSrc/
# eclipse
*.launch

View File

@ -32,13 +32,13 @@ DOXYFILE_ENCODING = UTF-8
# title of most generated pages and in a few other places.
# 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
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER =
PROJECT_NUMBER = 1.0
# 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

View File

@ -1,5 +1,5 @@
plugins {
id 'fabric-loom' version '1.7-SNAPSHOT'
id 'fabric-loom' version '1.9-SNAPSHOT'
id 'maven-publish'
}
@ -47,13 +47,16 @@ dependencies {
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
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.
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
//modCompileOnly "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'
include 'net.kyrptonaught:customportalapi:0.0.1-beta65-1.20'
modImplementation 'com.github.glitchfiend:TerraBlender-fabric:1.20.1-3.0.1.7'
modImplementation 'net.kyrptonaught:customportalapi:0.0.1-beta64.5-1.20.2'
include 'net.kyrptonaught:customportalapi:0.0.1-beta64.5-1.20.2'
modImplementation 'com.github.glitchfiend:TerraBlender-fabric:1.20.2-3.2.0.14'
}
processResources {
@ -72,10 +75,10 @@ java {
// Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task
// if it is present.
// If you remove this line, sources will not be generated.
withSourcesJar()
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
withSourcesJar()
}
jar {

View File

@ -1,17 +1,17 @@
# Done to increase the memory available to gradle.
org.gradle.jvmargs=-Xmx1G
org.gradle.jvmargs=-Xmx2G
org.gradle.parallel=true
# Fabric Properties
# check these on https://fabricmc.net/develop
minecraft_version=1.20
yarn_mappings=1.20+build.1
loader_version=0.15.11
minecraft_version=1.20.2
yarn_mappings=1.20.2+build.4
loader_version=0.16.9
# Mod Properties
mod_version=0.0.1
mod_version=1.0.0
maven_group=jesse.keeblarcraft
archives_base_name=keeblarcraft
# 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
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
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

5
gradlew vendored
View File

@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
@ -84,7 +86,8 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# 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.
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 limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@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;
import jesse.keeblarcraft.gui.ClientHandlers;
import jesse.keeblarcraft.gui.ScreenManager;
import jesse.keeblarcraft.gui.widgets.TreeWidget;
// import jesse.keeblarcraft.gui.ScreenManager;
// import jesse.keeblarcraft.gui.widgets.TreeWidget;
import jesse.keeblarcraft.Shortcuts.ShortcutManager;
import net.fabricmc.api.ClientModInitializer;
@ -14,8 +14,8 @@ public class KeeblarcraftClient implements ClientModInitializer {
ShortcutManager.RegisterKeybinds();
ClientHandlers.RegisterHandlers();
ScreenManager.GetInstance();
ScreenManager.AddWidget(TreeWidget.class, 10);
// ScreenManager.GetInstance();
// ScreenManager.AddWidget(TreeWidget.class, 10);
}
}

View File

@ -12,7 +12,7 @@ package jesse.keeblarcraft.Shortcuts;
import org.lwjgl.glfw.GLFW;
// 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.keybinding.v1.KeyBindingHelper;
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.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();
treeGui.AddParent(currentScreen);
// ScreenManager treeGui = ScreenManager.GetInstance();
// 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
// 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;
import jesse.keeblarcraft.Keeblarcraft;
import jesse.keeblarcraft.GuiMgr.ScreenHandlerRegistration;
import net.minecraft.client.gui.screen.ingame.HandledScreens;
public class ClientHandlers {
public static void RegisterHandlers() {
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
*
* 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
* 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
* 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.
*
*
*/
// /*
// *
// * ScreenManager
// *
// * 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
// * 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
// * 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.
// *
// *
// */
package jesse.keeblarcraft.gui;
// package jesse.keeblarcraft.gui;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
// import java.lang.reflect.InvocationTargetException;
// import java.util.ArrayList;
// import java.util.HashMap;
// import java.util.List;
// import java.util.Map.Entry;
import jesse.keeblarcraft.Keeblarcraft;
import jesse.keeblarcraft.GuiMgr.TreeHandler;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.text.Text;
// import jesse.keeblarcraft.Keeblarcraft;
// import jesse.keeblarcraft.GuiMgr.TreeHandler;
// import net.minecraft.client.MinecraftClient;
// import net.minecraft.client.gui.DrawContext;
// import net.minecraft.client.gui.screen.Screen;
// import net.minecraft.client.gui.screen.ingame.HandledScreen;
// import net.minecraft.entity.player.PlayerInventory;
// import net.minecraft.text.Text;
// Client side renderer
public class ScreenManager extends HandledScreen<TreeHandler> {
private static ScreenManager static_inst;
@SuppressWarnings("resource")
private static PlayerInventory static_inventory = new PlayerInventory(null);// = MinecraftClient.getInstance().player.getInventory();
// // Client side renderer
// public class ScreenManager extends HandledScreen<TreeHandler> {
// private static ScreenManager static_inst;
// @SuppressWarnings("resource")
// private static PlayerInventory static_inventory = new PlayerInventory(null);// = MinecraftClient.getInstance().player.getInventory();
public static ScreenManager GetInstance() {
if (static_inst == null) {
static_inst = new ScreenManager(Keeblarcraft.TREE_HANDLER.create(0, static_inventory), static_inventory, Text.of("Test"));
}
return static_inst;
}
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 TreeWidget treeWidget = null;
private Screen parent;
/////////////////////////////////////////////////////////////////////////////
/// @fn ScreenManager
///
/// @arg[in] handler is the TreeHandler (ScreenHandler) object
///
/// @arg[in] inventory is the players inventory. Required by HandledScreen
/// object however is unused currently in this Screen
///
/// @arg[in] title is the title of the screen window
///
/// @brief Class constructor
/////////////////////////////////////////////////////////////////////////////
public ScreenManager(TreeHandler handler, PlayerInventory inventory, Text title) {
super(handler, inventory, title);
System.out.println("Called constructor of screen manager!");
// Initialize layers in map
// for (int i = 0; i < NUMBER_DRAW_LAYERS; i++) {
// layers.put(i, new ArrayList<Class<? extends GenericLayerT>>());
// public static ScreenManager GetInstance() {
// if (static_inst == null) {
// static_inst = new ScreenManager(Keeblarcraft.TREE_HANDLER.create(0, static_inventory), static_inventory, Text.of("Test"));
// }
// return static_inst;
// }
}
/////////////////////////////////////////////////////////////////////////////
/// @fn AddParent
///
/// @arg[in] parent is the parent screen object
///
/// @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
/// closed by the user
/////////////////////////////////////////////////////////////////////////////
public void AddParent(Screen parent) {
this.parent = parent;
}
// 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
public static void AddWidget(Class<? extends GenericLayerT> widget, int drawLayer) {
if (layerMap.containsKey(drawLayer)) {
// Just append the widget to the draw layer
var layerList = layerMap.get(drawLayer);
layerList.add(widget);
} else {
// Brand new layer!
layerMap.put(drawLayer, new ArrayList<>(List.of(widget)));
}
}
// // private TreeWidget treeWidget = null;
// private Screen parent;
/////////////////////////////////////////////////////////////////////////////
/// @fn init
///
/// @brief Initialize method; called one-time to setup class variables
/////////////////////////////////////////////////////////////////////////////
@Override
public void init() {
// initialize screen size to the global background picture
this.width = MinecraftClient.getInstance().getWindow().getScaledWidth();
this.height = MinecraftClient.getInstance().getWindow().getScaledHeight();
// /////////////////////////////////////////////////////////////////////////////
// /// @fn ScreenManager
// ///
// /// @arg[in] handler is the TreeHandler (ScreenHandler) object
// ///
// /// @arg[in] inventory is the players inventory. Required by HandledScreen
// /// object however is unused currently in this Screen
// ///
// /// @arg[in] title is the title of the screen window
// ///
// /// @brief Class constructor
// /////////////////////////////////////////////////////////////////////////////
// public ScreenManager(TreeHandler handler, PlayerInventory inventory, Text title) {
// super(handler, inventory, title);
// System.out.println("Called constructor of screen manager!");
// 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()) {
var layerList = layerEntry.getValue();
// // Initialize layers in map
// // for (int i = 0; i < NUMBER_DRAW_LAYERS; i++) {
// // layers.put(i, new ArrayList<Class<? extends GenericLayerT>>());
// // }
// }
layers.put(layerEntry.getKey(), new ArrayList<>());
var activeLayerList = layers.get(layerEntry.getKey());
for (int i = 0; i < layerList.size(); i++) {
try {
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(""));
activeLayerList.add(initializedWidget);
} catch (InstantiationException e) {
System.out.println("Could not initialize GenericLayerT class (" + layerList.get(i).getClass().toString() + ") because of IntantiationException");
e.printStackTrace();
} catch (IllegalAccessException e) {
System.out.println("Could not initialize GenericLayerT class (" + layerList.get(i).getClass().toString() + ") because of IllegalAccessException");
e.printStackTrace();
} catch (IllegalArgumentException e) {
System.out.println("Could not initialize GenericLayerT class (" + layerList.get(i).getClass().toString() + ") because of IllegalArgumentException");
e.printStackTrace();
} catch (InvocationTargetException e) {
System.out.println("Could not initialize GenericLayerT class (" + layerList.get(i).getClass().toString() + ") because of InvocationTargetException");
e.printStackTrace();
} catch (NoSuchMethodException e) {
System.out.println("Could not initialize GenericLayerT class (" + layerList.get(i).getClass().toString() + ") because of NoSuchMethodException");
e.printStackTrace();
} catch (SecurityException e) {
System.out.println("Could not initialize GenericLayerT class (" + layerList.get(i).getClass().toString() + ") because of SecurityException");
e.printStackTrace();
}
}
}
// /////////////////////////////////////////////////////////////////////////////
// /// @fn AddParent
// ///
// /// @arg[in] parent is the parent screen object
// ///
// /// @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
// /// closed by the user
// /////////////////////////////////////////////////////////////////////////////
// public void AddParent(Screen parent) {
// this.parent = parent;
// }
// public static void AddWidget(Class<? extends GenericLayerT> widget, int drawLayer) {
// if (layerMap.containsKey(drawLayer)) {
// // Just append the widget to the draw layer
// var layerList = layerMap.get(drawLayer);
// layerList.add(widget);
// } else {
// // Brand new layer!
// layerMap.put(drawLayer, new ArrayList<>(List.of(widget)));
// }
// }
// /////////////////////////////////////////////////////////////////////////////
// /// @fn init
// ///
// /// @brief Initialize method; called one-time to setup class variables
// /////////////////////////////////////////////////////////////////////////////
// @Override
// public void init() {
// // initialize screen size to the global background picture
// this.width = MinecraftClient.getInstance().getWindow().getScaledWidth();
// this.height = MinecraftClient.getInstance().getWindow().getScaledHeight();
// // 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()) {
// var layerList = layerEntry.getValue();
// layers.put(layerEntry.getKey(), new ArrayList<>());
// var activeLayerList = layers.get(layerEntry.getKey());
// for (int i = 0; i < layerList.size(); i++) {
// try {
// 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(""));
// activeLayerList.add(initializedWidget);
// } catch (InstantiationException e) {
// System.out.println("Could not initialize GenericLayerT class (" + layerList.get(i).getClass().toString() + ") because of IntantiationException");
// e.printStackTrace();
// } catch (IllegalAccessException e) {
// System.out.println("Could not initialize GenericLayerT class (" + layerList.get(i).getClass().toString() + ") because of IllegalAccessException");
// e.printStackTrace();
// } catch (IllegalArgumentException e) {
// System.out.println("Could not initialize GenericLayerT class (" + layerList.get(i).getClass().toString() + ") because of IllegalArgumentException");
// e.printStackTrace();
// } catch (InvocationTargetException e) {
// System.out.println("Could not initialize GenericLayerT class (" + layerList.get(i).getClass().toString() + ") because of InvocationTargetException");
// e.printStackTrace();
// } catch (NoSuchMethodException e) {
// System.out.println("Could not initialize GenericLayerT class (" + layerList.get(i).getClass().toString() + ") because of NoSuchMethodException");
// e.printStackTrace();
// } catch (SecurityException e) {
// System.out.println("Could not initialize GenericLayerT class (" + layerList.get(i).getClass().toString() + ") because of SecurityException");
// e.printStackTrace();
// }
// }
// }
// 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);
// this.addDrawableChild(treeWidget);
}
// // 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);
// // this.addDrawableChild(treeWidget);
// }
/////////////////////////////////////////////////////////////////////////////
/// @fn render
///
/// @arg[in] context is the drawing context of super class
///
/// @arg[in] mouseX 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
///
/// @note This is a pure abstract in parent and is required
/////////////////////////////////////////////////////////////////////////////
@Override
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
}
// /////////////////////////////////////////////////////////////////////////////
// /// @fn render
// ///
// /// @arg[in] context is the drawing context of super class
// ///
// /// @arg[in] mouseX 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
// ///
// /// @note This is a pure abstract in parent and is required
// /////////////////////////////////////////////////////////////////////////////
// @Override
// 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
// }
/////////////////////////////////////////////////////////////////////////////
/// @fn drawForeground
///
/// @arg[in] context is the drawing context of super class
///
/// @arg[in] mouseX is unused
///
/// @arg[in] mouseY is unused
///
/// @brief Draw foreground exists to draw the titles; however we
/// intentionally override it so the superclass object does not
/// draw the overlay over the background screen
/////////////////////////////////////////////////////////////////////////////
@Override
public void drawForeground(DrawContext context, int mouseX, int mouseY) {
// We override this function to intentionally do nothing
// If in the future we want, we would draw the foreground and TITLES with this!
}
// /////////////////////////////////////////////////////////////////////////////
// /// @fn drawForeground
// ///
// /// @arg[in] context is the drawing context of super class
// ///
// /// @arg[in] mouseX is unused
// ///
// /// @arg[in] mouseY is unused
// ///
// /// @brief Draw foreground exists to draw the titles; however we
// /// intentionally override it so the superclass object does not
// /// draw the overlay over the background screen
// /////////////////////////////////////////////////////////////////////////////
// @Override
// public void drawForeground(DrawContext context, int mouseX, int mouseY) {
// // We override this function to intentionally do nothing
// // If in the future we want, we would draw the foreground and TITLES with this!
// }
/////////////////////////////////////////////////////////////////////////////
/// @fn close
///
/// @brief Called when the screen closes
///
/// @note This is a pure abstract in parent and is required
/////////////////////////////////////////////////////////////////////////////
@Override
public void close() {
this.client.setScreen(parent); // return to previous screen or null
}
// /////////////////////////////////////////////////////////////////////////////
// /// @fn close
// ///
// /// @brief Called when the screen closes
// ///
// /// @note This is a pure abstract in parent and is required
// /////////////////////////////////////////////////////////////////////////////
// @Override
// public void close() {
// this.client.setScreen(parent); // return to previous screen or null
// }
/////////////////////////////////////////////////////////////////////////////
/// @fn mouseDragged
///
/// @arg[in] mouseX is x-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] deltaX is the change in the X position from the previous
/// mouse click
///
/// @arg[in] deltaY is the change in the Y position from the previous
/// mouse click
///
/// @brief The drag event is called on all widgets on the screen so
/// long as the initial position of the drag is within the
/// bounds of the widget box itself. Widgets themselves will need
/// to handle any sub-widgets since the bound check is only
/// there to verify if the event happened ANYWHERE within a
/// widget box
/////////////////////////////////////////////////////////////////////////////
@Override
public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) {
super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY);
// UpdateAnchorValues();
// /////////////////////////////////////////////////////////////////////////////
// /// @fn mouseDragged
// ///
// /// @arg[in] mouseX is x-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] deltaX is the change in the X position from the previous
// /// mouse click
// ///
// /// @arg[in] deltaY is the change in the Y position from the previous
// /// mouse click
// ///
// /// @brief The drag event is called on all widgets on the screen so
// /// long as the initial position of the drag is within the
// /// bounds of the widget box itself. Widgets themselves will need
// /// to handle any sub-widgets since the bound check is only
// /// there to verify if the event happened ANYWHERE within a
// /// widget box
// /////////////////////////////////////////////////////////////////////////////
// @Override
// public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) {
// super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY);
// // UpdateAnchorValues();
for (Entry<Integer, ArrayList<GenericLayerT>> layerEntry : layers.entrySet()) {
var layerList = layerEntry.getValue();
// for (Entry<Integer, ArrayList<GenericLayerT>> layerEntry : layers.entrySet()) {
// var layerList = layerEntry.getValue();
for (var layerListIterator = 0; layerListIterator < layerList.size(); layerListIterator++) {
var layer = layerList.get(layerListIterator);
// for (var layerListIterator = 0; layerListIterator < layerList.size(); layerListIterator++) {
// var layer = layerList.get(layerListIterator);
// 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)) {
layer.mouseDragged(mouseX, mouseY, button, deltaX, deltaY);
}
}
}
return true;
}
// // 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)) {
// layer.mouseDragged(mouseX, mouseY, button, deltaX, deltaY);
// }
// }
// }
// return true;
// }
/////////////////////////////////////////////////////////////////////////////
/// @fn mouseScrolled
///
/// @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] amount is a normalized value that indicates scroll direction
///
/// @brief The scroll event is called on all widgets on the screen so
/// long as the initial position of the scroll is within the
/// bounds of the widget box itself. Widgets themselves will need
/// to handle any sub-widgets since the bound check is only
/// there to verify if the event happened ANYWHERE within a
/// widget box
///
/////////////////////////////////////////////////////////////////////////////
@Override
public boolean mouseScrolled(double mouseX, double mouseY, double amount) {
super.mouseScrolled(mouseX, mouseY, amount);
// /////////////////////////////////////////////////////////////////////////////
// /// @fn mouseScrolled
// ///
// /// @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] amount is a normalized value that indicates scroll direction
// ///
// /// @brief The scroll event is called on all widgets on the screen so
// /// long as the initial position of the scroll is within the
// /// bounds of the widget box itself. Widgets themselves will need
// /// to handle any sub-widgets since the bound check is only
// /// there to verify if the event happened ANYWHERE within a
// /// widget box
// ///
// /////////////////////////////////////////////////////////////////////////////
// @Override
// public boolean mouseScrolled(double mouseX, double mouseY, double amount) {
// super.mouseScrolled(mouseX, mouseY, amount);
for (Entry<Integer, ArrayList<GenericLayerT>> layerEntry : layers.entrySet()) {
var layerList = layerEntry.getValue();
// for (Entry<Integer, ArrayList<GenericLayerT>> layerEntry : layers.entrySet()) {
// var layerList = layerEntry.getValue();
for (var layerListIterator = 0; layerListIterator < layerList.size(); layerListIterator++) {
var layer = layerList.get(layerListIterator);
// for (var layerListIterator = 0; layerListIterator < layerList.size(); layerListIterator++) {
// var layer = layerList.get(layerListIterator);
// 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)) {
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
}
// // 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)) {
// 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
// }
/////////////////////////////////////////////////////////////////////////////
/// @fn mouseClicked
///
/// @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] button is the mouse click button (left/right click value)
///
/// @brief The mouse click is called on all widgets on the screen so
/// long as the initial position of the click is within the
/// bounds of the widget box itself. Widgets themselves will need
/// to handle any sub-widgets since the bound check is only
/// there to verify if the event happened ANYWHERE within a
/// widget box
///
/////////////////////////////////////////////////////////////////////////////
@Override
public boolean mouseClicked(double mouseX, double mouseY, int button) {
super.mouseClicked(mouseX, mouseY, button);
// /////////////////////////////////////////////////////////////////////////////
// /// @fn mouseClicked
// ///
// /// @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] button is the mouse click button (left/right click value)
// ///
// /// @brief The mouse click is called on all widgets on the screen so
// /// long as the initial position of the click is within the
// /// bounds of the widget box itself. Widgets themselves will need
// /// to handle any sub-widgets since the bound check is only
// /// there to verify if the event happened ANYWHERE within a
// /// widget box
// ///
// /////////////////////////////////////////////////////////////////////////////
// @Override
// public boolean mouseClicked(double mouseX, double mouseY, int button) {
// super.mouseClicked(mouseX, mouseY, button);
for (Entry<Integer, ArrayList<GenericLayerT>> layerEntry : layers.entrySet()) {
var layerList = layerEntry.getValue();
// for (Entry<Integer, ArrayList<GenericLayerT>> layerEntry : layers.entrySet()) {
// var layerList = layerEntry.getValue();
for (var layerListIterator = 0; layerListIterator < layerList.size(); layerListIterator++) {
var layer = layerList.get(layerListIterator);
// for (var layerListIterator = 0; layerListIterator < layerList.size(); layerListIterator++) {
// var layer = layerList.get(layerListIterator);
// 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)) {
layer.mouseClicked(mouseX, mouseY, button);
}
}
}
return true;
}
// // 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)) {
// layer.mouseClicked(mouseX, mouseY, button);
// }
// }
// }
// return true;
// }
/////////////////////////////////////////////////////////////////////////////
/// @fn DrawLayers
///
/// @arg[in] context is the global drawing context for the screen
///
/// @arg[in] delta is passed in from background draw
///
/// @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
/// little distance as possible between redraws when possible!
///
/// @note Currently the foreground is not drawn in the custom screen
/// manager. This is because the foreground features the general
/// inventory manager that this screen handler is based on and we
/// do not want to see those text pop ups.
/////////////////////////////////////////////////////////////////////////////
public void DrawLayers(DrawContext context, float delta) {
for (Entry<Integer, ArrayList<GenericLayerT>> layerEntry : layers.entrySet()) {
var layerList = layerEntry.getValue();
// /////////////////////////////////////////////////////////////////////////////
// /// @fn DrawLayers
// ///
// /// @arg[in] context is the global drawing context for the screen
// ///
// /// @arg[in] delta is passed in from background draw
// ///
// /// @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
// /// little distance as possible between redraws when possible!
// ///
// /// @note Currently the foreground is not drawn in the custom screen
// /// manager. This is because the foreground features the general
// /// inventory manager that this screen handler is based on and we
// /// do not want to see those text pop ups.
// /////////////////////////////////////////////////////////////////////////////
// public void DrawLayers(DrawContext context, float delta) {
// for (Entry<Integer, ArrayList<GenericLayerT>> layerEntry : layers.entrySet()) {
// var layerList = layerEntry.getValue();
for (var layerListIterator = 0; layerListIterator < layerList.size(); layerListIterator++) {
var layer = layerList.get(layerListIterator);
System.out.println("Drawing layer " + layerEntry.getKey() + " for class type " + layer.getClass().toString());
layer.DrawLayer(context, layerEntry.getKey());
}
}
}
// for (var layerListIterator = 0; layerListIterator < layerList.size(); layerListIterator++) {
// var layer = layerList.get(layerListIterator);
// System.out.println("Drawing layer " + layerEntry.getKey() + " for class type " + layer.getClass().toString());
// layer.DrawLayer(context, layerEntry.getKey());
// }
// }
// }
/////////////////////////////////////////////////////////////////////////////
/// @fn InBounds
///
/// @arg[in] initX is initial position of X axis
///
/// @arg[in] initY is initial position of Y axis
///
/// @arg[in] endX is the end position of X 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] 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
/// of a bounded box
/////////////////////////////////////////////////////////////////////////////
private boolean InBounds(int initX, int initY, int endX, int endY, int x, int y) {
return (x >= initX && x <= endX) && (y >= initY && y <= endY);
}
// /////////////////////////////////////////////////////////////////////////////
// /// @fn InBounds
// ///
// /// @arg[in] initX is initial position of X axis
// ///
// /// @arg[in] initY is initial position of Y axis
// ///
// /// @arg[in] endX is the end position of X 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] 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
// /// of a bounded box
// /////////////////////////////////////////////////////////////////////////////
// private boolean InBounds(int initX, int initY, int endX, int endY, int x, int y) {
// return (x >= initX && x <= endX) && (y >= initY && y <= endY);
// }
/////////////////////////////////////////////////////////////////////////////
/// @fn drawBackground
///
/// @arg[in] context is the drawing context of super class
///
/// @arg[in] delta is the change in background draw
///
/// @arg[in] mouseX is the mouse x-axis position
///
/// @arg[in] mouseY is the mouse y-axis position
///
/// @brief This function is an abstract parent class and must be
/// implemented. This is "hijacked" and just being used as our
/// main drawing method of all the background images. There isn't
/// a huge difference of drawing our stuff in background vs the
/// foreground - except possibly foreground is drawn first.
/////////////////////////////////////////////////////////////////////////////
@Override
protected void drawBackground(DrawContext context, float delta, int mouseX, int mouseY) {
DrawLayers(context, delta);
}
}
// /////////////////////////////////////////////////////////////////////////////
// /// @fn drawBackground
// ///
// /// @arg[in] context is the drawing context of super class
// ///
// /// @arg[in] delta is the change in background draw
// ///
// /// @arg[in] mouseX is the mouse x-axis position
// ///
// /// @arg[in] mouseY is the mouse y-axis position
// ///
// /// @brief This function is an abstract parent class and must be
// /// implemented. This is "hijacked" and just being used as our
// /// main drawing method of all the background images. There isn't
// /// a huge difference of drawing our stuff in background vs the
// /// foreground - except possibly foreground is drawn first.
// /////////////////////////////////////////////////////////////////////////////
// @Override
// protected void drawBackground(DrawContext context, float delta, int mouseX, int mouseY) {
// DrawLayers(context, delta);
// }
// }

View File

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

View File

@ -10,13 +10,14 @@
package jesse.keeblarcraft.AttributeMgr;
import java.util.HashMap;
import java.util.Set;
import jesse.keeblarcraft.Keeblarcraft;
import jesse.keeblarcraft.AttributeMgr.AttributeNodes.AbstractNode;
import jesse.keeblarcraft.AttributeMgr.AttributeNodes.AttributeFlight;
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.Utils.ChatUtil;
public class AttributeMgr {
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");
e.printStackTrace();
}
ChatUtil.LoggerColored("Registring attribute called", ChatUtil.CONSOLE_COLOR.CYAN, Keeblarcraft.LOGGER);
try {
if (attributes.containsKey(verifyNode.GetNodeTitle())) {
Keeblarcraft.LOGGER.warn("Could not register attribute with duplicate name '" + verifyNode.GetNodeTitle() + "'");
} 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);
}
} catch (Exception e) {} // Left empty since previous try-catch will throw error-message
@ -70,6 +70,19 @@ public class AttributeMgr {
@SuppressWarnings("deprecation")
public static String ApplyAttribute(String uuid, String attributeName) {
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)) {
AttributeTree playerTree = activeTrees.get(uuid);
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");
}
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
String isNull = (node == null ? "NULL" : "NOT NULL");
@ -92,13 +113,26 @@ public class AttributeMgr {
msg = "Applied attribute '" + attributeName + "' successfully";
} else {
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 {
msg = "Could not apply attribute, attribute name does not exist!";
System.out.println("Attribute does not exist!");
}
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
///
@ -112,7 +146,8 @@ public class AttributeMgr {
/// TODO: Find a better way to do this more dynamically in the future
/// hint: make it an API for other modders to add to
RegisterAttributeClass(AttributeFlight.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 net.minecraft.item.ArmorItem;
import net.minecraft.item.Item;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
public final class AttributeMetalJacket extends AbstractNode {
// 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.AttributeMgr.AttributeNodes.AbstractNode;
import jesse.keeblarcraft.ConfigMgr.ConfigManager;
import jesse.keeblarcraft.Utils.ChatUtil;
import jesse.keeblarcraft.Utils.ChatUtil.CONSOLE_COLOR;
import jesse.keeblarcraft.Utils.CustomExceptions.FILE_WRITE_EXCEPTION;
import net.minecraft.server.network.ServerPlayerEntity;
public class AttributeTree {
PlayerTree playerAttributeTree = new PlayerTree();
ConfigManager config = new ConfigManager();
private AbstractNode root = new RootNode();
private ServerPlayerEntity player;
/////////////////////////////////////////////////////////////////////////////
/// @class TreeNode
@ -33,7 +32,7 @@ public class AttributeTree {
/// @brief This is an individual node that goes within the larger
/// PlayerTree class object
/////////////////////////////////////////////////////////////////////////////
private class TreeNode {
public class TreeNode {
public TreeNode(AbstractNode node, Integer maxLevel, List<String> parents, List<String> children) {
thisNode = node;
parentNodes = parents;
@ -42,15 +41,15 @@ public class AttributeTree {
currentNodeLevel = 1;
}
AbstractNode thisNode;
Integer currentNodeLevel;
Integer maxNodeLevel;
public AbstractNode thisNode;
public Integer currentNodeLevel;
public Integer maxNodeLevel;
// 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
// code before just adding stuff willy-nilly!
List<String> parentNodes;
List<String> childrenNodes;
public List<String> parentNodes;
public List<String> childrenNodes;
}
/////////////////////////////////////////////////////////////////////////////
@ -61,10 +60,10 @@ public class AttributeTree {
/// stored inside the AttributeMgr class
/////////////////////////////////////////////////////////////////////////////
private class PlayerTree {
String uuid;
public String uuid;
// Key = name of AbstractNode
// 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));
// 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) {
System.out.println("Registering new callback for new node");
playerAttributeTree.tree.get(newNode.GetNodeTitle()).thisNode.RegisterCallbacks();
@ -212,6 +213,18 @@ public class AttributeTree {
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
///
@ -265,37 +278,35 @@ public class AttributeTree {
///
/// @brief Constructor for class
/////////////////////////////////////////////////////////////////////////////
public AttributeTree(String uuid) {
// DEVELOPER NOTE:
// If you are testing this part of the code, please be reminded that anonymous testing starts a new
// 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
public AttributeTree(ServerPlayerEntity p) {
this.player = p;
String uuid = player.getUuidAsString();
Boolean existingFile = false;
try {
playerAttributeTree = config.GetJsonObjectFromFile("attributes/" + uuid + ".json", PlayerTree.class);
existingFile = true;
existingFile = playerAttributeTree != null;
} catch (Exception e) {
System.out.println("Attribute tree file does not exist for this player");
// 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
if (!existingFile)
{
System.out.println(ChatUtil.ColoredString("Trying to create new file", CONSOLE_COLOR.BLUE));
System.out.println("Trying to create new file");
try {
playerAttributeTree = new PlayerTree();
playerAttributeTree.uuid = uuid;
FlashConfig();
} 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
// a new file with this players 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;
}
@ -313,10 +324,7 @@ public class AttributeTree {
/// @brief Flashes the config to the disk
/////////////////////////////////////////////////////////////////////////////
public void FlashConfig() {
try {
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));
}
/// TODO: This is broken because of a 'java.util.Option#value it cannot write. Idk, fix soon'
// config.WriteToJsonFile("attributes/" + playerAttributeTree.uuid + ".json", playerAttributeTree);
}
}

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.Map.Entry;
import org.apache.logging.log4j.core.jmx.Server;
import jesse.keeblarcraft.BankMgr.BankAccountType.ACCOUNT_TYPE;
import jesse.keeblarcraft.ConfigMgr.ConfigManager;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
@ -26,7 +25,8 @@ public final class BankManager {
private class PlayerBankConfig {
List<String> activeBanks = new ArrayList<String>(); // List of all banks a player has accounts in
String defaultSelectedBank;
String defaultSelectedBank = "";
String defaultSelectedAccount = "";
}
// Key = player uuid
@ -44,7 +44,11 @@ public final class BankManager {
// Val = Bank routing number
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
/////////////////////////////////////////////////////////////////////////////
@ -118,10 +122,14 @@ public final class BankManager {
/////////////////////////////////////////////////////////////////////////////
public void ChangeDefaultPlayerAccount(ServerPlayerEntity player, String newDefaultAccount) {
String bankName = AccountNumberGenerator.GetFinancialSymbolFromId(newDefaultAccount);
System.out.println("ChangeDefaultPlayerAccount: Received bankName " + bankName);
System.out.println(bankNameFastMap);
// 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)) {
Integer routNum = bankNameFastMap.get(bankName);
IndividualBank bank = banks.get(routNum);
@ -129,10 +137,29 @@ public final class BankManager {
// Verify this person has access to this account
if(bank.IsAccountHolder(newDefaultAccount, player.getUuidAsString())) {
// Finally update config to this account since checks pass
playerConfigs.get(player.getUuidAsString()).defaultSelectedBank = newDefaultAccount;
playerConfigs.get(player.getUuidAsString()).defaultSelectedAccount = newDefaultAccount;
}
} 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
/////////////////////////////////////////////////////////////////////////////
public void InitiateBankFundsTransfer(ServerPlayerEntity fromPlayer, String toAccount, Integer amount) {
public void InitiateBankFundsTransfer(ServerPlayerEntity fromPlayer, String toAccount, Integer amount, String reason) {
// Get player default selection
String fromAccount = playerConfigs.get(fromPlayer.getUuidAsString()).defaultSelectedBank;
String fromAccount = playerConfigs.get(fromPlayer.getUuidAsString()).defaultSelectedAccount;
String fromAccountSymbol = AccountNumberGenerator.GetFinancialSymbolFromId(fromAccount);
String toAccountSymbol = AccountNumberGenerator.GetFinancialSymbolFromId(toAccount);
@ -246,12 +273,21 @@ public final class BankManager {
String account = "";
if (playerConfigs.containsKey(playerUuid)) {
account = playerConfigs.get(playerUuid).defaultSelectedBank;
account = playerConfigs.get(playerUuid).defaultSelectedAccount;
}
return account;
}
public String GetPlayerSelectedBank(String playerUuid) {
String bank = "";
if (playerConfigs.containsKey(playerUuid)) {
bank = playerConfigs.get(playerUuid).defaultSelectedBank;
}
return bank;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn InitiateBankAccountCreation
///
@ -263,40 +299,18 @@ public final class BankManager {
///
/// @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;
System.out.println("initiating bank creation");
boolean defaultServerBank = bankIdentifier == null || bankIdentifier == "";
System.out.println("value of bankIdentifier is " + defaultServerBank);
IndividualBank bank = GetBankByName(bankIdentifier);
System.out.println("The player name is " + player.getDisplayName().getString());
// 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 (bank != null) {
success = bank.CreateAccount(player.getUuidAsString(), player.getEntityName(), accountType);
}
if (success) {
player.sendMessage(Text.of("The banking operation was successful and your banking information has been updated"));
} 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 jesse.keeblarcraft.BankMgr.BankAccountType.ACCOUNT_TYPE;
// 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
// like a safety deposit box
@ -16,14 +18,14 @@ public class IndividualAccount {
private Integer accountBalance;
private Boolean allowNegativeBalance;
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(String accountNumber, Integer routingNumber, List<String> holders,
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 + " " +
accountHolderUuids + " " + allowNegativeBalance + " " + initialBalance + " " + alias + " " + accountType);

View File

@ -11,23 +11,22 @@ import static java.util.Map.entry;
import java.io.File;
import jesse.keeblarcraft.ConfigMgr.ConfigManager;
import jesse.keeblarcraft.Utils.ChatUtil;
import jesse.keeblarcraft.Utils.ChatUtil.CONSOLE_COLOR;
import jesse.keeblarcraft.Utils.CustomExceptions.FILE_WRITE_EXCEPTION;
import jesse.keeblarcraft.Keeblarcraft;
import jesse.keeblarcraft.BankMgr.BankAccountType.ACCOUNT_TYPE;
// Contains the information of an individual 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.
public class IndividualBank {
private Map<String, Integer> ACCOUNT_TYPES = Map.ofEntries(
entry("checking", 0),
entry("savings", 1)
private Map<ACCOUNT_TYPE, Integer> ACCOUNT_TYPES = Map.ofEntries(
entry(ACCOUNT_TYPE.CHECKING, 0),
entry(ACCOUNT_TYPE.SAVINGS, 1)
);
private ConfigManager config = new ConfigManager();
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 String bankFourLetterIdentifier;
private String registeredBankName;
@ -36,13 +35,13 @@ public class IndividualBank {
// 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.
private Integer kbicInsuredAmount;
private Boolean kbicInsured;
private Integer kbicInsuredAmount = 0;
private Boolean kbicInsured = false;
// 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.
// 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
// Value = ACCOUNT
@ -89,7 +88,7 @@ public class IndividualBank {
// TODO: REPLACE WITH SQL SERVER. DIRTY ITERATE OVER ALL FILES IN DIRECTORY TO LOAD STRUCTURE
File dir = new File(accountsListDir);
File[] allFiles = dir.listFiles();
if (allFiles != null) {
if (accounts != null && allFiles != null) {
for (File file : allFiles ) {
// First grab file identifier as KEY
String accountIdentifier = file.getName();
@ -107,7 +106,6 @@ public class IndividualBank {
if (!existingFile)
{
System.out.println(ChatUtil.ColoredString("Trying to create new file", CONSOLE_COLOR.BLUE));
try {
// We assume the bank dir is created by server. Create this banks dir
// config.CreateDirectory("bank/" + routingNumber);
@ -117,16 +115,15 @@ public class IndividualBank {
// Flash initial account configuration file for this bank
FlashConfig("accounts");
} 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
// '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
// or gets put on one to update the map every time
if (accounts != null) {
for (Entry<String, IndividualAccount> account : accounts.accountsList.entrySet()) {
// 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();
@ -143,6 +140,10 @@ public class IndividualBank {
}
}
numberOfAccounts = accounts.accountsList.size();
} else {
accounts = new Accounts();
numberOfAccounts = 0;
}
}
/////////////////////////////////////////////////////////////////////////////
@ -164,12 +165,9 @@ public class IndividualBank {
/// @return List of all bank accounts. List will be EMPTY if no accounts
/////////////////////////////////////////////////////////////////////////////
public List<IndividualAccount> GetAccountsOfUser(String uuid) {
System.out.println("UUID passed in: " + uuid);
List<IndividualAccount> accountsFromUser = new ArrayList<IndividualAccount>();
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) {
for (int i = 0; i < listOfAccounts.size(); 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
/////////////////////////////////////////////////////////////////////////////
public Boolean CreateAccount(String holderUuid, String holderName, String accountTypeStr) {
public Boolean CreateAccount(String holderUuid, String holderName, ACCOUNT_TYPE accountType) {
Boolean success = false;
System.out.println("Attempting to create new bank account given args UUID / NAME / TYPE : " + holderUuid + " " + holderName + " " + accountTypeStr);
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())) {
if (accounts.accountsList.size() <= maxBankAccounts) {
// Verify this isn't a blacklisted user
System.out.println("Is user bank locked? " + 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.
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("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
// entire life time of the server. BUT, you never know!
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 + " }");
maxAttempts--;
}
@ -402,7 +397,7 @@ public class IndividualBank {
if (!accounts.accountsList.containsKey(actualAccountNumber)) {
IndividualAccount newAccount = new IndividualAccount(actualAccountNumber, this.routingNumber, List.of(holderName),
List.of(holderUuid), false, 0,
"", ACCOUNT_TYPES.get(accountTypeStr), bankFourLetterIdentifier);
"", accountType, bankFourLetterIdentifier);
System.out.println("Updating accounts list for this bank");
UpdateBankAccounts(holderName, holderUuid, actualAccountNumber, newAccount);
success = true;
@ -564,12 +559,7 @@ public class IndividualBank {
}
// Re-flash file
try {
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 {
enum TRANSACTION_TYPE {
DEBIT,
CREDIT
CREDIT,
WITHDRAWAL,
DEPOSIT
}
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 String transactionId;
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.List;
import jesse.keeblarcraft.ChatStuff.ChatFormatting.COLOR_CODE;
import net.minecraft.text.ClickEvent;
import net.minecraft.text.HoverEvent;
import net.minecraft.text.MutableText;
import net.minecraft.text.Style;
import net.minecraft.text.Text;
public class HelpBuilder {
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;
}
public class ChatMsg {
/////////////////////////////////////////////////////////////////////////////
/// @fn MakeCopyableTxt
///
@ -139,7 +109,28 @@ public class HelpBuilder {
/// @return Formatted string of colored text
/////////////////////////////////////////////////////////////////////////////
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>();
for (String str : msg) {
retList.add(getColor(color) + str + COLOR_END);
retList.add(ChatFormatting.GetColor(color) + str + ChatFormatting.COLOR_END);
}
return retList;
@ -179,7 +170,7 @@ public class HelpBuilder {
/// @return Formatted string of colored text
/////////////////////////////////////////////////////////////////////////////
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
@ -200,7 +191,7 @@ public class HelpBuilder {
/// @return Formatted string of colored text
/////////////////////////////////////////////////////////////////////////////
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("\\."));
Boolean isFirst = true;
@ -208,12 +199,12 @@ public class HelpBuilder {
if (isFirst) {
coloredStr += str;
isFirst = false;
coloredStr += getColor(secondaryColor);
coloredStr += ChatFormatting.GetColor(secondaryColor);
} else {
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) {
int ret = -1;
System.out.println("Applying attribute");
if (context.getSource().isExecutedByPlayer()) {
System.out.println("Executed by player");
String result = AttributeMgr.ApplyAttribute(targetPlayer.getUuidAsString(), attributeName);
Keeblarcraft.LOGGER.info("[ApplyAttribute] -> " + result);
context.getSource().getPlayer().sendMessage(Text.of(result));

View File

@ -1,20 +1,24 @@
package jesse.keeblarcraft.Commands;
import com.mojang.brigadier.arguments.IntegerArgumentType;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.context.CommandContext;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
import java.util.Map.Entry;
import static java.util.Map.entry;
import jesse.keeblarcraft.BankMgr.BankAccountType;
import jesse.keeblarcraft.BankMgr.BankManager;
import jesse.keeblarcraft.BankMgr.IndividualAccount;
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.Utils.HelpBuilder;
import jesse.keeblarcraft.Utils.HelpBuilder.COLOR_CODE;
import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource;
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_LOCK = "admin-accounts-lock";
HelpBuilder msgFormatter = new HelpBuilder();
ChatMsg msgFormatter = new ChatMsg();
private static Map<String, String> HELP_COMMANDS = Map.ofEntries(
entry
@ -196,148 +200,206 @@ public class BankCommands {
/// @brief Registers all bank commands on the server
/////////////////////////////////////////////////////////////////////////////
public void RegisterCommands() {
// Bank help
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();
// 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"))
)
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);
// Building the argument tree here
dispatcher.getRoot().addChild(bankRoot);
bankRoot.addChild(argList);
bankRoot.addChild(help);
help.addChild(helpTarget);
});
}
/////////////////////////////////////////////////////////////////////////////
/// @fn RemoveFillerWords
///
/// @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;
}
public int SelectBank(ServerPlayerEntity player, String bank) {
System.out.println("Select bank called");
BankManager.GetInstance().ChangeDefaultSelectedBank(player, bank);
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
///
@ -355,166 +417,19 @@ public class BankCommands {
}
}
// Possible code paths ({}=required, []=optionals, ()=explanation):
// REQUIRED (path) = {SetBal|AddMoney|SubMoney} {LONG_ID|BANK_ID} {amount} (Depending on context, changes balance somehow from an account ID or bank)
// REQUIRED (path) = {GetBal} {LONG_ID:BANK_ID} (Gets the balance of a bank account or bank)
// 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);
public int AdminSubtractMoney(ServerPlayerEntity player, Integer amount, String account, String reason) {
AdminBalanceChange(player, account, amount, "subtract", reason);
return 0;
}
AdminBalanceChange(sourcePlayer, accountId, amount, "subtract", optionalReason);
} else {
HelpCommand(sourcePlayer, List.of(HELPCMD_ADMIN_BALANCE_CHANGE));
}
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);
public int AdminAddMoney(ServerPlayerEntity player, Integer amount, String account, String reason) {
AdminBalanceChange(player, account, amount, "add", reason);
return 0;
}
AdminBalanceChange(sourcePlayer, accountId, amount, "add", optionalReason);
} else {
HelpCommand(sourcePlayer, List.of(HELPCMD_ADMIN_BALANCE_CHANGE));
}
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 int AdminSetMoney(ServerPlayerEntity player, Integer amount, String account, String reason) {
AdminBalanceChange(player, account, amount, "set", reason);
return 0;
}
public String GetServerAllowance() {
@ -538,7 +453,6 @@ public class BankCommands {
/// amount
/////////////////////////////////////////////////////////////////////////////
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);
}
@ -582,15 +496,9 @@ public class BankCommands {
///
/// @brief Change the balance of a designated account
/////////////////////////////////////////////////////////////////////////////
public void ManageAccounts(ServerPlayerEntity sourcePlayer, List<String> argList) {
System.out.println("Manage accounts arg list is { " + argList + " }");
if (argList.size() > 0) {
// TODO: For now we assume they reference the bank name and not routing #
String bankName = argList.get(0).toUpperCase();
public int ListBankInfo(ServerPlayerEntity sourcePlayer) {
String bankName = BankManager.GetInstance().GetPlayerSelectedBank(sourcePlayer.getUuidAsString());
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) {
System.out.println("Grabbing user account information");
@ -618,13 +526,13 @@ public class BankCommands {
} else {
sourcePlayer.sendMessage(Text.of(msgFormatter.ColorMsg("That bank does not exist", COLOR_CODE.RED)));
}
} else {
sourcePlayer.sendMessage(Text.of("Unrecognized move command. Please use \"/bank help ACCOUNTS\" for more information."));
}
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()));
return 0;
}
// Possible code paths:
@ -640,39 +548,8 @@ public class BankCommands {
///
/// @brief Command to move account. Read above comment for code paths
/////////////////////////////////////////////////////////////////////////////
public void MoveCommand(ServerPlayerEntity sourcePlayer, List<String> argList) {
if (argList.size() >= 2) {
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."));
}
public int MoveCommand(ServerPlayerEntity sourcePlayer, Integer amount, String fromAccount, String toAccount) {
return 0;
}
// Posible code paths:
@ -713,14 +590,14 @@ public class BankCommands {
/// @brief Shorthand function call-through to CreateCommand for generating
/// an account(s) report.
/////////////////////////////////////////////////////////////////////////////
public void ReportCommand(ServerPlayerEntity sourcePlayer, List<String> argList) {
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
CreateCommand(sourcePlayer, argList);
} else {
sourcePlayer.sendMessage(Text.of("Unrecognized report command. Please run \"/bank help REPORT\" for more information."));
}
}
// public void ReportCommand(ServerPlayerEntity sourcePlayer, List<String> argList) {
// 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
// CreateCommand(sourcePlayer, argList);
// } else {
// sourcePlayer.sendMessage(Text.of("Unrecognized report command. Please run \"/bank help REPORT\" for more information."));
// }
// }
// Possible code paths:
// REQUIRED = {}
@ -746,88 +623,29 @@ public class BankCommands {
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:
// REQUIRED = {ACCOUNT ID|ALIAS}
// OPTIONAL = []
public int CloseCommand(ServerPlayerEntity sourcePlayer, List<String> argList) {
if (argList.size() > 0) {
String accountToClose = argList.get(0);
/*
* CALL TO BANKMGR TO DO STUFF
*/
} else {
sourcePlayer.sendMessage(Text.of("Unrecognized close command. Please see \"/bank help CLOSE\" for more information."));
}
public int CloseCommand(ServerPlayerEntity sourcePlayer, String account) {
// if (argList.size() > 0) {
// String accountToClose = argList.get(0);
// /*
// * CALL TO BANKMGR TO DO STUFF
// */
// } else {
// sourcePlayer.sendMessage(Text.of("Unrecognized close command. Please see \"/bank help CLOSE\" for more information."));
// }
return 0;
}
// Possible code paths:
// required = {account id | alias}
// optional = [default|secondary|backup]
public int SelectCommand(ServerPlayerEntity sourcePlayer, List<String> argList) {
if (argList.size() > 0) {
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."));
}
public int SelectDefaultAccount(ServerPlayerEntity sourcePlayer, String account) {
BankManager.GetInstance().ChangeDefaultPlayerAccount(sourcePlayer, account);
return 0;
}
// Possible code paths:
// REQUIRED = {AMOUNT} {ACCOUNT_ID} [optional]
// OPTIONAL = [reason]
/////////////////////////////////////////////////////////////////////////////
/// @fn WireCommand
///
@ -837,22 +655,8 @@ public class BankCommands {
///
/// @brief Create wire on bank account
/////////////////////////////////////////////////////////////////////////////
public int WireCommand(ServerPlayerEntity sourcePlayer, List<String> argList) {
System.out.println("WireCommand called with arg size " + argList.size());
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."));
}
public int WireCommand(ServerPlayerEntity sourcePlayer, Integer amount, String destAccount, String reason) {
BankManager.GetInstance().InitiateBankFundsTransfer(sourcePlayer, destAccount, amount, reason);
return 0;
}
@ -869,8 +673,10 @@ public class BankCommands {
/// @brief Builds a dynamic help list to the player to see all command
/// 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");
List<String> helpCommand = new ArrayList<String>(Arrays.asList(helpCommandList.split(" ")));
if (helpCommand.size() == 0) {
// General help command
for (Entry<String, String> helpCmd : HELP_COMMANDS.entrySet()) {
@ -917,23 +723,14 @@ public class BankCommands {
///
/// @brief Creates a bank account
/////////////////////////////////////////////////////////////////////////////
public void CreateAccount(ServerPlayerEntity player, List<String> accountArgs) {
System.out.println("Attempting to create checking account with arg list { " + accountArgs + " }");
if (accountArgs.size() > 0) {
String accountType = accountArgs.get(0);
String accountAlias = "NO_ALIAS";
public int CreateAccount(ServerPlayerEntity player, ACCOUNT_TYPE accountType) {
String bank = BankManager.GetInstance().GetPlayerSelectedBank(player.getUuidAsString());
System.out.println("Received bank: " + bank);
// Set the optional account alias for ease-of-reference
if (accountArgs.size() >= 2) {
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"));
if (bank != "") {
BankManager.GetInstance().InitiateBankAccountCreation(bank, player, accountType);
}
return 0;
}
// Possible code paths for /bank create report

View File

@ -8,8 +8,8 @@
package jesse.keeblarcraft.Commands;
import jesse.keeblarcraft.Utils.ChatUtil;
import jesse.keeblarcraft.Utils.ChatUtil.CONSOLE_COLOR;
import jesse.keeblarcraft.Keeblarcraft;
import jesse.keeblarcraft.ChatStuff.ChatMsg;
public class CustomCommandManager {
// 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();
FactionCommands factionCommands = new FactionCommands();
MiscCommands miscCommands = new MiscCommands();
MailCommands mailCommands = new MailCommands();
// REGISTER COMMANDS BELOW
System.out.println(ChatUtil.ColoredString("REGISTERING CUSTOM COMMAND EXTENSIONS BELOW", CONSOLE_COLOR.BLUE));
Keeblarcraft.LOGGER.info("Registering mod commands");
shortcuts.RegisterShortcutCommands();
noteCommands.RegisterNoteCommands();
bankCommands.RegisterCommands();
attributeCommands.RegisterCommands();
factionCommands.RegisterFactionCommands();
miscCommands.RegisterCommands();
mailCommands.RegisterMailCommands();
}
}

View File

@ -2,15 +2,19 @@ package jesse.keeblarcraft.Commands;
import java.util.List;
import com.mojang.brigadier.arguments.IntegerArgumentType;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.context.CommandContext;
import jesse.keeblarcraft.FactionMgr.FactionManager;
import jesse.keeblarcraft.FactionMgr.Callbacks.PlayerCommandFlightCallback;
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.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import net.minecraft.util.ActionResult;
public class FactionCommands {
@ -27,6 +31,13 @@ public class FactionCommands {
var disbandFaction = CommandManager.literal("disband").build();
var promote = CommandManager.literal("promote").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
var createFactionName = CommandManager.argument("faction_name", StringArgumentType.greedyString())
@ -45,10 +56,22 @@ public class FactionCommands {
)
).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)
).build();
var listAll = CommandManager.literal("list")
.executes(context -> ListAllFactions(context.getSource().getPlayer())).build();
@ -61,10 +84,60 @@ public class FactionCommands {
factionNode.addChild(createFaction);
factionNode.addChild(disbandFaction);
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);
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;
}
private int AddPlayerToFaction() {
int retValue = -1;
return retValue;
private int InvitePlayerToFaction(CommandContext<ServerCommandSource> context, ServerPlayerEntity player) {
FactionManager.GetInstance().InvitePlayerToFaction(context.getSource().getPlayer(), player.getUuidAsString(), player.getEntityName());
return 0;
}
/////////////////////////////////////////////////////////////////////////////
@ -130,22 +202,26 @@ public class FactionCommands {
return 0;
}
private int KickPlayerFromFaction() {
private int GetFactionInformation(ServerPlayerEntity player) {
return 0;
}
private int KickPlayerFromFaction(CommandContext<ServerCommandSource> context, ServerPlayerEntity player) {
int retValue = -1;
return retValue;
}
private int PromotePlayerInFaction() {
int retValue = -1;
return retValue;
private int PromotePlayerInFaction(CommandContext<ServerCommandSource> context, ServerPlayerEntity player) {
ServerPlayerEntity caller = context.getSource().getPlayer();
FactionManager.GetInstance().PromotePlayer(caller, player.getUuidAsString(), player.getEntityName());
return 0;
}
private int DemotePlayerInFaction() {
int retValue = -1;
return retValue;
private int DemotePlayerInFaction(CommandContext<ServerCommandSource> context, ServerPlayerEntity player) {
ServerPlayerEntity caller = context.getSource().getPlayer();
FactionManager.GetInstance().DemotePlayer(caller, player.getUuidAsString(), player.getEntityName());
return 0;
}
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;
import org.apache.logging.log4j.core.jmx.Server;
import com.mojang.brigadier.arguments.StringArgumentType;
import jesse.keeblarcraft.Keeblarcraft;
import jesse.keeblarcraft.ConfigMgr.ConfigManager;
import jesse.keeblarcraft.ConfigMgr.GeneralConfig;
import jesse.keeblarcraft.EventMgr.DimensionLoadingEvent;
import jesse.keeblarcraft.Utils.DirectionalVec;
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.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
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.world.World;
import net.minecraft.world.dimension.DimensionType;
public class MiscCommands {
ConfigManager config = new ConfigManager();
@ -75,6 +56,17 @@ public class MiscCommands {
dispatcher.getRoot().addChild(warp);
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) {
@ -132,6 +124,12 @@ public class MiscCommands {
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) {
// if (cmdInitiator.hasPermissionLevel(4)) {

View File

@ -6,13 +6,12 @@ import com.mojang.brigadier.context.CommandContext;
import jesse.keeblarcraft.ConfigMgr.ConfigManager;
import jesse.keeblarcraft.JsonClassObjects.PlayerNote;
import jesse.keeblarcraft.Utils.ChatUtil;
import jesse.keeblarcraft.Utils.ChatUtil.CONSOLE_COLOR;
import jesse.keeblarcraft.Utils.CustomExceptions.DIRECTORY_CREATE_EXCEPTION;
import jesse.keeblarcraft.ChatStuff.ChatMsg;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
public class NoteCommands {
/// Class Variables
@ -21,27 +20,8 @@ public class NoteCommands {
/////////////////////////////////////////////////////////////////////////////
/// @fn NoteCommands
///
/// @brief This classes non-trivial constructor. Ensures creation
// of notes directory exists before commands can be ran
/////////////////////////////////////////////////////////////////////////////
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!
// }
}
public NoteCommands() {}
//TODO: Rework note commands upon story mode release
/////////////////////////////////////////////////////////////////////////////
@ -51,69 +31,69 @@ public class NoteCommands {
/////////////////////////////////////////////////////////////////////////////
public void RegisterNoteCommands() {
// 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) -> {
// dispatcher.register(CommandManager.literal("addnote")
// dispatcher.register(CommandManager.literal("delnote")
// .then(CommandManager.argument("value", StringArgumentType.greedyString())
// .executes(context -> AddNote(StringArgumentType.getString(context, "value"), context))));
// });
// // Command: "/delnote noteIdHere"
// // CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
// // dispatcher.register(CommandManager.literal("delnote")
// // .then(CommandManager.argument("value", StringArgumentType.greedyString())
// // .executes(context -> AddNote(StringArgumentType.getString(context, "value"), context))));
// // });
// Command: "/purgenotes"
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
dispatcher.register(CommandManager.literal("purgenotes")
.executes(context -> PurgeAllNotes(context)));
});
// // Command: "/purgenotes"
// CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
// dispatcher.register(CommandManager.literal("purgenotes")
// .executes(context -> PurgeAllNotes(context)));
// });
// Command: "/modifynote noteIdHere new_note_string_here"
// 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)))));
// // Command: "/modifynote noteIdHere new_note_string_here"
// // 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));
});
// 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"
// // 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))));
// Alias redirects
dispatcher.register(CommandManager.literal("rmnote").redirect(rootDeleteCmd));
dispatcher.register(CommandManager.literal("deletenote").redirect(rootDeleteCmd));
});
// // Alias redirects
// dispatcher.register(CommandManager.literal("rmnote").redirect(rootDeleteCmd));
// dispatcher.register(CommandManager.literal("deletenote").redirect(rootDeleteCmd));
// });
// Command Root: "/notegui"
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
dispatcher.register(CommandManager.literal("notegui")
.executes(context -> { OpenNoteGui(context);
return 0;
}));
});
// // Command Root: "/notegui"
// CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
// dispatcher.register(CommandManager.literal("notegui")
// .executes(context -> { OpenNoteGui(context);
// return 0;
// }));
// });
// Command Root: "/notelist"
// Aliases: "/listnotes"
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
final var rootListNotes = dispatcher.register(CommandManager.literal("notelist")
.executes(context -> { ListNotes(context);
return 0;
}));
// // Command Root: "/notelist"
// // 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));
// });
dispatcher.register(CommandManager.literal("listnotes").redirect(rootListNotes));
});
}
/////////////////////////////////////////////////////////////////////////////
@ -137,11 +117,11 @@ public class NoteCommands {
// Note mgmt
PlayerNote note = new PlayerNote(player.getUuidAsString());
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;
} 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;
@ -166,7 +146,7 @@ public class NoteCommands {
ServerPlayerEntity player = context.getSource().getPlayer();
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;
note.DeleteNote(value);
@ -206,7 +186,8 @@ public class NoteCommands {
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;
}
@ -232,7 +213,7 @@ public class NoteCommands {
PlayerNote note = new PlayerNote(player.getUuidAsString());
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;
} else {
@ -259,11 +240,10 @@ public class NoteCommands {
ServerPlayerEntity player = context.getSource().getPlayer();
PlayerNote notes = new PlayerNote(player.getUuidAsString());
ChatUtil.SendPlayerMsg(player, "Listing all notes...");
for (int i = 0; i <= notes.GetNotebookSize(); i++) {
String individualNote = notes.GetNoteString(i);
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.context.CommandContext;
import jesse.keeblarcraft.Utils.ChatUtil;
import jesse.keeblarcraft.Utils.ChatUtil.CONSOLE_COLOR;
import jesse.keeblarcraft.Keeblarcraft;
import jesse.keeblarcraft.Utils.PlayerChecks;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.minecraft.command.argument.EntityArgumentType;
import net.minecraft.entity.player.PlayerAbilities;
import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource;
@ -24,8 +25,6 @@ import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
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)
public void RegisterShortcutCommands()
@ -39,31 +38,31 @@ public class ShortcutCommands {
// Fly command
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
dispatcher.register(CommandManager.literal("fly")
.executes(context -> { FlightShortcut(context);
return 0;
}));
var flightNode = CommandManager.literal("fly").executes(context -> FlightSpeedShortcut(null, context)).build();
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) -> {
dispatcher.register(CommandManager.literal("fly")
.then(CommandManager.argument("value", IntegerArgumentType.integer())
.executes(context -> FlightSpeedShortcut(IntegerArgumentType.getInteger(context, "value"), context))));
var healNode = CommandManager.literal("heal").executes(context -> HealShortcut(context, null)).build();
var targetPlayer = CommandManager.argument("targetPlayer", EntityArgumentType.player())
.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) -> {
dispatcher.register(CommandManager.literal("heal")
.executes(context -> { HealShortcut(context);
return 0;
}));
var feedNode = CommandManager.literal("feed").executes(context -> FeedShortcut(context, null)).build();
var targetPlayer = CommandManager.argument("targetPlayer", EntityArgumentType.player())
.executes(context -> FeedShortcut(context, EntityArgumentType.getPlayer(context, "targetPlayer"))).build();
dispatcher.getRoot().addChild(feedNode);
feedNode.addChild(targetPlayer);
});
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
@ -111,118 +110,79 @@ public class ShortcutCommands {
retValue = -1;
break;
}
}
else {
player.sendMessage(Text.literal("\033[31m You do not have permissions to run this command! \033[0m"));
}
}
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;
}
private int FlightShortcut(CommandContext<ServerCommandSource> context) {
int retValue = -1;
if (context.getSource().isExecutedByPlayer()) {
private int FlightSpeedShortcut(Integer value, CommandContext<ServerCommandSource> context) {
if (PlayerChecks.HasPermission(context)) {
ServerPlayerEntity player = context.getSource().getPlayer();
if (player.hasPermissionLevel(4)) {
PlayerAbilities abilities = player.getAbilities();
abilities.flying = !abilities.flying; // Toggle flying
abilities.setFlySpeed(DEFAULT_FLIGHT_SPEED); // It seems flight speed is on a 0-1 scale
// Disable flight
if (abilities.flying && value == null) {
abilities.flying = false;
abilities.allowFlying = false;
abilities.setFlySpeed(0);
player.sendMessage(Text.of("Disabled flight"));
player.sendAbilitiesUpdate();
ChatUtil.SendPlayerMsg(player, "You can now fly! Flight speed is " + abilities.getFlySpeed());
} else {
player.sendMessage(Text.literal("You do not have permission for this command"));
}
} else if (!abilities.flying && value == null) {
value = 1;
}
return retValue;
}
private int FlightSpeedShortcut(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) {
// 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();
ChatUtil.SendPlayerMsg(player, "Flight speed set to " + (value));
} else {
player.sendMessage(Text.of("Flight speed set to " + value));
} else if (value != null) {
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;
return 0;
}
///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
///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;
if (context.getSource().isExecutedByPlayer()) {
private int FeedShortcut(CommandContext<ServerCommandSource> context, ServerPlayerEntity target) {
if (PlayerChecks.HasPermission(context)) {
// if target is null, feed ourselves
if (target == null) {
ServerPlayerEntity player = context.getSource().getPlayer();
if (player.hasPermissionLevel(4)) {
player.setHealth(player.getMaxHealth());
ChatUtil.SendPlayerMsg(player, "Healed!");
player.getHungerManager().setExhaustion(0.0f);
player.getHungerManager().setFoodLevel(20); // 20 is hardcoded inside class
player.getHungerManager().setSaturationLevel(10.0f); // 5 is set in constructor, but let's try 10!
player.sendMessage(Text.of("You were just super fed!"));
} 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;
}
private int HealShortcut(CommandContext<ServerCommandSource> context, ServerPlayerEntity target) {
int retValue = -1;
if (PlayerChecks.HasPermission(context)) {
// If no player specified; then heal ourself full HP
if (target == null) {
context.getSource().getPlayer().setHealth(context.getSource().getPlayer().getMaxHealth());
context.getSource().getPlayer().sendMessage(Text.of("Healed!"));
} else {
target.setHealth(target.getMaxHealth());
target.sendMessage(Text.of("You were just healed!"));
context.getSource().getPlayer().sendMessage(Text.of("You healed " + target.getEntityName()));
}
}
return retValue;
}

View File

@ -15,6 +15,7 @@ import java.io.FileWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Paths;
import com.google.common.base.Charsets;
import com.google.common.io.Files;
@ -30,65 +31,110 @@ import org.apache.commons.io.FileUtils;
import java.util.ArrayList;
import java.util.HashMap;
import jesse.keeblarcraft.Utils.ChatUtil;
import jesse.keeblarcraft.Utils.ChatUtil.CONSOLE_COLOR;
import jesse.keeblarcraft.Utils.CustomExceptions.*;
import jesse.keeblarcraft.Keeblarcraft;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtIo;
import net.minecraft.nbt.NbtList;
public class ConfigManager {
// Pedantic empty constructor
private static final String GLOBAL_CONFIG = "config/keeblarcraft/";
public ConfigManager() {}
// CreateFile
//
// Returns true if file is created, will return false if file cannot be created (returns true if already exists)
public Boolean CreateFile(String fileName) throws FILE_CREATE_EXCEPTION {
Boolean ret = false;
File file = new File(fileName);
// Check 1: Does the file already exist?
ret = file.exists();
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) {
// Get a File reference to a file that is created on disk
private File GetFile(String confFile) {
File file = null;
System.out.println("Get file called for " + GLOBAL_CONFIG + confFile);
try {
ret = file.createNewFile();
} catch (IOException e) {
// The file could not be created
throw new FILE_CREATE_EXCEPTION();
System.out.println("GetFile Cur Dir: " + Paths.get("").toAbsolutePath().toString());
file = new File(GLOBAL_CONFIG + confFile);
} catch (Exception e) {}
return file;
}
// Returns the parent path to a given input.
// Ex: /home/Downloads/file.txt will return /home/Downloads/
// Ex: /home/Downloads will return /home/
// Ex: / will return /
private String GetPathOfFile(String file) {
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;
}
}
}
System.out.println("PathOfFile: " + pathToFile);
return pathToFile;
}
// Creates a directory and all necessary parent directories listed in dirname (under global config area)
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 {
success = file.createNewFile();
} catch (Exception e) {
System.out.println("Failed to create file " + fileName);
e.printStackTrace();
}
} 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));
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;
}
// DeleteFile
//
// Returns true if file is deleted, false if could not be deleted or does not exist
public Boolean DeleteFile(String fileName) throws FILE_DELETE_EXCEPTION {
Boolean ret = false;
File file = new File(fileName);
public Boolean DeleteFile(String fileName) {
Boolean success = false;
File file = GetFile(fileName);
// Step 1: Does file exist?
ret = file.exists();
success = !file.exists();
// Step 2: If file exists, attempt to delete
if (ret == true) {
if (!success) {
try {
ret = file.delete();
} catch (SecurityException e) {
throw new FILE_DELETE_EXCEPTION();
success = file.delete();
} catch (Exception e) {
System.out.println("Failed to delete file " + fileName);
e.printStackTrace();
}
} 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));
}
return ret;
return success;
}
/////////////////////////////////////////////////////////////////////////////
@ -103,9 +149,9 @@ public class ConfigManager {
/// @brief Writes NbtList data to disk
/////////////////////////////////////////////////////////////////////////////
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()) {
file.getParentFile().mkdirs();
}
@ -134,9 +180,9 @@ public class ConfigManager {
/////////////////////////////////////////////////////////////////////////////
public HashMap<String, NbtList> ReadAllNbtListFromDirectory(String dir, int listType) {
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();
@ -190,7 +236,7 @@ public class ConfigManager {
FileWriter file;
try {
file = new FileWriter(fileName);
file = new FileWriter(GetFile(fileName));
switch(mode) {
case "w":
file.write(data);
@ -201,13 +247,14 @@ public class ConfigManager {
ret = true;
break;
default:
System.out.println(ChatUtil.ColoredString("Invalid mode to WriteToFile!", CONSOLE_COLOR.RED));
Keeblarcraft.LOGGER.debug("Invalid mode to WriteToFile!!");
break;
}
file.close();
} 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;
@ -223,17 +270,16 @@ public class ConfigManager {
// top-level key.
//
// 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();
fileName = "config/keeblarcraft/" + fileName;
try {
FileWriter writer = new FileWriter(fileName);
FileWriter writer = new FileWriter(GetFile(fileName));
gson.toJson(data, writer);
writer.flush();
writer.close();
} catch (JsonIOException | IOException e) {
System.out.println(ChatUtil.ColoredString("Could not successfully write to json file [" + fileName + "]", CONSOLE_COLOR.RED));
throw new FILE_WRITE_EXCEPTION();
Keeblarcraft.LOGGER.error("Could not successfully write to json file ["+fileName+"]");
e.printStackTrace();
}
}
@ -243,80 +289,32 @@ public class ConfigManager {
public <T> T GetJsonObjectFromFile(String fileName, Class<T> classToConvertTo) throws JsonSyntaxException {
Gson gson = new Gson();
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
// return value in the future - but for now throw JsonSyntaxException no matter what exception is caught
try {
File file = new File(fileName);
File file = GetFile(fileName);
ret = FileUtils.readFileToString(file, "UTF-8");
} catch (NullPointerException e) {
System.out.println(ChatUtil.ColoredString("nullptr exception", CONSOLE_COLOR.RED));
throw new JsonSyntaxException("");
} catch (FileNotFoundException e) {
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("");
} catch (Exception e) {
e.printStackTrace();
System.out.println("Caught an exception in retrieving JSON Object from file " + fileName);
// throw new JsonSyntaxException("");
}
return gson.fromJson(ret, classToConvertTo);
}
public Boolean DoesFileExist(String fileName) {
return new File(fileName).exists(); // untested
return GetFile(fileName) != null;
}
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 {
Boolean ret = false;
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;
public Boolean DeleteDirectory(String dirName) {
return DeleteFile(dirName);
}
// 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
//
// 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>();
try {
return Files.readLines(new File(fileName), Charsets.UTF_8);
return Files.readLines(GetFile(fileName), Charsets.UTF_8);
} catch (IOException e) {
ret.clear();
}

View File

@ -4,7 +4,6 @@ import java.util.ArrayList;
import java.util.List;
import jesse.keeblarcraft.Utils.DirectionalVec;
import jesse.keeblarcraft.Utils.CustomExceptions.FILE_WRITE_EXCEPTION;
public class GeneralConfig {
private static GeneralConfig static_inst;
@ -45,7 +44,6 @@ public class GeneralConfig {
try {
config = cfgMgr.GetJsonObjectFromFile("general.json", ImplementedConfig.class);
System.out.println("Read in config. Random value: " + config.global_spawn.x);
existingFile = true;
} catch(Exception e) {
System.out.println("FAILED TO READ IN GENERALCONFIG");
@ -87,6 +85,27 @@ public class GeneralConfig {
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
///
@ -98,6 +117,7 @@ public class GeneralConfig {
/// @return True if player is new, false if not
/////////////////////////////////////////////////////////////////////////////
public Boolean IsNewPlayer(String uuid) {
System.out.println("Is config null? " + (config == null ? "YES" : "NO"));
System.out.println("IsNewPlayer called. List has: " + config.playerList);
Boolean isNew = !config.playerList.contains(uuid);
@ -125,6 +145,10 @@ public class GeneralConfig {
/////////////////////////////////////////////////////////////////////////////
private class ImplementedConfig {
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
// 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() {
System.out.println("Attempting to write generalconfig to file. Is null? " + (config == null ? "YES" : "NO"));
try {
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;
import jesse.keeblarcraft.CustomBlocks.Blocks.FactionBaseBlock;
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
import net.minecraft.block.AbstractBlock;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
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", 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("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());
// RegisterItem("metaljacket_helmet", exampleItem);
}
}

View File

@ -4,8 +4,7 @@ import java.util.HashMap;
import java.util.Map.Entry;
import jesse.keeblarcraft.ConfigMgr.ConfigManager;
import jesse.keeblarcraft.Utils.ChatUtil;
import jesse.keeblarcraft.Utils.ChatUtil.CONSOLE_COLOR;
import jesse.keeblarcraft.ChatStuff.ChatMsg;
import jesse.keeblarcraft.world.dimension.ModDimensions;
import net.minecraft.nbt.NbtElement;
import net.minecraft.nbt.NbtList;
@ -121,7 +120,7 @@ public class DimensionLoadingEvent {
}
}
} 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;
import java.util.HashMap;
import jesse.keeblarcraft.AttributeMgr.AttributeMgr;
import jesse.keeblarcraft.AttributeMgr.AttributeTree;
import jesse.keeblarcraft.ConfigMgr.ConfigManager;
import jesse.keeblarcraft.ConfigMgr.GeneralConfig;
import jesse.keeblarcraft.Utils.DirectionalVec;
import net.fabricmc.fabric.api.networking.v1.PacketSender;
@ -13,6 +16,13 @@ import net.minecraft.text.Text;
public class PlayerJoinListener {
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
public static PlayerJoinListener GetInstance() {
@ -22,6 +32,28 @@ public class PlayerJoinListener {
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
///
@ -38,12 +70,13 @@ public class PlayerJoinListener {
// Handle skill tree map instance
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)
System.out.println("Running first time login stuff");
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;
}
// 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
@ -502,7 +522,6 @@ public class FactionConfig {
System.out.println("ListOfFactions - map size: " + allFactions.size());
for (Entry<String, WriteableFaction> entry : allFactions.entrySet()) {
System.out.println("Adding fac " + entry.getKey() + " to fac");
facs.add(entry.getKey());
}

View File

@ -12,14 +12,15 @@ package jesse.keeblarcraft.FactionMgr;
import java.util.List;
import jesse.keeblarcraft.ConfigMgr.ConfigManager;
import jesse.keeblarcraft.Utils.ChatUtil;
import jesse.keeblarcraft.Utils.ChatUtil.CONSOLE_COLOR;
import jesse.keeblarcraft.MailSystem.MailMgr;
import jesse.keeblarcraft.Keeblarcraft;
import jesse.keeblarcraft.ChatStuff.ChatMsg;
import jesse.keeblarcraft.Utils.CustomExceptions.FILE_WRITE_EXCEPTION;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
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();
private static FactionManager static_inst;
@ -62,7 +63,7 @@ public class FactionManager {
config.CreateDirectory(FACTION_CFG_FILE);
FlashConfig();
} 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());
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!"));
FlashConfig();
} else {
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());
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) {
creator.sendMessage(Text.of("[Factions]: Could not create faction - faction already exists."));
@ -180,6 +186,45 @@ public class FactionManager {
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) {
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
/////////////////////////////////////////////////////////////////////////////
public void FlashConfig() {
try {
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 jesse.keeblarcraft.ConfigMgr.ConfigManager;
import jesse.keeblarcraft.Utils.ChatUtil;
import jesse.keeblarcraft.Utils.ChatUtil.CONSOLE_COLOR;
import jesse.keeblarcraft.Utils.CustomExceptions.FILE_WRITE_EXCEPTION;
import jesse.keeblarcraft.Keeblarcraft;
import jesse.keeblarcraft.ChatStuff.ChatMsg;
public class PlayerNote {
/// 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
if (!existingFile)
{
System.out.println(ChatUtil.ColoredString("Trying to create new file", CONSOLE_COLOR.BLUE));
try {
thisNote.uuid = uuid;
FlashConfig();
} 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
// a new file with this players 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;
}
}
@ -230,10 +226,6 @@ public class PlayerNote {
/// @brief Writes to the configuration file
/////////////////////////////////////////////////////////////////////////////
public void FlashConfig() {
try {
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.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.ServerTickEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents.ServerStopping;
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
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.entity.BlockEntityType;
import net.minecraft.entity.EntityDimensions;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.entity.mob.HostileEntity;
import net.minecraft.item.Items;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
import net.minecraft.resource.featuretoggle.FeatureSet;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jesse.keeblarcraft.AttributeMgr.AttributeMgr;
import jesse.keeblarcraft.AttributeMgr.AttributeTree;
import jesse.keeblarcraft.BankMgr.BankManager;
import jesse.keeblarcraft.Commands.CustomCommandManager;
import jesse.keeblarcraft.ConfigMgr.SQLUnitTest;
import jesse.keeblarcraft.CustomBlocks.BlockList;
// import jesse.keeblarcraft.CustomBlocks.BlockEntities.MagicChestBlockEntity;
// import jesse.keeblarcraft.CustomBlocks.Blocks.MagicChestBlock;
import jesse.keeblarcraft.CustomBlocks.BlockEntities.BlockEntityRegistration;
import jesse.keeblarcraft.CustomItems.ItemManager;
import jesse.keeblarcraft.EventMgr.DimensionLoadingEvent;
import jesse.keeblarcraft.EventMgr.PlayerJoinListener;
import jesse.keeblarcraft.EventMgr.ServerTickListener;
import jesse.keeblarcraft.GuiMgr.ScreenHandlerRegistration;
import jesse.keeblarcraft.GuiMgr.TreeHandler;
import jesse.keeblarcraft.Utils.CustomExceptions.SETUP_FAILED_EXCEPTION;
import jesse.keeblarcraft.Utils.ChatUtil;
import jesse.keeblarcraft.Utils.Setup;
import jesse.keeblarcraft.Utils.ChatUtil.CONSOLE_COLOR;
public class Keeblarcraft implements ModInitializer {
public static String MOD_ID = "keeblarcraft";
@ -74,28 +65,14 @@ public class Keeblarcraft implements ModInitializer {
@Override
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) {
try {
// 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();
// This is a very special case where this must be in this classes' initializer
// method
/// TODO: Move callbacks somewhere else
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");
PlayerJoinListener.GetInstance().HandleServerJoinEvent(handler, sender, server);
});
@ -120,6 +97,16 @@ public class Keeblarcraft implements ModInitializer {
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!!
ServerTickListener.InitializeServerTicks();
@ -133,6 +120,10 @@ public class Keeblarcraft implements ModInitializer {
// Register the banking system
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
// Register items
@ -140,6 +131,7 @@ public class Keeblarcraft implements ModInitializer {
// Register blocks
BlockList.RegisterBlocks();
BlockEntityRegistration.RegisterBlockEntities();
// World generation
@ -152,14 +144,17 @@ public class Keeblarcraft implements ModInitializer {
.tintColor(234, 183, 8)
.registerPortal();
// Screen handlers
ScreenHandlerRegistration.registerScreenHandlers();
} 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();
}
} else {
// 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 jesse.keeblarcraft.Keeblarcraft;
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;
// 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 String GLOBAL_CONFIG = "config/keeblarcraft/";
public Setup() {
System.out.println(ChatUtil.ColoredString("Running system setup and checks...", CONSOLE_COLOR.BLUE));
}
public Setup() {}
// Returns the singleton object
public static Setup GetInstance() {
@ -51,24 +48,23 @@ public final class Setup {
// First time setup variables
private static final List<String> DIRECTORY_LIST = new ArrayList<String>() {{
add(GLOBAL_CONFIG); // inside config dir
add(GLOBAL_CONFIG + "notes"); // Expect 1 file per player!
add(GLOBAL_CONFIG + "factions"); // Expect 1 file per faction!
add(GLOBAL_CONFIG + "story"); // Expect 1 file per story chapter!
add(GLOBAL_CONFIG + "commands"); // Expect 1 file per command that's configurable!
add(GLOBAL_CONFIG + "events"); // Expect 1 file per event that is configurable!
add(GLOBAL_CONFIG + "bank");
add(GLOBAL_CONFIG + "attributes");
add(GLOBAL_CONFIG + "misc");
add("notes"); // Expect 1 file per player!
add("factions"); // Expect 1 file per faction!
add("story"); // Expect 1 file per story chapter!
add("commands"); // Expect 1 file per command that's configurable!
add("events"); // Expect 1 file per event that is configurable!
add("bank");
add("attributes");
add("misc");
}};
// These will be top-level config files above the directories this mod creates
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(GLOBAL_CONFIG + "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(GLOBAL_CONFIG + "general.json"); // The super general configuration file! (May be removed)
add(GLOBAL_CONFIG + "attributes/general_attribute_config.json");
add("story/general_story_config.json"); // Big config file, determines when players can do certain things at different story levels
add("factions/general_factions_config.json"); // General configuration file for factions stuff
add("events/general_event_config.json"); // General configuration file for story events!
add("general.json"); // The super general configuration file! (May be removed)
add("attributes/general_attribute_config.json");
}};
// RunChecks()
@ -80,45 +76,32 @@ public final class Setup {
ConfigManager conf = new ConfigManager();
// Create directory check
try {
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) {
try {
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.");
} else {
has_write = conf.CreateFile("test_dir/test_note.txt");
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) {
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_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)
if (has_write) {
try {
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;
Keeblarcraft.LOGGER.debug("CHECKS DEBUG: Value of has_write: "+has_write.toString()+". Value of has_read: "+has_read.toString());
// return has_write && has_read;
return true; /// TODO: ConfigManager has been rewritten so much that the above code is out dated. Fix later return true for now
}
// RunSetup
@ -135,9 +118,9 @@ public final class Setup {
for (Integer i = 0; i < DIRECTORY_LIST.size(); i++) {
if ( ! conf.DoesDirectoryExist(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 {
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++) {
if ( ! conf.DoesFileExist(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 {
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) {
throw new SETUP_FAILED_EXCEPTION();
}
} 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();
}
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;
}

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_ore": "Keeblarcraft example block ore",
"block.keeblarcraft.example_statue": "Keeblarcraft example statue",
"block.keeblarcraft.faction_base_block": "Factions Base Block",
"category.keeblarcraft.test": "Keeblarcraft bindings",
"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"
]
},
"mixins": [
"keeblarcraft.mixins.json"
],
"depends": {
"fabricloader": ">=0.15.11",
"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
}
}