Compare commits

...

39 Commits

Author SHA1 Message Date
walrus
f6eb9849e8 update
Some checks failed
build / build (21) (push) Has been cancelled
2025-01-21 18:18:56 -05:00
walrus
fdae73630d temp
Some checks are pending
build / build (21) (push) Waiting to run
2025-01-20 17:41:58 -05:00
walrus
e7afdbd470 faction repair power changed by faction power 2025-01-20 17:41:58 -05:00
walrus
e1dc196c8a [faction-item-repair] Rebase fix 2025-01-20 17:41:58 -05:00
walrus
db4dcfdcb4 [faction-item-repair] Added item repair inside faction area 2025-01-20 17:41:47 -05:00
Jkibbels
bf3b1f6ed2 [factions-banking] More updates
Some checks failed
build / build (21) (push) Has been cancelled
2025-01-20 17:38:53 -05:00
Jkibbels
a36ef1c8f1 [factions-banking] Balanced some of the beacon effects, notable bugs: Flight stays active when player leaves a faction. Need to update block entity to reset player on block break!
Some checks are pending
build / build (21) (push) Waiting to run
2025-01-20 02:28:41 -05:00
Jkibbels
0ed8838de0 [factions-banking] Fixed faction block to be correct faction on first place. Added faction tiers.
Some checks are pending
build / build (21) (push) Waiting to run
2025-01-20 00:20:18 -05:00
Jkibbels
fa5bc741ec [factions-banking] Added faction attachment to block. Still a bit buggy
Some checks are pending
build / build (21) (push) Waiting to run
2025-01-19 21:58:12 -05:00
Jkibbels
7d5fbca603 [factions-banking] Correct faction block GUI draw slot positions with new gui
Some checks are pending
build / build (21) (push) Waiting to run
2025-01-19 20:19:31 -05:00
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
Jkibbels
cb9c3c124e [DEV] Comment updates on everything done over the past 6 weeks
Some checks failed
build / build (21) (push) Has been cancelled
2024-12-06 02:04:09 -05:00
Jkibbels
f7126a0555 [MIXED] Fixed world gen inventory moving + spawn setting
Some checks failed
build / build (21) (push) Has been cancelled
2024-12-05 22:37:27 -05:00
Jkibbels
30ec133358 last minute pre-ship stuff
Some checks failed
build / build (21) (push) Has been cancelled
2024-11-29 04:00:14 -05:00
Jkibbels
b4234d4b6b normalized config files to keeblarcraft config dir inside config
Some checks failed
build / build (21) (push) Has been cancelled
2024-11-24 15:06:34 -05:00
Jkibbels
b048e34eda [MIXED] Some late state banking stuff but also critical first-day features needed for spawn building such as DIMENSION and BIOME additions. FACTIONS also begun implemented
Some checks are pending
build / build (21) (push) Waiting to run
2024-11-23 22:06:00 -05:00
Jkibbels
afbb2533e7 [BANKING] Bug fixing on account number having extra digit + formatting colors for help messages. Includes setting balances with admin command too
Some checks failed
build / build (21) (push) Has been cancelled
2024-11-16 22:56:52 -05:00
Jkibbels
8ece2f2d45 [BANKING] Additions in banking system in order to start getting balance changes... **UNTESTED**
Some checks failed
build / build (21) (push) Has been cancelled
2024-11-13 20:56:20 -05:00
Jkibbels
3abdf9b184 [BANKING] Small bits for future
Some checks failed
build / build (21) (push) Has been cancelled
2024-11-10 01:01:44 -05:00
Jkibbels
a42d196c3c [BANKING] Some tested code that finally works for banking stuff. Much to go still, but more honed in. So much to do :(
Some checks are pending
build / build (21) (push) Waiting to run
2024-11-09 23:21:21 -05:00
Jkibbels
87afc5c8ab [BANKING] Fleshing out more banking information. Logic to populate fast-access bank account list added UNTESTED
Some checks failed
build / build (21) (push) Has been cancelled
2024-11-06 20:01:41 -05:00
Jkibbels
d8a6b7ecd9 [issue/chat-system] GLOBAL CONTENT git br This branch is HIJACKED for all features now until release of server. Inclusion of more financial system; transaction data; and banking information
Some checks failed
build / build (21) (push) Has been cancelled
2024-11-04 19:45:28 -05:00
Jkibbels
5cae7ec313 [issue/chat-system] **UNRELATED** Commit with necessary changes to the banking system for it to be robust enough on release of the server. ONLY banking system changes in here! COMMAND ONLY. NOTHING HOOKED UP YET IN BANK MANAGER!
Some checks failed
build / build (21) (push) Has been cancelled
2024-11-02 04:25:37 -04:00
107 changed files with 8157 additions and 1505 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'
}
@ -10,6 +10,10 @@ base {
archivesName = project.archives_base_name
}
fabricApi {
configureDataGeneration()
}
repositories {
// Add repositories to retrieve artifacts from in here.
// You should only use this when depending on other mods because
@ -22,6 +26,8 @@ repositories {
// includeGroup("cc.tweaked")
// }
// }
maven { url = "https://maven.kyrptonaught.dev" }
maven { url = 'https://maven.minecraftforge.net/' } // for Terrablender
}
loom {
@ -33,7 +39,6 @@ loom {
sourceSet sourceSets.client
}
}
}
dependencies {
@ -42,10 +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-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 {
@ -64,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 ##########################################################################

View File

@ -1,4 +1,5 @@
#!/bin/bash
rm ~/.minecraft/mods/keeblarcraft* # What else could be named this? Really now?
cp build/devlibs/*sources.jar ~/.minecraft/mods
cp build/libs/keeblarcraft-0.0.1.jar ~/.minecraft/mods
cp build/libs/keeblarcraft-0.0.1.jar run/mods
echo Moved minecraft to mods dir

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

@ -0,0 +1,3 @@
// 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

@ -0,0 +1,26 @@
{
"ambient_light": 0.5,
"bed_works": true,
"coordinate_scale": 1.0,
"effects": "minecraft:overworld",
"fixed_time": 12750,
"has_ceiling": false,
"has_raids": false,
"has_skylight": true,
"height": 480,
"infiniburn": "#minecraft:infiniburn_overworld",
"logical_height": 256,
"min_y": 0,
"monster_spawn_block_light_limit": 0,
"monster_spawn_light_level": {
"type": "minecraft:uniform",
"value": {
"max_inclusive": 0,
"min_inclusive": 0
}
},
"natural": false,
"piglin_safe": false,
"respawn_anchor_works": false,
"ultrawarm": false
}

View File

@ -0,0 +1,99 @@
{
"carvers": {
"air": [
"minecraft:cave",
"minecraft:cave_extra_underground",
"minecraft:canyon"
]
},
"downfall": 0.6,
"effects": {
"fog_color": 1800383,
"foliage_color": 13763580,
"grass_color": 1818548,
"sky_color": 11803583,
"water_color": 15414436,
"water_fog_color": 1800383
},
"features": [
[],
[
"minecraft:lake_lava_underground",
"minecraft:lake_lava_surface"
],
[
"minecraft:amethyst_geode",
"minecraft:forest_rock"
],
[],
[],
[],
[
"minecraft:ore_dirt",
"minecraft:ore_gravel",
"minecraft:ore_granite_upper",
"minecraft:ore_granite_lower",
"minecraft:ore_diorite_upper",
"minecraft:ore_diorite_lower",
"minecraft:ore_andesite_upper",
"minecraft:ore_andesite_lower",
"minecraft:ore_tuff"
],
[],
[
"minecraft:spring_water",
"minecraft:spring_lava"
],
[
"minecraft:glow_lichen",
"minecraft:trees_plains",
"minecraft:forest_flowers",
"minecraft:patch_large_fern",
"minecraft:brown_mushroom_normal",
"minecraft:red_mushroom_normal",
"minecraft:patch_sugar_cane",
"minecraft:patch_pumpkin"
],
[
"minecraft:freeze_top_layer"
]
],
"has_precipitation": true,
"spawn_costs": {},
"spawners": {
"ambient": [],
"axolotls": [],
"creature": [
{
"type": "minecraft:sheep",
"maxCount": 4,
"minCount": 4,
"weight": 12
},
{
"type": "minecraft:pig",
"maxCount": 4,
"minCount": 4,
"weight": 10
},
{
"type": "minecraft:chicken",
"maxCount": 4,
"minCount": 4,
"weight": 10
},
{
"type": "minecraft:cow",
"maxCount": 4,
"minCount": 4,
"weight": 8
}
],
"misc": [],
"monster": [],
"underground_water_creature": [],
"water_ambient": [],
"water_creature": []
},
"temperature": 0.7
}

View File

@ -10,13 +10,15 @@
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.AttributeMgr.AttributeNodes.FactionNodes.FactionItemRepair;
import jesse.keeblarcraft.ConfigMgr.ConfigManager;
import jesse.keeblarcraft.Utils.ChatUtil;
public class AttributeMgr {
ConfigManager config;
@ -46,13 +48,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 +71,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 +93,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 +114,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 +147,9 @@ 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);
RegisterAttributeClass(FactionItemRepair.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,138 @@
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.FactionTier;
import jesse.keeblarcraft.FactionMgr.Callbacks.PlayerInBaseCallback;
import jesse.keeblarcraft.FactionMgr.FactionTier.FactionTierEnum;
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 int potionEffectLastingTimeTicks = 200; // 20 ticks per second makes this 10 seconds
private Integer timerLengthMillis = 5000; // The default potion length is 10 seconds; so reset every 5 to be sure!
private Boolean resetTimer = true;
private Timer timer = new Timer();
@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 Integer GetBeaconAmplifier(FactionTierEnum tier) {
switch (tier) {
case TIER_I:
case TIER_II:
beaconStrength = 0;
break;
case TIER_III:
beaconStrength = 1;
break;
case TIER_IV:
beaconStrength = 2;
break;
case TIER_V:
beaconStrength = 3;
break;
case TIER_VI:
beaconStrength = 8;
break;
default:
// Invalid case; in which case the beacon probably should do nothing
beaconStrength = 0;
break;
}
return beaconStrength;
}
private void ApplyEffects(ServerPlayerEntity player, FactionTierEnum tier) {
// player.setAbsorptionAmount(absorptionAmnt);
// Duration is in ticks
beaconStrength = GetBeaconAmplifier(tier);
// Tier 2 effects
if (FactionTier.IsGreaterOrEqualTo(tier, FactionTierEnum.TIER_II)) {
StatusEffectInstance regen = new StatusEffectInstance(StatusEffects.REGENERATION, potionEffectLastingTimeTicks, beaconStrength, true, true, true);
StatusEffectInstance fire = new StatusEffectInstance(StatusEffects.FIRE_RESISTANCE, potionEffectLastingTimeTicks, beaconStrength, true, true, true);
player.addStatusEffect(regen);
player.addStatusEffect(fire);
}
// Tier 3 effects
if (FactionTier.IsGreaterOrEqualTo(tier, FactionTierEnum.TIER_III)) {
StatusEffectInstance hero = new StatusEffectInstance(StatusEffects.HERO_OF_THE_VILLAGE, potionEffectLastingTimeTicks, beaconStrength, true, true, true);
StatusEffectInstance haste = new StatusEffectInstance(StatusEffects.HASTE, potionEffectLastingTimeTicks, beaconStrength, true, true, true);
player.addStatusEffect(hero);
player.addStatusEffect(haste);
}
// Tier 4 effects
if (FactionTier.IsGreaterOrEqualTo(tier, FactionTierEnum.TIER_IV)) {
StatusEffectInstance conduit = new StatusEffectInstance(StatusEffects.CONDUIT_POWER, potionEffectLastingTimeTicks, 0, true,true, true);
StatusEffectInstance luck = new StatusEffectInstance(StatusEffects.LUCK, potionEffectLastingTimeTicks, beaconStrength, true, true, true);
StatusEffectInstance absorption = new StatusEffectInstance(StatusEffects.ABSORPTION, potionEffectLastingTimeTicks, beaconStrength, true, true, true);
StatusEffectInstance waterBreathing = new StatusEffectInstance(StatusEffects.WATER_BREATHING, potionEffectLastingTimeTicks, beaconStrength, true, true, true);
player.addStatusEffect(conduit);
player.addStatusEffect(luck);
player.addStatusEffect(absorption);
player.addStatusEffect(waterBreathing);
}
// Tier 5 effects
if (FactionTier.IsGreaterOrEqualTo(tier, FactionTierEnum.TIER_V)) {
StatusEffectInstance resistance = new StatusEffectInstance(StatusEffects.RESISTANCE, potionEffectLastingTimeTicks, beaconStrength, true, true, true);
StatusEffectInstance strength = new StatusEffectInstance(StatusEffects.STRENGTH, potionEffectLastingTimeTicks, beaconStrength, true, true, true);
StatusEffectInstance dolphins = new StatusEffectInstance(StatusEffects.DOLPHINS_GRACE, potionEffectLastingTimeTicks, beaconStrength, true, true, true);
player.addStatusEffect(resistance);
player.addStatusEffect(strength);
player.addStatusEffect(dolphins);
}
// Tier 6 effects
if (FactionTier.IsGreaterOrEqualTo(tier, FactionTierEnum.TIER_VI)) {
StatusEffectInstance freeHealth = new StatusEffectInstance(StatusEffects.HEALTH_BOOST, potionEffectLastingTimeTicks, beaconStrength, true, true, true);
player.addStatusEffect(freeHealth);
}
}
@Override
public void RegisterCallbacks() {
PlayerInBaseCallback.EVENT.register((player, world, power, factionTier) -> {
if (resetTimer) {
// The timer is super necessary because some effects (like regen) will not actually regen the player unless they can run for a few seconds
timer.schedule(new TimerTask() {
@Override
public void run() {
ApplyEffects((ServerPlayerEntity) player, factionTier);
resetTimer = true;
}
}, timerLengthMillis);
resetTimer = false;
}
return ActionResult.PASS;
});
}
}

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, power, factionTier) -> {
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, power, factionTier) -> {
// 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, power, factionTier) -> {
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, power, factionTier) -> {
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

@ -0,0 +1,113 @@
package jesse.keeblarcraft.AttributeMgr.AttributeNodes.FactionNodes;
import java.util.Date;
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.Commands.FactionCommands;
import jesse.keeblarcraft.FactionMgr.FactionManager;
import jesse.keeblarcraft.FactionMgr.Callbacks.PlayerInBaseCallback;
import jesse.keeblarcraft.FactionMgr.FactionTier.FactionTierEnum;
import net.minecraft.item.ItemStack;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.ActionResult;
public class FactionItemRepair extends AbstractNode {
private Boolean resetTimer = true;
Timer timer = new Timer();
Date date = new Date();
int tempValue = 0;
int repairTier = -1;
@Override
public String GetNodeTitle() {
return "faction_item_repair";
}
@Override
public String GetNodeDescription() {
; return "Repairs item and too durability while a player is inside the faction";
}
@Override
public HashMap<String, List<String>> GetDetails() {
HashMap<String, List<String>> ret = new HashMap<String, List<String>>();
ret.put("Faction Item Repair", List.of("Repairs a players items and tools in their durability while they are at the faction home!",
"The repair rate is 1 durability every 5 seconds for each item not at max durability"));
return ret;
}
/*
* BaseRepair tier 1 speed
*/
public void RepairInventory(ServerPlayerEntity player, FactionTierEnum tier) {
//probably will end up using this List<DefaultedList<ItemStack>> combinedInventory; from PlayerInventory
//PlayerInventory playerInv = player.getInventory();// main is all your inventory you can see exluding your off hand and armor i think
switch (tier) {//should be the faction power
case TIER_I:
repairTier = -1;
break;
case TIER_II:
repairTier = -2;
break;
case TIER_III:
repairTier = -3;
break;
case TIER_IV:
repairTier = -4;
break;
case TIER_V:
repairTier = -5;
break;
case TIER_VI:
repairTier = -6;
break;
default:
repairTier = -1;
break;
}
for (ItemStack item : player.getInventory().main) {
if (item.isDamageable() && item.isDamaged()) {
item.setDamage(item.getDamage() - repairTier);
}
}
for (ItemStack item : player.getInventory().armor) {
if (item.isDamageable() && item.isDamaged()) {
item.setDamage(item.getDamage() - repairTier);
}
}
if (player.getInventory().offHand.isEmpty()) { return; }
if (player.getOffHandStack().isDamaged()) {
player.getOffHandStack().setDamage(player.getOffHandStack().getDamage() - repairTier);
}
return;
}
@Override
public void RegisterCallbacks() {
PlayerInBaseCallback.EVENT.register((player, world, power, tier) -> {
/* DO STUFF - REMEMBER: This function is called EVERY tick a player is inside the base! That's EVERY tick*/
if (resetTimer) {
resetTimer = false;
// Make a new timer object here to count down to reset the 'canRepair object'
// Reset the 'resetTimer' bool to true IN the timer
timer.schedule(new TimerTask() {
@Override
public void run() {
RepairInventory((ServerPlayerEntity) player, tier);
resetTimer = true;
}
}, 15000);//TESTING PURPOSES WILL CAHNGE HIGHER VALUE
}
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,140 @@
package jesse.keeblarcraft.BankMgr;
import java.util.Random;
/*
Account number composition:
EXAMPLE:
KCSB-9284-0JKI94358732
EXPLANATION:
The composition of the above number is mostly not random. The composition is 'C' = LETTER, and the first 4 represent the 4-letter combination
of the financial establishment (think of the stock market NASDAQ). The first 4 '#' (# = Number) digits represent the ROUTING number of the bank.
The next '#' (in its own brackets) represents ACCOUNT TYPE. This means the mod supports up to 9 configurations; some examples would be CHECKING
or SAVINGS. The next three '#' (in their own brackets too) will be the first three letters of the username of the account holder inside an ASCII
table. If the letter is not UTF 8 compatible - then the default will be '0'. The LAST eight '#' (not in brackets) are randomly generated via Java.
* Please note that the brackets in this example are only for demonstration of separating numbers from each other. They do not show up at all in generation.
CCCC-####-[#][###]########
* Additional note - enums are not implicitly integers under the hood like C++; so, a financial establishment could pass in ANY 0-9 digit for "account type" and
each establishment is allowed to treat that however they want. In one banks case it make checking accounts 3; but in anothers it's 4. This is a general programming
note for now. It is probably best to keep this consistent in your server/mod so tellers can understand them universally.
*/
/////////////////////////////////////////////////////////////////////////////
/// @class AccountNumberGenerator
///
/// @brief Utility class for the banking system. Can generate new account
/// numbers based on parameters and parse the account number
/////////////////////////////////////////////////////////////////////////////
public class AccountNumberGenerator {
/////////////////////////////////////////////////////////////////////////////
/// @fn AccountNumberGenerator
///
/// @param[in] symbol is the bank/finance institution symbol
///
/// @param[in] routingNumber is the bank routing number
///
/// @param[in] accountType is the type of account being generated
///
/// @param[in] username is the players username who needs the account
///
/// @brief Creates a new account number for a user
///
/// @return String representation of account number
/////////////////////////////////////////////////////////////////////////////
public static String GenerateNewAccountNumber(String symbol, Integer routingNumber, Integer accountType, String username) {
String generatedAccountNumber = symbol + "-" + routingNumber + "-" + accountType;
// Block to translate part of username into number format
for (int i = 0; i < 3; i++) {
if (username.length() >= 3 && username.charAt(i) <= 255) { // 255 is largest ASCII value. Might be a sloppy check; can always test later (if I find someone with non ASCII)
Integer asciiValueOfLetter = (int) username.charAt(i);
String strValueOfAscii = asciiValueOfLetter.toString();
strValueOfAscii = strValueOfAscii.substring(0, 1);
generatedAccountNumber += strValueOfAscii;
} else if (username.charAt(i) <= 255) { // Case where length is less than 3 but is still in ASCII table
Integer asciiValueOfLetter = (int) username.charAt(i);
String strValueOfAscii = asciiValueOfLetter.toString();
strValueOfAscii = strValueOfAscii.substring(0, 1);
generatedAccountNumber += strValueOfAscii;
} else { // Case where the length is less than 3 and is not standard ASCII
generatedAccountNumber += "0";
}
}
// Guarentee an 8 digit number. 10000000 is floor and max rng int is at most 89999999. Combined they total 99999999
Random rng = new Random();
Integer randInteger = 10000000 + rng.nextInt(89999999);
generatedAccountNumber += randInteger;
return generatedAccountNumber;
}
// the below functions must be given a key generated from the above function or they will combust into
// not less than one million pieces! :)
/////////////////////////////////////////////////////////////////////////////
/// @fn GetFinancialSymbolFromId
///
/// @param[in] accountId is the generated account number
///
/// @brief Gets the financial symbol from the account id
///
/// @return String representation of financial symbol
/////////////////////////////////////////////////////////////////////////////
public static String GetFinancialSymbolFromId(String accountId) {
return accountId.substring(0, 4);
}
/////////////////////////////////////////////////////////////////////////////
/// @fn GetRoutingNumberFromId
///
/// @param[in] accountId is the generated account number
///
/// @brief Gets the routing number from the account id
///
/// @return Returns the integer of the account number
/////////////////////////////////////////////////////////////////////////////
public static Integer GetRoutingNumberFromId(String accountId) {
return Integer.parseInt(accountId.substring(5, 9));
}
/////////////////////////////////////////////////////////////////////////////
/// @fn GetAccountNumberFromId
///
/// @param[in] accountId is the generated account number
///
/// @brief Gets the smaller account identifier from the entire account
/// identifier. This would be the ACCOUNT TYPE + GENERATED NUMBER
/// on the end of the whole identifier (so no financial symbol and
/// no routing number)
///
/// @return String representation of small account number
/////////////////////////////////////////////////////////////////////////////
public static String GetAccountNumberFromId(String accountId) {
return accountId.substring(10);
}
/////////////////////////////////////////////////////////////////////////////
/// @fn GetAccountTypeFromId
///
/// @param[in] accountId is the generated account number
///
/// @brief Gets the account type from account ID
///
/// @note The string representation of a valid account ID will have
/// '0' - '9' (range) in this position; so, subtracting 48 from
/// the ASCII returns the actual account number as an integer.
///
/// @return Integer representing account type (0-9)
/////////////////////////////////////////////////////////////////////////////
public static Integer GetAccountTypeFromId(String accountId) {
return ((int) accountId.charAt(10)) - 48; // ASCII 0 starts at 48. One must subtract 48 to be correct.
}
}

View File

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

View File

@ -1,256 +1,316 @@
package jesse.keeblarcraft.BankMgr;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.util.Map.Entry;
import jesse.CommonServerUtils;
import jesse.keeblarcraft.BankMgr.BankAccountType.ACCOUNT_TYPE;
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.MinecraftServer;
import net.minecraft.server.PlayerManager;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
public class BankManager {
BankManagerFile bankInfo = new BankManagerFile(); // not sure why we make another one but i guess so we
ConfigManager config = new ConfigManager(); // for read and write privs
CommonServerUtils commonServerUtils = new CommonServerUtils();
// The bank manager takes care of routing any and all transactions throughout the server.
// It is a singleton object that is active throughout the mods lifetime and will cache players accounts
// when they log in to avoid constant look-ups through JSON.
public final class BankManager {
private static BankManager static_inst;
public BankManager(String uuid) {
Boolean existingFile = false;
try {
bankInfo = config.GetJsonObjectFromFile("bank/" + uuid + ".json", BankManagerFile.class);
existingFile = true;
} catch (Exception e) {
// Do nothing. This means the file does not exist
public static BankManager GetInstance() {
if (static_inst == null) {
static_inst = new BankManager();
}
return static_inst;
}
// 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 {
FlashConfig(bankInfo.uuid);
} catch (Exception e) {
System.out.println(ChatUtil.ColoredString("Could not write to file", CONSOLE_COLOR.RED));
private class PlayerBankConfig {
List<String> activeBanks = new ArrayList<String>(); // List of all banks a player has accounts in
String defaultSelectedBank = "";
String defaultSelectedAccount = "";
}
// Key = player uuid
// Val = player config
HashMap<String, PlayerBankConfig> playerConfigs = new HashMap<String, PlayerBankConfig>(); // Stores global detail information for bank mgr to use
private static Integer KEEBLARCRAFT_SERVER_BANK_ID = 1000; // Server global bank (default bank on server)
ConfigManager config = new ConfigManager();
// KEY = Bank routing number
// Val = Bank object
private HashMap<Integer, IndividualBank> banks = new HashMap<Integer, IndividualBank>();
// KEY = Bank name
// Val = Bank routing number
private HashMap<String, Integer> bankNameFastMap = new HashMap<String, Integer>();
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
/////////////////////////////////////////////////////////////////////////////
/// @fn InitializeBanks
///
/// @brief Initializes all the banks on the server at construction time
/////////////////////////////////////////////////////////////////////////////
public void InitializeBanks() {
banks.put(KEEBLARCRAFT_SERVER_BANK_ID, new IndividualBank(Integer.toString(KEEBLARCRAFT_SERVER_BANK_ID), "KeeblarcraftGlobal"));
// Initialize fast map
for (Entry<Integer, IndividualBank> bank : banks.entrySet()) {
bankNameFastMap.put(bank.getValue().GetBankName(), bank.getValue().GetRoutingNumber());
}
}
/////////////////////////////////////////////////////////////////////////////
/// @fn GetAllBankNames
///
/// @return List of all the banks that exist on a server
/////////////////////////////////////////////////////////////////////////////
public List<String> GetAllBankNames() {
List<String> names = new ArrayList<String>();
// Iterate through all banks in the list to get their names
for (Entry<Integer, IndividualBank> bank : banks.entrySet()) {
names.add(bank.getValue().GetBankName());
}
return names;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn GetBankByRoutingNumber
///
/// @return The IndividualBank object by routing number if the bank exists
/////////////////////////////////////////////////////////////////////////////
public IndividualBank GetBankByRoutingNumber(Integer number) {
IndividualBank bank = null;
if (banks.containsKey(number)) {
bank = banks.get(number);
}
return bank;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn GetBankByName
///
/// @return The Individualbank object by name if the bank exists
/////////////////////////////////////////////////////////////////////////////
public IndividualBank GetBankByName(String name) {
IndividualBank bank = null;
System.out.println("GetBankByName called with value " + name);
if (bankNameFastMap.containsKey(name)) {
System.out.println("Value of bank with name is " + bankNameFastMap.get(name));
System.out.println("Banks map size is " + banks.size());
bank = banks.get(bankNameFastMap.get(name));
}
System.out.println("Returning bank information");
return bank;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn ChangeDefaultPlayerAccount
///
/// @param[in] player Player object to change default accounts of
///
/// @param[in] The new default account global account identifier
///
/// @return Changes the players default account at a selected bank
/////////////////////////////////////////////////////////////////////////////
public void ChangeDefaultPlayerAccount(ServerPlayerEntity player, String newDefaultAccount) {
String bankName = AccountNumberGenerator.GetFinancialSymbolFromId(newDefaultAccount);
// 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);
// 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()).defaultSelectedAccount = newDefaultAccount;
}
} else {
System.out.println(ChatUtil.ColoredString("Moving on", CONSOLE_COLOR.BLUE));
}
if ("".equals(bankInfo.uuid)) {
System.out.println(ChatUtil.ColoredString("Assigning new config file for this uuid. No previous existing",
CONSOLE_COLOR.BLUE));
bankInfo.uuid = uuid;
player.sendMessage(Text.of("Could not change default selected account. Bank does not exist!"));
}
}
//this class is the structure for the hashmap in BankManagerFile
private class BankManagerMetaData {
public BankManagerMetaData(long money, String reason, long payment, String otherParty, Integer time) {
this.balance = money;
this.reason = reason;
this.payment = payment;
this.otherParty = otherParty;
this.time = time;
// 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;
}
long balance = 0;
String reason; //not sure why my compiler is saying unused
long payment;
String otherParty;
Integer time;
// 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."));
}
}
// This is the general bank account of the read-in config for the player uuid ||| the class that gets converted into a json for the players file
public class BankManagerFile {
// Players uuid is the name of the file
String uuid;
/////////////////////////////////////////////////////////////////////////////
/// @fn AdminChangeFunds
///
/// @param[in] initiator The player object who is initiating this call
///
/// @param[in] accountId The account to change funds of
///
/// @param[in] amount The amount to change funds of in changeType
///
/// @param[in] changeType The type of funds change being initiated
///
/// @param[in] optionalReason The optional reason of changing funds
///
/// @brief Command manager to initiate a funds change from an admins
/// perspective (safe guards dropped). Valid changeTypes are
/// found inside the switch-case statement in the below function
/////////////////////////////////////////////////////////////////////////////
public void AdminChangeFunds(ServerPlayerEntity initiator, String accountId, Integer amount, String changeType, String optionalReason) {
// Check to make sure account id exists
Integer routingNum = AccountNumberGenerator.GetRoutingNumberFromId(accountId);
IndividualBank bankFromRout = GetBankByRoutingNumber(routingNum);
// Contents of file
/*
* Example:
* player_uuid_here:
* {
* "1":
* {
* "balance": "10";
* "reason": "tax evasion";
* "payment": $-44
* "other party": "jt";
* "time": "30";
* }
* "2":
* {
* Etc.
* }
* }
*/
public HashMap<String, BankManagerMetaData> bank = new HashMap<String, BankManagerMetaData>();
}
System.out.println("Is bank null? " + (bankFromRout == null ? "YES" : "NO"));
System.out.println("Bank specified: " + bankFromRout);
System.out.println("Routing number: " + routingNum);
// Verify bank exists
if (bankFromRout != null) {
// Verify account exists
System.out.println("accountNumber is " + accountId);
String accountNumber = AccountNumberGenerator.GetAccountNumberFromId(accountId);
System.out.println("changeType is " + changeType);
public long GetBalance() {
long ret = 0;
for (Entry<String, BankManagerMetaData> entry : bankInfo.bank.entrySet()) {
ret = entry.getValue().balance;
}
return ret;
}
//https://maven.fabricmc.net/docs/fabric-api-0.34.8+1.17/net/fabricmc/fabric/api/networking/v1/PlayerLookup.html maybe this for getting the players im still not sure
public void SetBalance(Integer newBalance, String reason, String otherParty) {
Integer transactionNumber = bankInfo.bank.size();
bankInfo.bank.put(transactionNumber.toString(),
new BankManagerMetaData(newBalance, reason, newBalance, otherParty, 0));
FlashConfig(PlayerListNameChecker(otherParty));
}
public void AddMoney(String reason, long payment, String otherParty) {
if (bankInfo.bank.size() > 0) {
for (Entry<String, BankManagerMetaData> entry : bankInfo.bank.entrySet()) {
entry.getValue().balance += payment;
entry.getValue().reason = "SERVER: " + reason;
entry.getValue().payment = payment;
entry.getValue().otherParty = otherParty;
entry.getValue().time = 0;
switch (changeType) {
case "add":
bankFromRout.AddMoneyToAccount(accountNumber, amount);
break;
case "subtract":
bankFromRout.SubtractMoneyFromAccount(accountNumber, amount);
break;
case "set":
bankFromRout.SetMoneyOnAccount(accountNumber, amount);
break;
default:
System.out.println("The operation that was specified by the developer does not exist. Valid operations are add/subtract/set");
break;
}
} else {
bankInfo.bank.put(bankInfo.uuid, new BankManagerMetaData(payment, reason, payment, otherParty, 0));
initiator.sendMessage(Text.of("That bank does not exist!"));
}
}
FlashConfig(PlayerListNameChecker(otherParty));
}
/////////////////////////////////////////////////////////////////////////////
/// @fn InitiateBankFundsTransfer
///
/// @param[in] fromPlayer is the player funds are coming out of
///
/// @param[in] toAccount is the account the funds are going to
///
/// @param[in] amount is the amount of money coming from the player
///
/// @brief Initiate a funds transfer between accounts or banks
/////////////////////////////////////////////////////////////////////////////
public void InitiateBankFundsTransfer(ServerPlayerEntity fromPlayer, String toAccount, Integer amount, String reason) {
// Get player default selection
String fromAccount = playerConfigs.get(fromPlayer.getUuidAsString()).defaultSelectedAccount;
public void SubtractBalance(String reason, long payment, String otherParty) {
if (bankInfo.bank.size() > 0) {
for (Entry<String, BankManagerMetaData> entry : bankInfo.bank.entrySet()) {
entry.getValue().balance -= payment;//not working?
entry.getValue().reason = "SERVER: " + reason;
entry.getValue().payment = payment;
entry.getValue().otherParty = otherParty;
entry.getValue().time = 0;
String fromAccountSymbol = AccountNumberGenerator.GetFinancialSymbolFromId(fromAccount);
String toAccountSymbol = AccountNumberGenerator.GetFinancialSymbolFromId(toAccount);
System.out.println("InitiateBankFundsTransfer: FROM_ACCOUNT, FROM_ACCOUNT_SYMBOL, TO_ACCOUNT_SYMBOL: " + fromAccount + ", " + fromAccountSymbol + ", " + toAccountSymbol);
Integer destRoutingNumber = bankNameFastMap.get(toAccountSymbol);
Integer fromRoutingNumber = bankNameFastMap.get(fromAccountSymbol);
IndividualBank destBank = banks.get(destRoutingNumber);
IndividualBank fromBank = banks.get(fromRoutingNumber);
// Verify banks exist
if (destBank != null && fromBank != null) {
if (fromBank.IsValidWithdrawal(amount, fromAccount)) {
fromBank.SubtractMoneyFromAccount(fromAccount, amount);
destBank.AddMoneyToAccount(toAccount, amount);
fromPlayer.sendMessage(Text.of("[" + fromAccountSymbol + "]: Your wire has processed."));
} else {
fromPlayer.sendMessage(Text.of("[" + fromAccountSymbol + "]: You are not allowed to make this withdrawal."));
}
} else {
bankInfo.bank.put(bankInfo.uuid, new BankManagerMetaData(0, reason, payment, otherParty, 0));
}
FlashConfig(PlayerListNameChecker(otherParty));
}
public void Wire(String reason, long payment, String otherParty) {
if (bankInfo.bank.size() > 0) {
for (Entry<String, BankManagerMetaData> entry : bankInfo.bank.entrySet()) {
entry.getValue().balance -= payment;
entry.getValue().reason = reason;
entry.getValue().payment = payment;
entry.getValue().otherParty = otherParty;
entry.getValue().time = 0;
if (payment <= 0) {
// add a error for the PLAYER not the server
return;
}
}
// make a server instance
MinecraftServer server = CommonServerUtils.GetServerInstance();
String[] playerList = server.getPlayerNames();
//NOT SURE IF THIS FOR LOOP IS ONE OFF COULD POSSIBLEY BE SO IF NO ONE IS GETTING MONEY DOUBLE CHECK FOR LOOP
for (int i = 0; i < playerList.length; i++) {
System.out.println(ChatUtil.ColoredString("PLAYERS: " + playerList, CONSOLE_COLOR.YELLOW));
if (playerList[i] == otherParty) {
System.out.println(ChatUtil.ColoredString("Found Player: " + otherParty, CONSOLE_COLOR.GREEN));
// we will use getuuidbyname then set the other VALID players bank BE SURE TO
// MAKE THEM A BANK FIRST IF THEY DONT HAVE ONE fortnite forever
if (config.GetFile("bank/" + GetUuidByName(server, otherParty) + ".json").size() < 1) {
BankManagerFile newBankInfo = new BankManagerFile();
BankManagerMetaData newBank = new BankManagerMetaData(0, "Account Created", 0, "Server", 0);
newBankInfo.bank.put(GetUuidByName(server, otherParty).toString(), newBank);
try {
config.WriteToJsonFile("bank/" + newBankInfo.uuid + ".json", newBankInfo);
} catch (FILE_WRITE_EXCEPTION e) {
System.out.println(ChatUtil.ColoredString("Could not flash notes configuration file", CONSOLE_COLOR.RED));
return;
fromPlayer.sendMessage(Text.of("Something went wrong! Either your bank or their bank does not exist. You shouldn't get this error!"));
}
}
//since the other player has a account now and we have access to it we can start fucking around
BankManagerFile newBankInfo = new BankManagerFile();
newBankInfo = config.GetJsonObjectFromFile("bank/" + GetUuidByName(server, otherParty) + ".json", BankManagerFile.class);
// for now we will only use adding valance and not subtracting since that dosent make any sense
for (Entry<String, BankManagerMetaData> entry : newBankInfo.bank.entrySet()) {
entry.getValue().balance += payment;
entry.getValue().reason = reason;
entry.getValue().payment = payment;
entry.getValue().otherParty = otherParty;
entry.getValue().time = 0;
}
//cannot use regular flash config since the hard coded values need to add agurment for the uuid
//needs to be inside the player check
FlashConfig(newBankInfo.uuid);
try {
config.WriteToJsonFile("bank/" + newBankInfo.uuid + ".json", bankInfo);
} catch (FILE_WRITE_EXCEPTION e) {
System.out.println(ChatUtil.ColoredString("Could not flash notes configuration file", CONSOLE_COLOR.RED));
public void InitiateBankAccountClosure(String bankIdentifier, ServerPlayerEntity player, String bankAccountId) {
}
/////////////////////////////////////////////////////////////////////////////
/// @fn GetDefaultSelectedAccount
///
/// @param[in] playerUuid is the player to get their default account
///
/// @param[in] bankIdentifier is the bank the default account is at
///
/// @brief Gets a players default account
///
/// @return The global account identifier of the default selected account
/////////////////////////////////////////////////////////////////////////////
public String GetDefaultSelectedAccount(String playerUuid, String bankIdentifier) {
String account = "";
if (playerConfigs.containsKey(playerUuid)) {
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
///
/// @param[in] bankIdentifier is the bank routing number
///
/// @param[in] player is the player object trying to create account
///
/// @paran[in] accountType Is the type of account the player wants to make
///
/// @brief Initiates a bank account creation with a bank
/////////////////////////////////////////////////////////////////////////////
public void InitiateBankAccountCreation(String bankIdentifier, ServerPlayerEntity player, ACCOUNT_TYPE accountType) {
Boolean success = false;
IndividualBank bank = GetBankByName(bankIdentifier);
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 {
System.out.println(ChatUtil.ColoredString("Player Not Found: " + otherParty, CONSOLE_COLOR.RED));
return;
}
}
} else {
System.out.println(ChatUtil.ColoredString("You need to finance better", CONSOLE_COLOR.RED));
return;
}
}
String GetUuidByName(MinecraftServer server, String playerName) {
PlayerManager playerManager = server.getPlayerManager();
ServerPlayerEntity player = playerManager.getPlayer(playerName);
if (player.getUuid() != null) {
return player.getUuidAsString();
} else {
return "";
}
}
String PlayerListNameChecker(String otherParty) {
MinecraftServer server = CommonServerUtils.GetServerInstance();
String[] playerList = server.getPlayerNames();
for (int i = 0; i < playerList.length; i++) {
System.out.println(ChatUtil.ColoredString("PLAYERS: " + playerList, CONSOLE_COLOR.YELLOW));
if (playerList[i] == otherParty) {
System.out.println(ChatUtil.ColoredString("Found Player: " + otherParty, CONSOLE_COLOR.GREEN));
// we will use getuuidbyname then set the other VALID players bank BE SURE TO
// MAKE THEM A BANK FIRST IF THEY DONT HAVE ONE fortnite forever
if (config.GetFile("bank/" + GetUuidByName(server, otherParty) + ".json").size() < 1) {
BankManagerFile newBankInfo = new BankManagerFile();
BankManagerMetaData newBank = new BankManagerMetaData(0, "Account Created", 0, "Server", 0);
newBankInfo.bank.put(GetUuidByName(server, otherParty).toString(), newBank);
try {
config.WriteToJsonFile("bank/" + newBankInfo.uuid + ".json", newBankInfo);
} catch (FILE_WRITE_EXCEPTION e) {
System.out.println(ChatUtil.ColoredString("Could not flash notes configuration file", CONSOLE_COLOR.RED));
return "";
}
}
else {
System.out.println(ChatUtil.ColoredString("Bank Account Found", CONSOLE_COLOR.GREEN));
}
return GetUuidByName(server, otherParty);
}
}
System.out.println(ChatUtil.ColoredString("For Loop condition bypassed Null Playerlist or Null Server instance", CONSOLE_COLOR.RED));
return "";
}
public void FlashConfig(String uuid) {
try {
config.WriteToJsonFile("bank/" + uuid + ".json", bankInfo);
} catch (FILE_WRITE_EXCEPTION e) {
System.out.println(ChatUtil.ColoredString("Could not flash notes configuration file", CONSOLE_COLOR.RED));
player.sendMessage(Text.of("The banking operating FAILED. Make sure you selected this bank before creating it!"));
}
}
}

View File

@ -0,0 +1,239 @@
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
public class IndividualAccount {
private String globalAccountNumber;
private String bankLetterIdentifier;
private String accountNumber;
private String accountNumberAlias;
private Integer routingNumber; // Will always be the bank it's in
private List<String> accountHolders;
private List<String> accountHolderUuids;
private Integer accountBalance;
private Boolean allowNegativeBalance;
private Boolean accountLocked;
private ACCOUNT_TYPE accountType;
public IndividualAccount() {}
public IndividualAccount(String accountNumber, Integer routingNumber, List<String> holders,
List<String> accountHolderUuids, Boolean allowNegativeBalance, Integer initialBalance,
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);
this.accountNumber = accountNumber;
this.routingNumber = routingNumber;
this.accountHolders = holders;
this.accountHolderUuids = accountHolderUuids;
this.allowNegativeBalance = allowNegativeBalance;
this.accountBalance = initialBalance;
this.accountNumberAlias = alias;
this.accountType = accountType;
this.bankLetterIdentifier = bankLetterIdentifier;
this.globalAccountNumber = bankLetterIdentifier + "-" + routingNumber + "-" + accountNumber;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn AddAccountHolder
///
/// @param[in] newHolder to be added to account
///
/// @param[in] newHolderUuid to be added to account
///
/// @brief Adds another UUID who can access the bank account
/////////////////////////////////////////////////////////////////////////////
public void AddAccountHolder(String newHolder, String newHolderUuid) {
if (!accountHolders.contains(newHolder)) {
accountHolders.add(newHolder);
}
if (!accountHolderUuids.contains(newHolderUuid)) {
accountHolderUuids.add(newHolderUuid);
}
}
/////////////////////////////////////////////////////////////////////////////
/// @fn SetMoney
///
/// @param[in] amount is the new account balance
///
/// @brief Set the balance of the bank account. NOT RECOMMENDED OUTSIDE
/// OF ADMINISTRATIVE USE!!!
///
/// @note This will forcefully ignore account settings like not being
/// able to go negative. This is not recommended to use
/////////////////////////////////////////////////////////////////////////////
public void SetMoney(Integer amount) {
System.out.println("Previous balance on account: " + this.accountBalance + ". New balance: " + amount);
this.accountBalance = amount;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn AliasAccount
///
/// @param[in] newAlias to name the account
///
/// @brief Sets new alias of this account
/////////////////////////////////////////////////////////////////////////////
public void AliasAccount(String newAlias) {
this.accountNumberAlias = newAlias;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn IsLocked
///
/// @brief Returns if account is locked
///
/// @return True if locked, false if not
/////////////////////////////////////////////////////////////////////////////
public Boolean IsLocked() {
return accountLocked;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn LockAccount
///
/// @brief Locks an account
/////////////////////////////////////////////////////////////////////////////
public void LockAccount() {
accountLocked = true;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn Deposit
///
/// @param[in] amount is amount to be added
///
/// @brief Deposits (adds) amount of money to account
///
/// @return True if succeeds, false if fails
/////////////////////////////////////////////////////////////////////////////
public Boolean Deposit(Integer amount) {
Boolean success = false;
if (!accountLocked)
{
accountBalance += amount;
success = true;
}
return success;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn Withdraw
///
/// @param[in] amount is amount to be subtracted
///
/// @brief Withdraws (subtracts) amount from account balance
///
/// @return True if succeeds, false if fails
/////////////////////////////////////////////////////////////////////////////
public Boolean Withdraw(Integer amount) {
Boolean success = false;
if (!accountLocked)
{
// Determine remaining balance
Integer remaining = accountBalance - amount;
success = (remaining < 0 && !allowNegativeBalance);
// Complete the transaction if successful
if (success) {
accountBalance = remaining;
}
}
return success;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn CanWithdraw
///
/// @return True if account can afford withdrawal, false if not
/////////////////////////////////////////////////////////////////////////////
public Boolean CanWithdraw(Integer amount) {
Boolean canWithdraw = false;
if (!accountLocked && (accountBalance - amount >= 0 || allowNegativeBalance)) {
canWithdraw = true;
}
return canWithdraw;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn IsHolder
///
/// @return True if name is on name list
/////////////////////////////////////////////////////////////////////////////
public Boolean IsHolder(String name) {
Boolean ret = false;
if (accountHolders.contains(name)) {
ret = true;
}
return ret;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn AllowsNegative
///
/// @return True if account allows negative balances, false if not
/////////////////////////////////////////////////////////////////////////////
public Boolean AllowsNegative() {
return this.allowNegativeBalance;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn GetAccountHolders
///
/// @return List of everyone who has access to this account
/////////////////////////////////////////////////////////////////////////////
public List<String> GetAccountHolders() {
return accountHolders;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn GetAccountBalance
///
/// @return Account balance
/////////////////////////////////////////////////////////////////////////////
public Integer GetAccountBalance() {
return accountBalance;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn GetAccountNumber
///
/// @return String representation of account number (SHORT account number)
/////////////////////////////////////////////////////////////////////////////
public String GetAccountNumber() {
return accountNumber;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn GetRoutingNumber
///
/// @return Routing number of account
/////////////////////////////////////////////////////////////////////////////
public Integer GetRoutingNumber() {
return routingNumber;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn GetGlobalAccountNumber
///
/// @return Gets global (ENTIRE) account number
/////////////////////////////////////////////////////////////////////////////
public String GetGlobalAccountNumber() {
return globalAccountNumber;
}
}

View File

@ -0,0 +1,565 @@
package jesse.keeblarcraft.BankMgr;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import static java.util.Map.entry;
import java.io.File;
import jesse.keeblarcraft.ConfigMgr.ConfigManager;
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<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 = 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;
private static String CONFIG_LOCATION = "config/keeblarcraft/bank/";
// 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 = 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 = 0;
// Key = ACCOUNT NUMBER
// Value = ACCOUNT
private class Accounts {
// Key = account identifier
// Val = account object
private HashMap<String, IndividualAccount> accountsList = new HashMap<String, IndividualAccount>();
// Key = user uuid
// Val = List of account identifiers
private HashMap<String, List<String>> accountsListFromName = new HashMap<String, List<String>>(); // This is a list that just points to a list of account numbers by person. USEFUL
}
Accounts accounts;
private List<String> lockedUsers; // A list of users who are locked out of the bank and are incapable of performing more actions within it
/////////////////////////////////////////////////////////////////////////////
/// @fn IndividualBank
///
/// @param[in] routingNumber is the routing number this bank is constructed
/// with
///
/// @param[in] nameOfBank Will be the display name of this bank to players
///
/// @brief Constructor for this bank
/////////////////////////////////////////////////////////////////////////////
public IndividualBank(String routingNumber, String nameOfBank) {
accounts = new Accounts();
lockedUsers = new ArrayList<String>();
registeredBankName = nameOfBank.toUpperCase();
bankFourLetterIdentifier = nameOfBank.substring(0, 4).toLowerCase();
this.routingNumber = Integer.parseInt(routingNumber);
System.out.println("CREATING BANK ACCOUNT WITH ROUTING NUMBER " + routingNumber + " AND NAME " + nameOfBank);
boolean existingFile = false;
try {
// Read in the global accounts list
String accountsListDir = CONFIG_LOCATION + routingNumber.toString() + "/accounts/";
System.out.println("accountsListDir + bankName is " + accountsListDir + nameOfBank);
accounts = config.GetJsonObjectFromFile(accountsListDir + nameOfBank, Accounts.class);
existingFile = true;
// 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 (accounts != null && allFiles != null) {
for (File file : allFiles ) {
// First grab file identifier as KEY
String accountIdentifier = file.getName();
String accountFromFile = accountsListDir + "/" + accountIdentifier;
System.out.println("accountIdentifier found in file is " + accountIdentifier);
System.out.println("account identifier with dir path is " + accountFromFile);
accounts.accountsList.put(accountIdentifier, config.GetJsonObjectFromFile(accountFromFile, IndividualAccount.class));
}
}
} catch (Exception e) {
System.out.println("The try-catch in IndividualBank.java failed to complete. Printing stack trace");
// e.printStackTrace();
// Falling into this catch just means the file needs to be made
}
if (!existingFile)
{
try {
// We assume the bank dir is created by server. Create this banks dir
// config.CreateDirectory("bank/" + routingNumber);
// Create this banks initial accounts dir
config.CreateDirectory(CONFIG_LOCATION + routingNumber + "/accounts");
// Flash initial account configuration file for this bank
FlashConfig("accounts");
} catch (Exception e) {
Keeblarcraft.LOGGER.error("Could not write to file in IndividualBank");
}
}
// 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();
// Match each user to the secondary map & add to list-value if not existing
for (Integer holderIndex = 0; holderIndex < accountHolders.size(); holderIndex++) {
if (accounts.accountsListFromName.containsKey(accountHolders.get(holderIndex))) {
// Case 1: User exists, update map entry
accounts.accountsListFromName.get(accountHolders.get(holderIndex)).add(account.getKey()); // Add a new account id to this person in the new flat map
} else {
// Case 2: User does not already exist; add a new map entry
accounts.accountsListFromName.put(accountHolders.get(holderIndex), List.of(account.getKey())); // Store name as key, and new List with the value of ACCOUNT #
}
}
}
numberOfAccounts = accounts.accountsList.size();
} else {
accounts = new Accounts();
numberOfAccounts = 0;
}
}
/////////////////////////////////////////////////////////////////////////////
/// @fn GetBankName
///
/// @return Returns this banks name
/////////////////////////////////////////////////////////////////////////////
public String GetBankName() {
return registeredBankName;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn GetAccountsOfUser
///
/// @param[in] uuid is the players UUID to check
///
/// @brief Gets all the accounts a user has at this bank by UUID
///
/// @return List of all bank accounts. List will be EMPTY if no accounts
/////////////////////////////////////////////////////////////////////////////
public List<IndividualAccount> GetAccountsOfUser(String uuid) {
List<IndividualAccount> accountsFromUser = new ArrayList<IndividualAccount>();
List<String> listOfAccounts = accounts.accountsListFromName.get(uuid);
if (listOfAccounts != null && listOfAccounts.size() > 0) {
for (int i = 0; i < listOfAccounts.size(); i++) {
accountsFromUser.add(accounts.accountsList.get(listOfAccounts.get(i)));
}
}
return accountsFromUser;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn GetBankBalance
///
/// @return The banks balance
/////////////////////////////////////////////////////////////////////////////
public Integer GetBankBalance() {
return bankMoney;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn AddBankBalance
///
/// @param[in] amount Amount to add to the banks balance
///
/// @brief Adds to the banks balance
/////////////////////////////////////////////////////////////////////////////
public void AddBankBalance(Integer amount) {
bankMoney += amount;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn SubtractBankBalance
///
/// @param[in] amount Amount to subtract from banks balance
///
/// @brief Subtracts from the banks balance
/////////////////////////////////////////////////////////////////////////////
public void SubtractBankBalance(Integer amount) {
bankMoney -= amount;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn SetBankBalance
///
/// @param[in] amount Amount to give the bank
///
/// @brief Set the banks balance
/////////////////////////////////////////////////////////////////////////////
public void SetBankBalance(Integer amount) {
bankMoney = amount;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn IsBankInsured
///
/// @return True if bank is insured, false if not
/////////////////////////////////////////////////////////////////////////////
public Boolean IsBankInsured() {
return kbicInsured;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn InsuranceAmount
///
/// @brief Get the insurance amount at this bank
///
/// @return Insurance amount
/////////////////////////////////////////////////////////////////////////////
public Integer InsuranceAmount() {
Integer insuredAmnt = 0;
if (kbicInsured) {
insuredAmnt = kbicInsuredAmount;
} else {
insuredAmnt = 0;
}
return insuredAmnt;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn UpdateBankAccounts
///
/// @brief Flashes bank account information to disk; updates volatile
/// memory of banking information for this bank
/////////////////////////////////////////////////////////////////////////////
public void UpdateBankAccounts(String newHolderName, String newHolderUuid, String accountIdentifier, IndividualAccount newAccountOnly) {
// Update the fast-access map first
System.out.println("UpdateBankAccounts called with information " + newHolderName + " " + newHolderUuid + " " + accountIdentifier);
if (accounts.accountsListFromName.containsKey(newHolderUuid)) {
// Check if user is already in map
accounts.accountsListFromName.get(newHolderUuid).add(accountIdentifier);
} else {
// Add new entry to map
List<String> userAccountList = new ArrayList<String>(); // Lists are immutable; must make ArrayList
userAccountList.add(accountIdentifier);
accounts.accountsListFromName.put(newHolderUuid, userAccountList);
}
// Update regular account list
if (accounts.accountsList.containsKey(accountIdentifier)) {
// This path assumes we are adding a holder as opposed to adding an account (else, how else would this work?)
System.out.println("Account found in accounts list, adding this person as a holder instead");
accounts.accountsList.get(accountIdentifier).AddAccountHolder(newHolderName, newHolderUuid);
} else {
// Non-existent account means a new one!
System.out.println("Brand new account creation, adding!");
accounts.accountsList.put(accountIdentifier, newAccountOnly);
numberOfAccounts++;
}
System.out.println("Flashing configuration file");
FlashConfig("bank/" + routingNumber + "/accounts");
}
/////////////////////////////////////////////////////////////////////////////
/// @fn GetRoutingNumber
///
/// @return Routing number
/////////////////////////////////////////////////////////////////////////////
public Integer GetRoutingNumber() {
return this.routingNumber;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn AddMoneyToAccount
///
/// @param[in] accountId is the account to add money to at this bank
///
/// @param[in] amount is the amount of money to add to this account
///
/// @brief Adds money to an account at this bank if it exists
/////////////////////////////////////////////////////////////////////////////
public void AddMoneyToAccount(String accountId, Integer amount) {
IndividualAccount account = accounts.accountsList.get(accountId);
System.out.println("Received account # " + accountId + " and money amnt " + amount);
if (account != null) {
account.Deposit(amount);
FlashConfig("bank/" + routingNumber + "/accounts");
}
}
/////////////////////////////////////////////////////////////////////////////
/// @fn SubtractMoneyFromAccount
///
/// @param[in] accountId is the account to subtract money to at this bank
///
/// @param[in] amount is the amount of money to subtract to this account
///
/// @brief Subtracts money from an account at this bank if it exists
/////////////////////////////////////////////////////////////////////////////
public void SubtractMoneyFromAccount(String accountId, Integer amount) {
IndividualAccount account = accounts.accountsList.get(accountId);
for (Entry<String, IndividualAccount> debug : accounts.accountsList.entrySet()) {
System.out.println("ACCOUNT ID: " + debug.getKey());
System.out.println("ACCOUNT NUM: " + debug.getValue().GetAccountNumber());
}
if (account != null) {
account.Withdraw(amount);
FlashConfig("bank/" + routingNumber + "/accounts");
}
}
/////////////////////////////////////////////////////////////////////////////
/// @fn SetMoneyOnAccount
///
/// @param[in] accountId is the account number
///
/// @param[in] amount is the new balance to give this account
///
/// @brief Sets a balance on an account if it exists
/////////////////////////////////////////////////////////////////////////////
public void SetMoneyOnAccount(String accountId, Integer amount) {
IndividualAccount account = accounts.accountsList.get(accountId);
System.out.println("Is account null? " + (account == null ? "YES" : "NO"));
System.out.println("Received account # " + accountId + " and money amnt " + amount);
for (Entry<String, IndividualAccount> debug : accounts.accountsList.entrySet()) {
System.out.println("ACCOUNT ID: " + debug.getKey());
System.out.println("ACCOUNT NUM: " + debug.getValue().GetAccountNumber());
}
if (account != null) {
account.SetMoney(amount);
FlashConfig("bank/" + routingNumber + "/accounts");
}
}
/////////////////////////////////////////////////////////////////////////////
/// @fn CreateAccount
///
/// @param[in] holderUuid is the new holders UUID of this account
///
/// @param[in] holderName is the display name of the holder
///
/// @param[in] accountTypeStr is the account type as a string (will be number)
///
/// @brief Create a new account at this bank
///
/// @return True if account can be created, false if it fails
/////////////////////////////////////////////////////////////////////////////
public Boolean CreateAccount(String holderUuid, String holderName, ACCOUNT_TYPE accountType) {
Boolean success = false;
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(accountType), holderName);
System.out.println("Account generator came back with bank account id { " + accountId + " }");
System.out.println("4 letter bank: " + AccountNumberGenerator.GetFinancialSymbolFromId(accountId));
System.out.println("Routing: " + AccountNumberGenerator.GetRoutingNumberFromId(accountId));
System.out.println("Account type: " + AccountNumberGenerator.GetAccountTypeFromId(accountId));
System.out.println("RNG Account number: " + AccountNumberGenerator.GetAccountNumberFromId(accountId));
// 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(accountType), holderName);
System.out.println("Account generator came back with bank account id { " + accountId + " }");
maxAttempts--;
}
// Final check to add the account
String actualAccountNumber = AccountNumberGenerator.GetAccountNumberFromId(accountId);
System.out.println("Bank account identifier is { " + actualAccountNumber + " }. Is this already an existing account? " + accounts.accountsList.containsKey(actualAccountNumber));
if (!accounts.accountsList.containsKey(actualAccountNumber)) {
IndividualAccount newAccount = new IndividualAccount(actualAccountNumber, this.routingNumber, List.of(holderName),
List.of(holderUuid), false, 0,
"", accountType, bankFourLetterIdentifier);
System.out.println("Updating accounts list for this bank");
UpdateBankAccounts(holderName, holderUuid, actualAccountNumber, newAccount);
success = true;
}
}
}
return success;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn AliasAccount
///
/// @param[in] accountId to alias
///
/// @param[in] newAlias is name to give this account
///
/// @brief Alias an account
/////////////////////////////////////////////////////////////////////////////
public void AliasAccount(String accountId, String newAlias) {
String accountNumber = AccountNumberGenerator.GetAccountNumberFromId(accountId);
if (accounts.accountsList.containsKey(accountNumber)) {
accounts.accountsList.get(accountNumber).AliasAccount(newAlias);
}
}
/////////////////////////////////////////////////////////////////////////////
/// @fn LockAccountHolder
///
/// @param[in] holderName is player to lock account
///
/// @brief Locks all accounts under a name for this user
///
/// @return True if lock succeeds, false if not
/////////////////////////////////////////////////////////////////////////////
public Boolean LockAccountHolder(String holderName) {
Boolean success = false;
Integer accountIter = 0;
for (Entry<String, List<String>> holderAccounts : accounts.accountsListFromName.entrySet()) {
accounts.accountsList.get(holderAccounts.getValue().get(accountIter++)).LockAccount();
}
return success;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn CloseAccount
///
/// @param[in] accountId is id of account to be closed
///
/// @brief Closes an account
///
/// @note Balance of account must be 0 to close successfully
///
/// @return True if can close, false if not
/////////////////////////////////////////////////////////////////////////////
public Boolean CloseAccount(String accountId) {
Boolean success = false;
String accountNumber = AccountNumberGenerator.GetAccountNumberFromId(accountId);
if (accounts.accountsList.get(accountNumber).GetAccountBalance() == 0) {
accounts.accountsList.remove(accountNumber);
success = true;
}
return success;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn HasAccount
///
/// @param[in] accountIdentifier account number to check to see if it exists
/// at this bank
///
/// @brief See if an account identifier belongs to this bank
///
/// @return True if this bank has this account identifier, false if not
/////////////////////////////////////////////////////////////////////////////
public Boolean HasAccount(String accountIdentifier) {
Boolean containsAccount = false;
if (accounts.accountsList.containsKey(accountIdentifier)) {
containsAccount = true;
}
return containsAccount;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn IsValidWithdrawal
///
/// @param[in] withdrawalAmount The amount to be withdrawn
///
/// @param[in] accountIdentifier account to withdraw from
///
/// @brief Verifies if a withdrawal will succeed on an account prior to
/// the actual withdrawal itself
///
/// @return True if this account can afford this withdrawal. False if not
/////////////////////////////////////////////////////////////////////////////
public Boolean IsValidWithdrawal(Integer withdrawalAmount, String accountIdentifier) {
Boolean isValid = false;
if (accounts.accountsList.containsKey(accountIdentifier)) {
IndividualAccount account = accounts.accountsList.get(accountIdentifier);
if (account.CanWithdraw(withdrawalAmount)) {
isValid = true;
}
}
return isValid;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn IsAccountHolder
///
/// @param[in] accountIdentifier Account to check
///
/// @param[in] uuid Is players UUID to see if they are on this account
///
/// @brief Check if a player is on this account
///
/// @return True if player is on this account. False if not or account
/// does not exist
/////////////////////////////////////////////////////////////////////////////
public Boolean IsAccountHolder(String accountIdentifier, String uuid) {
Boolean isHolder = false;
// Verify account exists first
if (accounts.accountsList.containsKey(accountIdentifier)) {
isHolder = accounts.accountsList.get(accountIdentifier).IsHolder(uuid);
}
return isHolder;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn FlashConfig
///
/// @param[in] dirName is config to flash to. Banking is not trivial and will
/// require separate files to be updated at different locations!
///
/// @brief Flashes the config to the disk
///
/// @note dirName should be the relative full path to dir
/// @note Function will be removed in near future for SQL but is
/// expensive to run as it flashes everything even if un-updated
/////////////////////////////////////////////////////////////////////////////
public void FlashConfig(String dirName) {
for (Entry<String, IndividualAccount> singleAccount : accounts.accountsList.entrySet()) {
// Iterate over each one & verify if a file exists inside the dir. if it does;
// nuke it and
// replace it with the new contents in memory
String accountNum = singleAccount.getKey().toString();
// delete file
File file = new File(dirName + "/" + accountNum + ".json");
if (file.exists()) {
file.delete();
}
// Re-flash file
config.WriteToJsonFile(dirName + "/" + accountNum + ".json", singleAccount.getValue());
}
}
}

View File

@ -0,0 +1,17 @@
package jesse.keeblarcraft.BankMgr;
// All details that involve a transaction attempt
public class TransactionMetadata {
enum TRANSACTION_TYPE {
DEBIT,
CREDIT,
WITHDRAWAL,
DEPOSIT
}
public String fromParty; // 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,91 @@
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 SetHeader(ChatMsg msg) {
this.header = msg.regularText;
}
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 AddMsg(ChatMsg newMsg) {
AddMsg(newMsg.regularText);
}
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);
// Send the header
target.sendMessage(header);
target.sendMessage(Text.of("")); // Spacer
// Send the body
int msgIndex = 0;
for (int page = 0; page < pageCount; page++) {
for (int i = 0; i < pageLimit; i++) {
target.sendMessage(msgList.get(msgIndex++));
}
}
// Send the footer
// target.sendMessage(footer);
}
}

View File

@ -0,0 +1,216 @@
/*
*
* 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 ChatMsg {
// May be null; store last message of each type so class can be referenced as object
MutableText mutableText;
Text regularText;
/////////////////////////////////////////////////////////////////////////////
/// @fn MakeCopyableTxt
///
/// @param[in] terminalTxt is the text to be seen on screen
///
/// @param[in] hoverTxt is the desired text to be seen in a new hover event
///
/// @param[in] copyInt is an integer argument that can be copied when the
/// player clicks on the chat message
///
/// @brief Creates a copyable text block for the player
///
/// @return MutableText of text intended to be used to send to player
/////////////////////////////////////////////////////////////////////////////
public MutableText MakeCopyableTxt(String terminalTxt, String hoverTxt, Integer copyInt) {
return MakeCopyableTxt(terminalTxt, hoverTxt, Integer.toString(copyInt));
}
/////////////////////////////////////////////////////////////////////////////
/// @fn MakeCopyableTxt
///
/// @param[in] terminalTxt is the text to be seen on screen
///
/// @param[in] hoverTxt is the desired text to be seen in a new hover event
///
/// @param[in] expandedList takes in a list of strings that can be copied
/// when the player clicks on a chat message
///
/// @brief Creates a copyable text block for the player
///
/// @return MutableText of text intended to be used to send to player
/////////////////////////////////////////////////////////////////////////////
public MutableText MakeCopyableTxt(String terminalTxt, String hoverTxt, List<String> expandedList) {
String expanded = "[";
int index = 0;
for (String str : expandedList) {
expanded += str;
// Add delimiter if next index is not at size
if (++index < expandedList.size()) {
expanded += ",";
}
}
expanded += "]";
return MakeCopyableTxt(terminalTxt, hoverTxt, expanded);
}
/////////////////////////////////////////////////////////////////////////////
/// @fn MakeCopyableTxt
///
/// @param[in] terminalTxt is the text to be seen on screen
///
/// @param[in] hoverTxt is the desired text to be seen in a new hover event
///
/// @param[in] copyStr is a regular string that can be copied when the player
/// clicks on a chat message
///
/// @brief Creates a copyable text block for the player
///
/// @return MutableText of text intended to be used to send to player
/////////////////////////////////////////////////////////////////////////////
public MutableText MakeCopyableTxt(String terminalTxt, String hoverTxt, String copyStr) {
Text copyableText = Text.of(terminalTxt);
MutableText testTxt = (MutableText) copyableText;
System.out.println("Making hoverable stuff");
testTxt.setStyle(Style.EMPTY.withClickEvent(new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, copyStr))
.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.of(hoverTxt))));
System.out.println("Done making hoverable stuff");
System.out.println("Value of copyAbleText: " + copyableText.getString());
System.out.println("Value of testTxt: " + testTxt.getString());
mutableText = testTxt;
return testTxt;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn ColorMsg
///
/// @param[in] msg is an integer message that is desired to be colored
///
/// @param[in] color is the color option
///
/// @brief Creates a formatted string that will be colored at the
/// specification of the developer
///
/// @return Formatted string of colored text
/////////////////////////////////////////////////////////////////////////////
public String ColorMsg(Integer msg, COLOR_CODE color) {
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) {
regularText = Text.of(ChatFormatting.GetColor(color) + msg.getString() + ChatFormatting.COLOR_END);
return regularText;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn ColorMsg
///
/// @param[in] msg is a list of strings that is desired to all be colored
/// the same
///
/// @param[in] color is the color option
///
/// @brief Creates a formatted list of strings that will be colored
/// at the specification of the developer and will be returned as
/// a list
///
/// @return Formatted list of strings
/////////////////////////////////////////////////////////////////////////////
public List<String> ColorMsg(List<String> msg, COLOR_CODE color) {
List<String> retList = new ArrayList<String>();
for (String str : msg) {
retList.add(ChatFormatting.GetColor(color) + str + ChatFormatting.COLOR_END);
}
return retList;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn ColorMsg
///
/// @param[in] msg to be formatted
///
/// @param[in] color is the color option
///
/// @brief Creates a formatted string that will be colored at the
/// specification of the developer
///
/// @return Formatted string of colored text
/////////////////////////////////////////////////////////////////////////////
public String ColorMsg(String msg, COLOR_CODE color) {
return ChatFormatting.GetColor(color) + msg + ChatFormatting.COLOR_END;
}
// Parses a help command and color codes it. assume everything up to first '.' is the
// help cmd usage and color it with primaryColor. secondaryColor applied to rest
/////////////////////////////////////////////////////////////////////////////
/// @fn FormatMsg
///
/// @param[in] helpCmd is outsourced as an intentional help message. The
/// string expects the initial format to stop with a '.'
/// delimiter.
///
/// @param[in] primaryColor is the color of the string up to the delimiter
///
/// @param[in] secondaryColor is the color after the delimiter
///
/// @brief Creates a formatted string
///
/// @return Formatted string of colored text
/////////////////////////////////////////////////////////////////////////////
public String FormatMsg(String helpCmd, COLOR_CODE primaryColor, COLOR_CODE secondaryColor) {
String coloredStr = ChatFormatting.GetColor(primaryColor);
List<String> splitStr = List.of(helpCmd.split("\\."));
Boolean isFirst = true;
for (String str : splitStr) {
if (isFirst) {
coloredStr += str;
isFirst = false;
coloredStr += ChatFormatting.GetColor(secondaryColor);
} else {
coloredStr += str;
}
}
return coloredStr + ChatFormatting.COLOR_END;
}
}

View File

@ -44,18 +44,18 @@ public class AttributeCommands {
(
EntityArgumentType.getPlayer(context, "targetPlayer"),
StringArgumentType.getString(context, "attributeName"),
context)
context
)
.build();
).build();
var attributeNameDelete = CommandManager.argument("attributeName", StringArgumentType.greedyString())
.executes(context -> DeleteAttribute
(
EntityArgumentType.getPlayer(context, "targetPlayer"),
StringArgumentType.getString(context, "attributeName"),
context)
context
)
.build();
).build();
// Build out the argument tree here
dispatcher.getRoot().addChild(attributeNode);
@ -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,155 +1,758 @@
package jesse.keeblarcraft.Commands;
import com.mojang.brigadier.arguments.IntegerArgumentType;
import com.mojang.brigadier.arguments.LongArgumentType;
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.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 net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
public class BankCommands {
private static List<String> FILLER_WORDS = new ArrayList<String>(List.of("of", "from", "as", "with", "name", "dubbed", "coined", "note"));
private static String HELPCMD_HELP = "help";
private static String HELPCMD_CREATE = "create";
private static String HELPCMD_SELECT = "select";
private static String HELPCMD_CLOSE = "close";
private static String HELPCMD_REPORT = "report";
private static String HELPCMD_BALANCE = "balance";
private static String HELPCMD_EXAMPLES = "examples";
private static String HELPCMD_MOVE = "move";
private static String HELPCMD_SYNTAX = "syntax";
private static String HELPCMD_ALIAS = "alias";
private static String HELPCMD_WIRE = "wire";
private static String HELPCMD_ACCOUNTS = "accounts";
private static String HELPCMD_ADMIN_BALANCE_CHANGE = "admin-set-balance";
private static String HELPCMD_ADMIN_BALANCE_GET = "admin-get-balance";
private static String HELPCMD_ADMIN_CREATE_BANK = "admin-create-bank";
private static String HELPCMD_ADMIN_CLOSE_BANK = "admin-close-bank";
private static String HELPCMD_ADMIN_FORCE_WIRE = "admin-force-wire";
private static String HELPCMD_ADMIN_LOCK_BANK = "admin-lock-bank";
private static String HELPCMD_SET_SERVER_ALLOWANCE = "admin-set-server-allowance";
private static String HELPCMD_GET_SERVER_ALLOWANCE = "admin-get-server-allowance";
private static String HELPCMD_ADMIN_COMMANDS_LIST = "admin-commands-list";
private static String HELPCMD_ADMIN_ACCOUNTS = "admin-accounts";
private static String HELPCMD_ADMIN_ACCOUNTS_LIST = "admin-accounts-list";
private static String HELPCMD_ADMIN_ACCOUNTS_MOVE = "admin-accounts-move";
private static String HELPCMD_ADMIN_ACCOUNTS_FORCE_CLOSE = "admin-accounts-force-close";
private static String HELPCMD_ADMIN_ACCOUNTS_ADD = "admin-accounts-add";
private static String HELPCMD_ADMIN_ACCOUNTS_TRANSACTIONS = "admin-accounts-transactions";
private static String HELPCMD_ADMIN_ACCOUNTS_LOCK = "admin-accounts-lock";
ChatMsg msgFormatter = new ChatMsg();
private static Map<String, String> HELP_COMMANDS = Map.ofEntries(
entry
(
HELPCMD_HELP, "Usage: /bank help. This is the general help message for the bank system. For detailed help messages, please run /bank help <command OR subcommand>. List of possible " +
"commands are: CREATE, SELECT, CLOSE, REPORT, BALANCE, EXAMPLES, WIRE, MOVE, SYNTAX, ALIAS"
),
entry
(
HELPCMD_CREATE, "Usage: /bank create {checking|savings}. This will create a bank account with the default selected bank (/bank select {BANK_ID} to choose other)."
),
entry
(
HELPCMD_SELECT, "Usage: /bank select {BANK_ID}. Do `/bank list` for a list of banks on the server."
),
entry
(
HELPCMD_CLOSE, "Usage: /bank close {ACCOUNT_ID}. Do `/bank accounts list` to see all the accounts you have! Note: CANNOT close accounts that aren't 0 balance."
),
entry
(
HELPCMD_REPORT, "Usage: /bank report [ACCOUNT_ID|none]. Optional args mean you can get a specific report list for one account; but if none specified we default to all accounts."
),
entry
(
HELPCMD_BALANCE, "Usage: /bank balance [ACCOUNT_ID]. Optional args get balances for other accounts that aren't the default selected account. You may run `/bank accounts list` to " +
"see all possible options to get a balance for."
),
entry
(
HELPCMD_EXAMPLES, "Usage: /bank examples. This will print a much larger command with more thorough examples (and even shortcuts!) of all the commands from the bank system."
),
entry
(
HELPCMD_MOVE, "Usage: /bank move {ACCOUNT_ID} to {BANK_ID}. The intended use of this command is to move accounts across banks, but you could also plug in another ACCOUNT_ID in " +
" the `BANK_ID` part to perform an internal wire instead. NOTE: Moving might not succeed based on bank rules!"
),
entry
(
HELPCMD_SYNTAX, "Usage: /bank syntax. This banking system was written to be human readable in command-form and often operates like a database. You can put certain filler-words inside your commands that are " +
"parsed out at runtime if it helps with reading. Example command: \"/bank select 942-3449-42\" will work just fine to select a bank account as a primary account. HOWEVER, you can also " +
"type \"/bank select for-bills as default\" so long as you aliased the account identifier as 'for-bills'. Much nicer to read and work with. [Related: /bank help aliases]"
),
entry
(
HELPCMD_ALIAS, "Usage: /bank alias {ACCOUNT_ID} {UNIQUE_NAME}. Alias provides a handy way to refer to bank accounts by their unique names instead of long-form account ids. NOTE: Aliases " +
"are ONLY unique within the context of an individual bank and not across all banks, but generally you can replace `ACCOUNT_ID` as seen in other commands with the alias if it exists."
),
entry
(
HELPCMD_WIRE, "Usage: /bank wire {AMOUNT} to {ACCOUNT_ID|NAME}. It is recommended to wire a specific account ID over a name since it works if the other player is offline. If name is specified, " +
" the wire will go through to that players default account. Use with caution!"
),
entry
(
HELPCMD_ACCOUNTS, "Usage: /bank accounts {BANK_ID}. Prints out all of your banking information at a bank assuming you have any."
),
entry
(
HELPCMD_ADMIN_BALANCE_CHANGE, "Usage: /bank admin {set-bal|add-money|subtract-money} {ACCOUNT_ID|BANK_ID} {AMOUNT}. This command covers set/add/subtract money. Usage varies on context, but general help command is going to be " +
"/bank admin {set-bal|add-money|sub-money} {USER_ACCOUNT_ID|BANK_ROUTING_NUM} {amount}. Please note that the \"|\" in this context means OR - you do not put both! " +
"So you can set a banks balance or accounts balance with this command."
),
entry
(
HELPCMD_ADMIN_BALANCE_GET, "Usage: /bank admin get {USER_ACCOUNT_ID|BANK_ID}. Please note that the \"|\" in this means OR. Do NOT put both!"
),
entry
(
HELPCMD_ADMIN_CREATE_BANK, "Usage: /bank admin create {new bank name}. Bank name must be longer than 4 letters!"
),
entry
(
HELPCMD_ADMIN_CLOSE_BANK, "Usage: /bank admin close {BANK_ID}. Please be aware if the bank has an active balance or user accounts you will be asked to " +
"confirm if this is really what you want to do. Money is not magic, so if you specify to close the bank the bank balance is transferred back " +
"to the servers primary bank account & all user accounts money are transferred to the server bank. Accounts will automatically be opened to preserve " +
"the money for users to claim because banks are not ordinarily supposed to just close. Only run this command if you absolutely have to!"
),
entry
(
HELPCMD_ADMIN_FORCE_WIRE, "Usage: /bank admin wire {AMOUNT} from {ACCOUNT_ID} to {ACCOUNT_ID}. Please be aware this is a heavy handed command and may " +
"unintentionally override a bank accounts default setting. A bank account with a rule that can't go negative WILL go negative if this command is " +
"run because it's an administrative command! Use with caution"
),
entry
(
HELPCMD_ADMIN_LOCK_BANK, "Usage: /bank admin lock-bank {BANK_ID}. Completely freezes all activity in and out of a bank."
),
entry
(
HELPCMD_SET_SERVER_ALLOWANCE, "Usage: /bank admin set-server-allowance {amount} {interval}. Example usage: /bank admin set-server-allowance 1,000,000 " +
"30d. Supported interval characters: d/m/y (day/month/year). These times are in MINECRAFT in-game time, not real life time! Months are assumed to be equally " +
"30 days and years are 365 days. If you need precision, just specify your amount in days!"
),
entry
(
HELPCMD_GET_SERVER_ALLOWANCE, "Usage: /bank admin get-server-allowance. Returns the amount of money in the allowance for server and the interval it is in. "
),
entry
(
HELPCMD_ADMIN_COMMANDS_LIST, "Usage: /bank admin {sub-command} [optionals]. POSSIBLE ADMIN COMMANDS LIST: [set-bal, add-money, get-bal, sub-money, accounts, create-bank, close-bank, lock-bank, unlock, " +
"force-wire, get-server-allowance, set-server-allowance]. Commands FROM [accounts] cmd => [list, move, force-close, add, transactions, lock]"
),
entry
(
HELPCMD_ADMIN_ACCOUNTS, "Usage: /bank admin accounts {sub-command} [optionals]. This command has sub-commands that are expected. Possible => [list, move, force-close, add, transactions, lock]. General syntax is " +
"/bank admin accounts [sub-command]"
),
entry
(
HELPCMD_ADMIN_ACCOUNTS_ADD, "Usage: /bank admin accounts add {ONLINE_PLAYER} [BANK_ID]. Adds a regular checking account to a bank for a player who is online. " +
"If BANK_ID not specified; defaults to the servers default bank"
),
entry
(
HELPCMD_ADMIN_ACCOUNTS_FORCE_CLOSE, "Usage: /bank admin accounts force-close {ACCOUNT_ID}. Command not supported in this version."
),
entry
(
HELPCMD_ADMIN_ACCOUNTS_LIST, "Usage: /bank admin accounts list {USERNAME}. Command not supported in this version."
),
entry
(
HELPCMD_ADMIN_ACCOUNTS_LOCK, "Usage: /bank admin accounts lock {ACCOUNT_ID}. Command not supported in this version."
),
entry
(
HELPCMD_ADMIN_ACCOUNTS_MOVE, "Usage: /bank admin accounts move {ACCOUNT_ID} to {BANK_ID}. Command not supported in this version."
),
entry
(
HELPCMD_ADMIN_ACCOUNTS_TRANSACTIONS, "Usage: /bank admin accounts transactions {ACCOUNT_ID}. Command not supported in this version."
)
);
ConfigManager config = new ConfigManager();
/////////////////////////////////////////////////////////////////////////////
/// @fn RegisterCommands
///
/// @brief Registers all bank commands on the server
/////////////////////////////////////////////////////////////////////////////
public void RegisterCommands() {
// Command: "/getbalance"
// Bank help
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
dispatcher.register(CommandManager.literal("getbalance")
.executes(context -> GetBalance(context)));
});
var bankRoot = CommandManager.literal("bank").build();
var help = CommandManager.literal("help").build();
var helpTarget = CommandManager.argument("target", StringArgumentType.greedyString())
.executes(context -> HelpCommand(context.getSource().getPlayer(), StringArgumentType.getString(context, "target")))
.build();
// Command: "/setbalance || rootSetBalance"
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
final var rootSetBalance = dispatcher.register(CommandManager.literal("setbalance")
.then(CommandManager.argument("newBalance", IntegerArgumentType.integer())
.then(CommandManager.argument("reason", StringArgumentType.string())
.then(CommandManager.argument("otherParty", StringArgumentType.string())
.executes(context -> SetBalance(
IntegerArgumentType.getInteger(context, "newBalance"),
StringArgumentType.getString(context, "reason"),
StringArgumentType.getString(context, "otherParty"),
context))))));
var info = CommandManager.literal("info")
.executes(context -> ListBankInfo(context.getSource().getPlayer()))
.build();
dispatcher.register(CommandManager.literal("setbalance").redirect(rootSetBalance));
});
bankRoot.addChild(info);
// Command: "/AddMoney"
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
dispatcher.register(CommandManager.literal("AddMoney")
.then(CommandManager.argument("reason", StringArgumentType.string())
.then(CommandManager.argument("payment", LongArgumentType.longArg())
.then(CommandManager.argument("otherParty", StringArgumentType.string())
.executes(context -> AddMoney(
StringArgumentType.getString(context, "reason"),
LongArgumentType.getLong(context, "payment"),
StringArgumentType.getString(context, "otherParty"),
context))))));
});
var create = CommandManager.literal("create").build();
var createAccount = CommandManager.literal("account").build();
// Command: "/subtractbalance || /SubtractBalance"
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
final var SubtractBalance = dispatcher.register(CommandManager.literal("subtractbalance")
.then(CommandManager.argument("reason", StringArgumentType.string())
.then(CommandManager.argument("payment", LongArgumentType.longArg())
.then(CommandManager.argument("otherParty", StringArgumentType.string())
.executes(context -> SubtractBalance(
StringArgumentType.getString(context, "reason"),
LongArgumentType.getLong(context, "payment"),
StringArgumentType.getString(context, "otherParty"),
context))))));
var checking = CommandManager.literal("checking")
.executes(context -> CreateAccount(context.getSource().getPlayer(), ACCOUNT_TYPE.CHECKING))
.build();
dispatcher.register(CommandManager.literal("subtractbalance").redirect(SubtractBalance));
});
var savings = CommandManager.literal("savings")
.executes(context -> CreateAccount(context.getSource().getPlayer(), ACCOUNT_TYPE.SAVINGS))
.build();
// Command: "/wire || /sendmoney"
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
final var sendmoney = dispatcher.register(CommandManager.literal("wire")
.then(CommandManager.argument("reason", StringArgumentType.string())
.then(CommandManager.argument("payment", LongArgumentType.longArg())
.then(CommandManager.argument("otherParty", StringArgumentType.string())
.executes(context -> Wire(
StringArgumentType.getString(context, "reason"),
LongArgumentType.getLong(context, "payment"),
StringArgumentType.getString(context, "otherParty"),
context))))));
bankRoot.addChild(create);
create.addChild(createAccount);
createAccount.addChild(checking);
createAccount.addChild(savings);
dispatcher.register(CommandManager.literal("wire").redirect(sendmoney));
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(help);
help.addChild(helpTarget);
});
}
public Integer GetBalance(CommandContext<ServerCommandSource> context) {
Integer ret = -1;
if (context.getSource().isExecutedByPlayer()) {
ServerPlayerEntity player = context.getSource().getPlayer();
BankManager playerBank = new BankManager(player.getUuidAsString());
player.sendMessage(Text.literal(String.valueOf(playerBank.GetBalance())));
public int SelectBank(ServerPlayerEntity player, String bank) {
System.out.println("Select bank called");
BankManager.GetInstance().ChangeDefaultSelectedBank(player, bank);
return 0;
}
return ret;
}
//SetBalance will be a ServerCommand only Perm level Op
public Integer SetBalance(Integer newBalance, String reason, String otherParty, CommandContext<ServerCommandSource> context) {
Integer ret = -1;
if (context.getSource().hasPermissionLevel(1)) {
ServerPlayerEntity player = context.getSource().getPlayer();
BankManager playerBank = new BankManager(player.getUuidAsString());
playerBank.SetBalance(newBalance, reason, otherParty);
player.sendMessage(Text.literal(String.valueOf(playerBank.GetBalance())));
}
return ret;
}
//AddMoney will be a ServerCommand Only Perm level Op
public Integer AddMoney(String reason, long payment, String otherParty, CommandContext<ServerCommandSource> context) {
Integer ret = -1;
if (context.getSource().hasPermissionLevel(1)) {
ret = 0;
ServerPlayerEntity player = context.getSource().getPlayer();
BankManager playerBank = new BankManager(player.getUuidAsString());
playerBank.AddMoney(reason, payment, otherParty);
player.sendMessage(Text.literal(String.valueOf(playerBank.GetBalance())));
}
return ret;
}
//SubtractBalance will be a ServerCommand Perm leve Op
public Integer SubtractBalance(String reason, long payment, String otherParty, CommandContext<ServerCommandSource> context) {
Integer ret = -1;
if (context.getSource().hasPermissionLevel(1)) {
ret = 0;
ServerPlayerEntity player = context.getSource().getPlayer();
BankManager playerBank = new BankManager(player.getUuidAsString());
playerBank.SubtractBalance(reason, payment, otherParty);
player.sendMessage(Text.literal(String.valueOf(playerBank.GetBalance())));
}
return ret;
}
public Integer Wire(String reason, long payment, String otherParty, CommandContext<ServerCommandSource> context) {
Integer ret = -1;
if (context.getSource().isExecutedByPlayer()) {
ret = 0;
ServerPlayerEntity player = context.getSource().getPlayer();
BankManager playerBank = new BankManager(player.getUuidAsString());
playerBank.Wire(reason, payment, otherParty);
player.sendMessage(Text.literal(String.valueOf(playerBank.GetBalance())));
}
return ret;
/////////////////////////////////////////////////////////////////////////////
/// @fn IsOperator
///
/// @param[in] player is the player to be tested
///
/// @brief Check to see if player is operator (move to util in future)
///
/// @return True if player is operator, false if not
/////////////////////////////////////////////////////////////////////////////
public Boolean IsOperator(ServerPlayerEntity player) {
if (player.hasPermissionLevel(4)) {
return true;
} else {
return false;
}
}
public int AdminSubtractMoney(ServerPlayerEntity player, Integer amount, String account, String reason) {
AdminBalanceChange(player, account, amount, "subtract", reason);
return 0;
}
public int AdminAddMoney(ServerPlayerEntity player, Integer amount, String account, String reason) {
AdminBalanceChange(player, account, amount, "add", reason);
return 0;
}
public int AdminSetMoney(ServerPlayerEntity player, Integer amount, String account, String reason) {
AdminBalanceChange(player, account, amount, "set", reason);
return 0;
}
public String GetServerAllowance() {
return "";
}
/////////////////////////////////////////////////////////////////////////////
/// @fn AdminBalanceChange
///
/// @param[in] player is player who ran command
///
/// @param[in] accountId is account id to change balance of
///
/// @param[in] amount is amount to change account balance
///
/// @param[in] type is type of fund change (parsed on @ref BankManager.java)
///
/// @param[in] optionalReason is the optional reason of balance change
///
/// @brief Admin command to change the balance of an account by some
/// amount
/////////////////////////////////////////////////////////////////////////////
public void AdminBalanceChange(ServerPlayerEntity player, String accountId, Integer amount, String type, String optionalReason) {
BankManager.GetInstance().AdminChangeFunds(player, accountId, amount, type, optionalReason);
}
public void AdminGetBalance(String accountId) {
}
public void AdminWireMoney(String fromAccount, String toAccount, Integer amount, String optionalReason) {
}
public void AdminCreateBank(String bankName, Integer initialBankBalance, Integer kbicInsuredAmount) {
}
public void AdminCloseBank(String bankIdentifier, String optionalReason, Boolean forceClosure) {
}
public void AdminAccounts() {
}
public void LockBank(String bankIdentifier, String optionalReason) {
}
public void LockPlayer(String playerName, String optionalReason) {
}
public void LockBankAccount(String accountId, String optionalReason) {
}
// Possible code paths:
// REQUIRED = {Routing # or Bank name}
// OPTIONAL = []
/////////////////////////////////////////////////////////////////////////////
/// @fn ManageAccounts
///
/// @brief Change the balance of a designated account
/////////////////////////////////////////////////////////////////////////////
public int ListBankInfo(ServerPlayerEntity sourcePlayer) {
String bankName = BankManager.GetInstance().GetPlayerSelectedBank(sourcePlayer.getUuidAsString());
IndividualBank bank = BankManager.GetInstance().GetBankByName(bankName);
if (bank != null) {
System.out.println("Grabbing user account information");
List<IndividualAccount> userAccounts = bank.GetAccountsOfUser(sourcePlayer.getUuidAsString());
sourcePlayer.sendMessage(Text.of("[BANK INFO FOR " + bankName.toUpperCase() + "]"));
System.out.println("userAccounts size: " + userAccounts.size());
for (int i = 0; i < userAccounts.size(); i++) {
String accountNumber = userAccounts.get(i).GetAccountNumber();
String globalAccountNumber = userAccounts.get(i).GetGlobalAccountNumber();
List<String> accountHolders = userAccounts.get(i).GetAccountHolders();
Integer accountBalance = userAccounts.get(i).GetAccountBalance();
String l1 = "ACCOUNT NUMBER: " + msgFormatter.ColorMsg(accountNumber, COLOR_CODE.BLUE);
String l2 = "GLOBAL ACCOUNT NUMBER: " + msgFormatter.ColorMsg(globalAccountNumber, COLOR_CODE.BLUE);
String l3 = "HOLDERS: " + msgFormatter.ColorMsg(accountHolders, COLOR_CODE.GRAY);
String l4 = "BALANCE: " + msgFormatter.ColorMsg(accountBalance, COLOR_CODE.GREEN);
sourcePlayer.sendMessage((Text) msgFormatter.MakeCopyableTxt(l1, "Click to copy", accountNumber));
sourcePlayer.sendMessage((Text) msgFormatter.MakeCopyableTxt(l2, "Click to copy", globalAccountNumber));
sourcePlayer.sendMessage((Text) msgFormatter.MakeCopyableTxt(l3, "Click to copy", accountHolders));
sourcePlayer.sendMessage((Text) msgFormatter.MakeCopyableTxt(l4, "Click to copy", accountBalance));
sourcePlayer.sendMessage(Text.of("\n"));
}
} else {
sourcePlayer.sendMessage(Text.of(msgFormatter.ColorMsg("That bank does not exist", COLOR_CODE.RED)));
}
return 0;
}
// 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:
// REQUIRED (path 1) = {AMOUNT} [FROM:{INTERNAL ACCOUNT #|ALIAS}] TO:{INTERNAL ACCOUNT #|ALIAS} ***Note: can be assumed to be SELECTED default if not specified
// REQUIRED (path 2) = {INTERNAL ACCOUNT #|ALIAS} {EXTERNAL BANK/FACTION ID}
// OPTIONAL = []
/////////////////////////////////////////////////////////////////////////////
/// @fn MoveCommand
///
/// @param[in] player is player who ran command
///
/// @param[in] argList is the argument list to be parsed
///
/// @brief Command to move account. Read above comment for code paths
/////////////////////////////////////////////////////////////////////////////
public int MoveCommand(ServerPlayerEntity sourcePlayer, Integer amount, String fromAccount, String toAccount) {
return 0;
}
// Posible code paths:
// REQUIRED = {ACCOUNT-ID|ALIAS} {ALIAS}
// OPTIONAL = []
/////////////////////////////////////////////////////////////////////////////
/// @fn AliasCommand
///
/// @param[in] player is player who ran command
///
/// @param[in] argList is the argument list to be parsed
///
/// @brief Aliases an account with a nick name
/////////////////////////////////////////////////////////////////////////////
public void AliasCommand(ServerPlayerEntity sourcePlayer, List<String> argList) {
if (argList.size() > 0) {
String newAlias = argList.get(0);
/*
* CALL TO BANKMGR TO SEE IF ALIAS ARG ALREADY EXISTS
*/
} else {
sourcePlayer.sendMessage(Text.of("Unrecognized alias command. Please run \"/bank help ALIAS\" for more information."));
}
}
// Possible code paths:
// REQUIRED = {...} valid argList required
// OPTIONAL = []
// NOTE: This is just a shorthand to get to `/bank create report`
/////////////////////////////////////////////////////////////////////////////
/// @fn ReportCommand
///
/// @param[in] player is player who ran command
///
/// @param[in] argList is the argument list to be parsed
///
/// @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."));
// }
// }
// Possible code paths:
// REQUIRED = {}
// OPTIONAL = [identifier|alias]
public int BalanceCommand(ServerPlayerEntity sourcePlayer, List<String> argList) {
String accountToBalance = "default";
/*
*
* Code here to get default account from player
*
*/
if (argList.size() == 1) {
/*
* Set accountToBalance here
*/
}
/*
* Return to player balance here in new chatutil function not yet made
*/
return 0;
}
// Possible code paths:
// REQUIRED = {ACCOUNT ID|ALIAS}
// OPTIONAL = []
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 SelectDefaultAccount(ServerPlayerEntity sourcePlayer, String account) {
BankManager.GetInstance().ChangeDefaultPlayerAccount(sourcePlayer, account);
return 0;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn WireCommand
///
/// @param[in] player is player who ran command
///
/// @param[in] argList is the argument list to be parsed
///
/// @brief Create wire on bank account
/////////////////////////////////////////////////////////////////////////////
public int WireCommand(ServerPlayerEntity sourcePlayer, Integer amount, String destAccount, String reason) {
BankManager.GetInstance().InitiateBankFundsTransfer(sourcePlayer, destAccount, amount, reason);
return 0;
}
// Possible code paths:
// REQUIRED = {}
// OPTIONAL = [command|subcommand]
/////////////////////////////////////////////////////////////////////////////
/// @fn HelpCommand
///
/// @param[in] player is player who ran command
///
/// @param[in] helpCommand is the argument list to be parsed
///
/// @brief Builds a dynamic help list to the player to see all command
/// options on the server
/////////////////////////////////////////////////////////////////////////////
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()) {
String cmd = msgFormatter.ColorMsg(helpCmd.getKey(), COLOR_CODE.GOLD);
String details = msgFormatter.FormatMsg(helpCmd.getValue(), COLOR_CODE.BLUE, COLOR_CODE.GRAY);
sourcePlayer.sendMessage(Text.of(cmd + " --> " + details));
sourcePlayer.sendMessage(Text.of("\n"));
}
} else {
// Iterate over list; verifying what commands are found
List<String> unknownCmds = new ArrayList<String>();
for (int i = 0; i < helpCommand.size(); i++) {
String newHelpCmd = helpCommand.get(i);
if (HELP_COMMANDS.containsKey(newHelpCmd)) {
// Print help for this specific command
String cmd = msgFormatter.ColorMsg(newHelpCmd, COLOR_CODE.GOLD);
String details = msgFormatter.FormatMsg(HELP_COMMANDS.get(newHelpCmd), COLOR_CODE.BLUE, COLOR_CODE.GRAY);
sourcePlayer.sendMessage(Text.of(cmd + " -> " + details));
} else {
// Add to unknown list at end
unknownCmds.add(newHelpCmd);
}
}
// After all prints have finished tell the player the commands they plugged in that we did not recognize
if (unknownCmds.size() > 0) {
String msg = msgFormatter.ColorMsg("The following commands do not exist or were mispelt: ", COLOR_CODE.RED);
sourcePlayer.sendMessage(Text.of(msg + unknownCmds));
}
}
return 0;
}
// Possible args:
// /bank create {SAVINGS/CHECKING} [optional: alias]
/////////////////////////////////////////////////////////////////////////////
/// @fn CreateAccount
///
/// @param[in] player is player who ran command
///
/// @param[in] accountArgs is the argument list to be parsed
///
/// @brief Creates a bank account
/////////////////////////////////////////////////////////////////////////////
public int CreateAccount(ServerPlayerEntity player, ACCOUNT_TYPE accountType) {
String bank = BankManager.GetInstance().GetPlayerSelectedBank(player.getUuidAsString());
System.out.println("Received bank: " + bank);
if (bank != "") {
BankManager.GetInstance().InitiateBankAccountCreation(bank, player, accountType);
}
return 0;
}
// Possible code paths for /bank create report
// required = {ACCOUNT ID / ALIAS} or {ALL}
/////////////////////////////////////////////////////////////////////////////
/// @fn GenerateAccountReport
///
/// @param[in] player is player who ran command
///
/// @param[in] reportArgs is the argument list to be parsed
///
/// @brief Creates a bank account(s) report
/////////////////////////////////////////////////////////////////////////////
public void GenerateAccountReport(ServerPlayerEntity player, List<String> reportArgs) {
if (reportArgs.size() > 0) {
String reportIdentifier = reportArgs.get(0).toLowerCase();
// First path is just to run a report on all accounts this player is attached to:
if (reportIdentifier == "all") {
/* BANKMANAGER CALL HERE. LOOP LIKELY NEEDED */
} else {
/* BANKMANAGER CALL HERE */
}
} else {
player.sendMessage(Text.of("Unrecognized report field data. Please run /bank help report for more information"));
}
}
}

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
@ -22,13 +22,18 @@ public class CustomCommandManager {
NoteCommands noteCommands = new NoteCommands();
BankCommands bankCommands = new BankCommands();
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

@ -1,47 +1,284 @@
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 jesse.keeblarcraft.FactionMgr.FactionTier.FactionTierEnum;
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.server.world.ServerWorld;
import net.minecraft.text.Text;
import net.minecraft.util.ActionResult;
public class FactionCommands {
// Register function for commands
/////////////////////////////////////////////////////////////////////////////
/// @fn RegisterFactionCommands
///
/// @brief Registers all commands for factions
/////////////////////////////////////////////////////////////////////////////
public void RegisterFactionCommands() {
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
var factionNode = CommandManager.literal("faction").build();
var createFaction = CommandManager.literal("create").build();
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 set = CommandManager.literal("set").build();
var get = CommandManager.literal("get").build();
var power = CommandManager.literal("power").build();
var join = CommandManager.literal("join").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())
.executes(context -> CreateFaction
(
context,
StringArgumentType.getString(context, "faction_name")
)
).build();
var disbandFactionName = CommandManager.argument("faction_name", StringArgumentType.greedyString())
.executes(context -> DeleteFaction
(
context,
StringArgumentType.getString(context, "faction_name")
)
).build();
var joinName = CommandManager.argument("faction_name", StringArgumentType.string())
.executes(context -> JoinFaction(context.getSource().getPlayer(), StringArgumentType.getString(context, "faction_name")))
.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 setPower = CommandManager.literal("power").build();
var setPowerAmnt = CommandManager.argument("power_amount", IntegerArgumentType.integer()).build();
var setPowerName = CommandManager.argument("set_power_name", StringArgumentType.string())
.executes(context -> SetFactionPower(context.getSource().getPlayer(), StringArgumentType.getString(context, "set_power_name"), IntegerArgumentType.getInteger(context, "power_amount")))
.build();
var getPowerName = CommandManager.argument("get_power_name", StringArgumentType.string())
.executes(context -> GetFactionPower(context.getSource().getPlayer(), StringArgumentType.getString(context, "get_power_name"))).build();
var leaveFaction = CommandManager.literal("leave").executes(context -> LeaveFaction(context)
).build();
var listAll = CommandManager.literal("list")
.executes(context -> ListAllFactions(context.getSource().getPlayer())).build();
// Root node
dispatcher.getRoot().addChild(factionNode);
// List command
factionNode.addChild(listAll);
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);
factionNode.addChild(set);
factionNode.addChild(get);
factionNode.addChild(join);
join.addChild(joinName);
get.addChild(power);
power.addChild(getPowerName);
set.addChild(setPower);
setPower.addChild(setPowerAmnt);
setPowerAmnt.addChild(setPowerName);
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 HANDLERS BELOW
private int CreateFaction() {
private int ForwardFlightCallback(CommandContext<ServerCommandSource> context) {
if (context.getSource().isExecutedByPlayer()) {
ServerPlayerEntity player = context.getSource().getPlayer();
ServerWorld world = context.getSource().getWorld();
Integer fPower = FactionManager.GetInstance().GetFactionPower(player);
FactionTierEnum fTier = FactionManager.GetInstance().GetFactionTier(FactionManager.GetInstance().GetFactionOfPlayer(player.getUuidAsString()));
ActionResult result = PlayerCommandFlightCallback.EVENT.invoker().interact(player, world, fPower, fTier);
}
return 0;
}
public int SetFactionPower(ServerPlayerEntity caller, String faction, Integer amount) {
Boolean success = FactionManager.GetInstance().SetFactionPower(caller, faction, amount);
if (success) {
caller.sendMessage(Text.of("Successfully set the faction " + faction + " power to " + amount));
} else {
caller.sendMessage(Text.of("This is an operator only command!"));
}
return 0;
}
public int JoinFaction(ServerPlayerEntity player, String factionName) {
FactionManager.GetInstance().JoinFaction(player, factionName);
return 0;
}
public int GetFactionPower(ServerPlayerEntity player) {
FactionManager.GetInstance().GetFactionPower(player);
return 0;
}
public int GetFactionPower(ServerPlayerEntity player, String factionName) {
Integer amnt = FactionManager.GetInstance().GetFactionPower(factionName);
player.sendMessage(Text.of("[" + factionName + " - POWER]:" + amnt));
return 0;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn CreateFaction
///
/// @param[in] context is the context of where this command runs from
///
/// @param[in] newFactionName is the faction name to be created
///
/// @brief Command to create a faction
/////////////////////////////////////////////////////////////////////////////
private int CreateFaction(CommandContext<ServerCommandSource> context, String newFactionName) {
int retValue = 0;
System.out.println("CreateFaction getting player obj");
ServerPlayerEntity player = context.getSource().getPlayer();
System.out.println("CreateFaction called");
if (newFactionName.length() >= 4) {
FactionManager.GetInstance().CreateFaction(newFactionName, player);
} else {
player.sendMessage(Text.of("Your faction must be at least 4 letters long!"));
}
return retValue;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn DeleteFaction
///
/// @param[in] context is the context of where this command runs from
///
/// @param[in] newFactionName is the faction name to be deleted
///
/// @brief Command to create a faction
/////////////////////////////////////////////////////////////////////////////
private int DeleteFaction(CommandContext<ServerCommandSource> context, String factionName) {
int retValue = 0;
ServerPlayerEntity player = context.getSource().getPlayer();
FactionManager.GetInstance().DeleteFaction(factionName, player);
return retValue;
}
private int InvitePlayerToFaction(CommandContext<ServerCommandSource> context, ServerPlayerEntity player) {
FactionManager.GetInstance().InvitePlayerToFaction(context.getSource().getPlayer(), player.getUuidAsString(), player.getEntityName());
return 0;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn LeaveFaction
///
/// @param[in] context is the context of where this command runs from
///
/// @brief Command to leave a faction
/////////////////////////////////////////////////////////////////////////////
private int LeaveFaction(CommandContext<ServerCommandSource> context) {
ServerPlayerEntity player = context.getSource().getPlayer();
FactionManager.GetInstance().LeaveFaction(player);
return 0;
}
// Returns information on the players current faction
private int GetFactionInformation(ServerPlayerEntity player) {
FactionManager.GetInstance().GetFactionInformation(player);
return 0;
}
private int KickPlayerFromFaction(CommandContext<ServerCommandSource> context, ServerPlayerEntity player) {
int retValue = -1;
return retValue;
}
private int DeleteFaction() {
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 AddPlayerToFaction() {
int retValue = -1;
return retValue;
}
private int KickPlayerFromFaction() {
int retValue = -1;
return retValue;
}
private int PromotePlayerInFaction() {
int retValue = -1;
return retValue;
}
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() {
@ -56,13 +293,6 @@ public class FactionCommands {
return retValue;
}
// admin only
private int SetFactionPower() {
int retValue = -1;
return retValue;
}
private int DeclareFactionEvent() {
int retValue = -1;
@ -87,9 +317,25 @@ public class FactionCommands {
return retValue;
}
private int ListAllFactions() {
/////////////////////////////////////////////////////////////////////////////
/// @fn ListAllFactions
///
/// @param[in] player is the command runner
///
/// @brief Command to see all factions on the server
/////////////////////////////////////////////////////////////////////////////
private int ListAllFactions(ServerPlayerEntity player) {
int retValue = -1;
System.out.println("Listing factions");
List<String> facs = FactionManager.GetInstance().ListOfFactions();
if (facs != null) {
player.sendMessage(Text.of("All factions on server: " + facs));
} else {
player.sendMessage(Text.of("There are no factions on this server yet!"));
}
return retValue;
}

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

@ -0,0 +1,176 @@
package jesse.keeblarcraft.Commands;
import com.mojang.brigadier.arguments.StringArgumentType;
import jesse.keeblarcraft.ConfigMgr.ConfigManager;
import jesse.keeblarcraft.ConfigMgr.GeneralConfig;
import jesse.keeblarcraft.Utils.DirectionalVec;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
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.math.Vec3d;
public class MiscCommands {
ConfigManager config = new ConfigManager();
public void RegisterCommands() {
// CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
// var magicInv = CommandManager.literal("magic-inv").build();
// var claim = CommandManager.literal("claim").executes(context -> ClaimInventory(context.getSource().getPlayer())).build();
// dispatcher.getRoot().addChild(magicInv);
// magicInv.addChild(claim);
// });
// CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
// var eChest = CommandManager.literal("enderchest").build();
// var player = CommandManager.argument("PLAYER", EntityArgumentType.player()).executes(
// context -> GetEnderchestOfPlayer(context.getSource().getPlayer(), EntityArgumentType.getPlayer(context, "PLAYER"))
// ).build();
// dispatcher.getRoot().addChild(eChest);
// eChest.addChild(player);
// // Alias
// dispatcher.register(CommandManager.literal("echest").redirect(eChest));
// });
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
var forceSpawn = CommandManager.literal("set-global-spawn").executes(context -> ForceGlobalSpawn(context.getSource().getPlayer())).build();
dispatcher.getRoot().addChild(forceSpawn);
});
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
var warp = CommandManager.literal("warp").build();
var warpLoc = CommandManager.argument("LOCATION", StringArgumentType.string())
.executes(context -> Warp(context.getSource().getPlayer(), StringArgumentType.getString(context, "LOCATION"))).build();
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) {
if (player.hasPermissionLevel(4)) {
System.out.println("Player is opped");
// hard coding spawn as only valid warp location. a more robust warp system can come later
DirectionalVec coords = GeneralConfig.GetInstance().GetSpawnCoords();
// DIRTY HACK: I am unsure how to compare the straight registry key. So for now, we will just iterate over all the worlds in the server. This really should
// not be a big deal since I have never seen a server with hundreds of worlds... but you never know I guess.
for (ServerWorld world : player.getServer().getWorlds()) {
System.out.println("Matched!");
if (world.getRegistryKey().toString().equals(coords.world.toString())) {
try {
player.teleport(world, coords.x, coords.y, coords.z, coords.yaw, coords.pitch);
} catch (Exception e) {
e.printStackTrace();
}
break;
} else {
System.out.println("KEY {" + world.getRegistryKey() + "} DID NOT MATCH OURS {" + coords.world + "}");
}
}
System.out.println("POST TELEPORT");
} else {
player.sendMessage(Text.of("This command is only available to server admins at the moment!"));
}
return 0;
}
public int ForceGlobalSpawn(ServerPlayerEntity player) {
if (player.hasPermissionLevel(4)) {
Vec3d coords = player.getPos();
DirectionalVec spawnVec = new DirectionalVec();
spawnVec.x = coords.x;
spawnVec.y = coords.y;
spawnVec.z = coords.z;
spawnVec.pitch = player.getPitch();
spawnVec.yaw = player.getYaw();
spawnVec.world = player.getWorld().getRegistryKey();
System.out.println("REG KEY OF SET: " + player.getWorld().getRegistryKey().toString());
System.out.println("REG KEY OF SET: " + player.getWorld().getRegistryKey());
player.sendMessage(Text.of("Global spawn has been set to [X, Y, Z]--[YAW, PITCH]: [" +
spawnVec.x + " " + spawnVec.y + " " + spawnVec.z + "]--" + "[" + spawnVec.yaw + " " + spawnVec.pitch + "]" + " IN WORLD " +
player.getWorld().asString()));
GeneralConfig.GetInstance().SetSpawnCoords(spawnVec);
} else {
player.sendMessage(Text.of("You do not have permission to use this command."));
}
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)) {
// EnderChestInventory enderInv = targetPlayer.getEnderChestInventory();
// enderInv.
// } else {
// }
return 0;
}
// public int ClaimInventory(ServerPlayerEntity player) {
// Vec3d playerPosition = player.getPos();
// BlockPos blockPosition = new BlockPos((int) playerPosition.x + 4, (int) playerPosition.y, (int) playerPosition.z).east();
// BlockPos blockPosition2 = new BlockPos((int) playerPosition.x + 3, (int) playerPosition.y, (int) playerPosition.z).east();
// // Verify we can place the blocks before loading cached inventory
// if (player.getWorld().setBlockState(blockPosition, chestState)
// && player.getWorld().setBlockState(blockPosition2, chestState)) {
// // The below code WILL remove the inventory from the dimension cache. Only get
// // it when we succeed in placing chests!
// NbtList nbtInventory = DimensionLoadingEvent.GetInstance().GetInventory(player.getUuidAsString());
// if (nbtInventory != null) {
// BlockEntity block = player.getWorld().getBlockEntity(blockPosition);
// BlockEntity block2 = player.getWorld().getBlockEntity(blockPosition2);
// if (block != null && block2 != null) {
// block.markDirty();
// block2.markDirty();
// }
// player.sendMessage(Text.of("Look around, your magic inventory chest was placed near you!"));
// }
// } else {
// player.sendMessage(Text.of("Well, this is embarassing! Could not place magic inventory chest near you!"));
// }
// return 0;
// }
}

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,28 +20,10 @@ 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
/////////////////////////////////////////////////////////////////////////////
/// @fn RegisterNoteCommands
///
@ -136,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;
@ -165,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);
@ -205,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;
}
@ -231,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 {
@ -258,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;
@ -28,63 +29,203 @@ import java.util.List;
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;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn WriteNbtListToFile
///
/// @param[in] fileName is the file location to write to
///
/// @param[in] key is the compound key type to store
///
/// @param[in] data is the NbtList to write
///
/// @brief Writes NbtList data to disk
/////////////////////////////////////////////////////////////////////////////
public void WriteNbtListToFile(String fileName, String key, NbtList data) {
// fileName = "config/keeblarcraft/" + fileName;
File file = GetFile(fileName);
if (!file.exists()) {
file.getParentFile().mkdirs();
}
try {
NbtCompound compound = new NbtCompound();
compound.put(key, data);
NbtIo.writeCompressed(compound, file);
} catch (Exception e) {
e.printStackTrace();
}
}
/////////////////////////////////////////////////////////////////////////////
/// @fn ReadAllNbtListFromDirectory
///
/// @param[in] dir is the directory path to read from
///
/// @param[in] listType is the NBT Compound list type
///
/// @brief Reads in NBTList data from a directory; using file names as key.
/// If a file is read in correctly, the file is deleted
///
/// @return A map of NbtList data with the key being the file name (minus ext)
/////////////////////////////////////////////////////////////////////////////
public HashMap<String, NbtList> ReadAllNbtListFromDirectory(String dir, int listType) {
HashMap<String, NbtList> list = new HashMap<String, NbtList>();
// dir = "config/keeblarcraft/" + dir;
File directory = GetFile(dir);
File[] files = directory.listFiles();
if (files != null) {
for (File file : files) {
String key = file.getName().substring(0, file.getName().length() - 4);
NbtList nbtList = ReadNbtListFromFile(file, key, listType);
if (nbtList != null) {
// Subtract out '.nbt' from name
list.put(key, nbtList);
file.delete();
}
}
}
return list;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn ReadNbtListFromFile
///
/// @param[in] file handler object to read nbt list data from
///
/// @param[in] key for the nbt compound object
///
/// @param[in] listType is the NBT Compound list type
///
/// @brief Reads in NBTList data from a single file
///
/// @return NbtList data
/////////////////////////////////////////////////////////////////////////////
public NbtList ReadNbtListFromFile(File file, String key, int listType) {
NbtList list = null;
try {
NbtCompound c = NbtIo.readCompressed(file);
list = c.getList(key, listType);
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
// WriteToFile
@ -95,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);
@ -106,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;
@ -128,16 +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();
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", CONSOLE_COLOR.RED));
throw new FILE_WRITE_EXCEPTION();
Keeblarcraft.LOGGER.error("Could not successfully write to json file ["+fileName+"]");
e.printStackTrace();
}
}
@ -151,73 +293,28 @@ public class ConfigManager {
// 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);
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
@ -225,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

@ -0,0 +1,168 @@
package jesse.keeblarcraft.ConfigMgr;
import java.util.ArrayList;
import java.util.List;
import jesse.keeblarcraft.Utils.DirectionalVec;
public class GeneralConfig {
private static GeneralConfig static_inst;
ConfigManager cfgMgr = new ConfigManager();
private ImplementedConfig config;
public static GeneralConfig GetInstance() {
if (static_inst == null) {
static_inst = new GeneralConfig();
}
return static_inst;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn GetConfig
///
/// @brief Returns the mods general configuration file object
///
/// @return The configuration object
/////////////////////////////////////////////////////////////////////////////
public ImplementedConfig GetConfig() {
if (config == null) {
config = new ImplementedConfig();
FlashConfig();
}
return config;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn GeneralConfig
///
/// @brief Constructs the general configuration file for the project
/////////////////////////////////////////////////////////////////////////////
public GeneralConfig() {
Boolean existingFile = false;
try {
config = cfgMgr.GetJsonObjectFromFile("general.json", ImplementedConfig.class);
existingFile = true;
} catch(Exception e) {
System.out.println("FAILED TO READ IN GENERALCONFIG");
e.printStackTrace();
}
if (!existingFile) {
config = new ImplementedConfig();
FlashConfig();
}
if (config == null) {
config = new ImplementedConfig();
FlashConfig();
}
}
/////////////////////////////////////////////////////////////////////////////
/// @fn GetSpawnCoords
///
/// @brief Gets the coordinates for the global spawn
///
/// @return A vector containing how a player should spawn in or null if not
/// set yet.
/////////////////////////////////////////////////////////////////////////////
public DirectionalVec GetSpawnCoords() {
System.out.println("Among us");
System.out.println("GetSpawnCoords called. is global_spawn null? " + (config.global_spawn == null ? "YES": "NO"));
return config.global_spawn;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn SetSpawnCoords
///
/// @brief Sets the coordinates for the global spawn
/////////////////////////////////////////////////////////////////////////////
public void SetSpawnCoords(DirectionalVec vec) {
config.global_spawn = vec;
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
///
/// @param[in] uuid is the player uuid
///
/// @brief Checks to see if player uuid has ever joined. If not, then add
/// to global list of uuids who have joined.
///
/// @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);
System.out.println("Value of isNew is " + isNew);
if (isNew) {
config.playerList.add(uuid);
FlashConfig();
}
return isNew;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn GetMOTD
///
/// @brief String object with the MOTD of the server
/////////////////////////////////////////////////////////////////////////////
public String GetMOTD() {
return config.MOTD;
}
/////////////////////////////////////////////////////////////////////////////
/// @class ImplementedConfig is the configuration class holder
/////////////////////////////////////////////////////////////////////////////
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
public List<String> playerList = new ArrayList<>();
DirectionalVec global_spawn;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn FlashConfig
///
/// @brief String object with the MOTD of the server
/////////////////////////////////////////////////////////////////////////////
private void FlashConfig() {
System.out.println("Attempting to write generalconfig to file. Is null? " + (config == null ? "YES" : "NO"));
cfgMgr.WriteToJsonFile("general.json", config);
}
}

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,219 @@
package jesse.keeblarcraft.CustomBlocks.BlockEntities;
import java.util.ArrayList;
import jesse.keeblarcraft.AttributeMgr.AttributeMgr;
import jesse.keeblarcraft.FactionMgr.FactionManager;
import jesse.keeblarcraft.FactionMgr.Callbacks.PlayerEnteredBaseCallback;
import jesse.keeblarcraft.FactionMgr.Callbacks.PlayerExitedBaseCallback;
import jesse.keeblarcraft.FactionMgr.Callbacks.PlayerInBaseCallback;
import jesse.keeblarcraft.FactionMgr.FactionTier.FactionTierEnum;
import jesse.keeblarcraft.GuiMgr.FactionBlockScreenHandler;
import jesse.keeblarcraft.Utils.CommonStructures.Position3d;
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 String faction; // Faction this block belongs to
private static int factionPower = 0;
private FactionTierEnum factionTier = FactionTierEnum.TIER_INVALID;
Boolean stopMobSpawn = true;
Boolean hasBuildFlight = true;
Boolean hasSuperBeacon = true;
Boolean hasItemRepair = true;
Position3d storedBlockPos;
private ArrayList<String> playersInRadius = new ArrayList<>();
protected final PropertyDelegate propertyDelegate;
public FactionBlockEntity(BlockPos pos, BlockState state, String faction) {
this(pos, state);
this.faction = faction;
}
public void SetFaction(String faction) {
this.faction = faction;
}
public FactionBlockEntity(BlockPos pos, BlockState state) {
super(BlockEntityRegistration.FACTION_BLOCK_ENTITY, pos, state);
storedBlockPos = new Position3d(pos.getX(), pos.getY(), pos.getZ());
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;
String playerFaction = FactionManager.GetInstance().GetFactionOfPlayer(player.getUuidAsString());
// Verify the player is in the faction to be considered "in bounds"!
if (playerFaction.equals(faction)) {
// 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;
}
// Call when the block attached to this entity is broken so we can send out our last messages to reset players correctly before perishing
public void ResetBlock() {
System.out.println("Reset block called. Is world null? " + (world==null?"YES":"NO"));
if (world != null) {
for (PlayerEntity player : world.getPlayers()) {
Boolean isPlayerInFactionRadius = IsPlayerInBounds(player, pos);
if (isPlayerInFactionRadius) {
ActionResult result = PlayerExitedBaseCallback.EVENT.invoker().interact(player, world, factionPower, factionTier);
}
}
} else {
System.out.println("Error, world is null and factionblockentity cannot reset players!");
}
}
// 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() || faction == null) {
return;
}
this.world = world;
factionPower = FactionManager.GetInstance().GetFactionPower(faction);
factionTier = FactionManager.GetInstance().GetFactionTier(faction);
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, factionPower, factionTier);
}
// Invoke the flight attribute on this player
if (hasBuildFlight) {
AttributeMgr.ApplyAttribute(player.getUuidAsString(), "faction_flight");
ActionResult result = PlayerInBaseCallback.EVENT.invoker().interact(player, world, factionPower, factionTier);
}
if (hasSuperBeacon) {
AttributeMgr.ApplyAttribute(player.getUuidAsString(), "faction_beacon");
// ActionResult result = PlayerInBaseCallback.EVENT.invoker().interact(player, world);
}
if (hasItemRepair) {
AttributeMgr.ApplyAttribute(player.getUuidAsString(), "faction_item_repair");
}
} else if (!isPlayerInFactionRadius && playersInRadius.contains(player.getUuidAsString())) {
playersInRadius.remove(player.getUuidAsString());
ActionResult result = PlayerExitedBaseCallback.EVENT.invoker().interact(player, world, factionPower, factionTier);
}
}
// 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

@ -0,0 +1,86 @@
// package jesse.keeblarcraft.CustomBlocks.BlockEntities;
// import jesse.keeblarcraft.Keeblarcraft;
// import jesse.keeblarcraft.CustomBlocks.BlockManager;
// import jesse.keeblarcraft.world.ImplementedInventory;
// 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.registry.RegistryWrapper;
// import net.minecraft.screen.NamedScreenHandlerFactory;
// import net.minecraft.screen.PropertyDelegate; // for syncing client + server
// import net.minecraft.screen.ScreenHandler;
// import net.minecraft.text.Text;
// import net.minecraft.util.collection.DefaultedList;
// import net.minecraft.util.math.BlockPos;
// public class MagicChestBlockEntity extends BlockEntity implements NamedScreenHandlerFactory, ImplementedInventory {
// private final DefaultedList<ItemStack> inventory = DefaultedList.ofSize(256, ItemStack.EMPTY);
// protected final PropertyDelegate propertyDelegate;
// private int progress = 0;
// private int maxProgress = 72;
// public MagicChestBlockEntity(BlockPos pos, BlockState state) {
// super(Keeblarcraft.MAGIC_CHEST_BLOCK_ENTITY, pos, state);
// this.propertyDelegate = new PropertyDelegate() {
// @Override
// public int get(int index) {
// return switch(index) {
// case 0 -> MagicChestBlockEntity.this.progress;
// case 1 -> MagicChestBlockEntity.this.maxProgress;
// default -> 0;
// };
// }
// @Override
// public void set(int index, int value) {
// switch (index) {
// case 0 -> MagicChestBlockEntity.this.progress = value;
// case 1 -> MagicChestBlockEntity.this.maxProgress = value;
// };
// }
// // MUST be size of how many integers we are synchronizing
// @Override
// public int size() {
// return 2;
// }
// };
// }
// @Override
// public ScreenHandler createMenu(int syncId, PlayerInventory playerInventory, PlayerEntity player) {
// // Screen handler will sync the inventory
// return new MagicChestScreenHandler(syncId, playerInventory, this);
// }
// @Override
// public DefaultedList<ItemStack> getItems() {
// return inventory;
// }
// @Override
// public Text getDisplayName() {
// return Text.translatable(getCachedState().getBlock().getTranslationKey());
// }
// @Override
// public void readNbt(NbtCompound nbt) {
// super.readNbt(nbt);
// Inventories.readNbt(nbt, this.inventory);
// }
// @Override
// public void writeNbt(NbtCompound nbt) {
// super.writeNbt(nbt);
// Inventories.writeNbt(nbt, this.inventory);
// }
// }

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;
@ -19,6 +19,7 @@ public class BlockList {
public static void RegisterBlocks() {
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("example_statue", new Block(FabricBlockSettings.copyOf(Blocks.BELL).nonOpaque()));
BlockManager.RegisterBlock("faction_base_block", new FactionBaseBlock(FabricBlockSettings.copyOf(Blocks.COBBLESTONE).requiresTool().nonOpaque()));
}
}

View File

@ -0,0 +1,124 @@
package jesse.keeblarcraft.CustomBlocks.Blocks;
import org.jetbrains.annotations.Nullable;
import jesse.keeblarcraft.CustomBlocks.BlockEntities.BlockEntityRegistration;
import jesse.keeblarcraft.CustomBlocks.BlockEntities.FactionBlockEntity;
import jesse.keeblarcraft.FactionMgr.FactionManager;
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.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.NamedScreenHandlerFactory;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
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.world.World;
import net.minecraft.world.WorldAccess;
public class FactionBaseBlock extends BlockWithEntity implements BlockEntityProvider {
// public static final VoxelShape SHAPE = Block.createCuboidShape(0, 0, 0, 16, 12, 16);
private String faction; // Faction attached to this block
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 void onPlaced(World world, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack itemStack) {
if (world.isClient()) {
return;
}
if (placer.isPlayer()) {
// We need to run faction checks here and make sure this player owns a faction otherwise they are NOT allowed to place it!
ServerPlayerEntity player = (ServerPlayerEntity) placer;
String fac = FactionManager.GetInstance().GetFactionOfPlayer(player.getUuidAsString());
FactionBlockEntity bEntity = (FactionBlockEntity) world.getBlockEntity(pos);
// Update block entity
if (bEntity != null) {
bEntity.SetFaction(fac);
}
// An empty string implies NO faction; only do things if it is NOT empty
if (!fac.equals("")) {
faction = fac;
player.sendMessage(Text.of("This block now belongs to the " + faction + " faction."));
} else {
player.sendMessage(Text.of("You do not appear to be in a faction, and thus this block cannot be placed!"));
// world.removeBlock(pos, false);
world.breakBlock(pos, true);
}
}
}
@Override
public BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
return new FactionBlockEntity(pos, state, faction);
}
// 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);
}
// This is pulled directly from #AbstractBlock$AbstractBlockState.class:onStateReplaced
// Catch if the block is being broken. Update our block entity to reset all
if (state.hasBlockEntity() && !state.isOf(newState.getBlock())) {
FactionBlockEntity bEntity = (FactionBlockEntity) world.getBlockEntity(pos);
if (bEntity != null) {
bEntity.ResetBlock();
}
}
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

@ -0,0 +1,43 @@
// package jesse.keeblarcraft.CustomBlocks.Blocks;
// import jesse.keeblarcraft.CustomBlocks.BlockEntities.MagicChestBlockEntity;
// import net.minecraft.block.BlockRenderType;
// import net.minecraft.block.BlockState;
// import net.minecraft.block.BlockWithEntity;
// import net.minecraft.block.entity.BlockEntity;
// 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.hit.BlockHitResult;
// import net.minecraft.util.math.BlockPos;
// import net.minecraft.world.World;
// public class MagicChestBlock extends BlockWithEntity {
// public MagicChestBlock(Settings settings) {
// super(settings);
// }
// @Override
// public BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
// return new MagicChestBlockEntity(pos, state);
// }
// @Override
// public BlockRenderType getRenderType(BlockState state) {
// return BlockRenderType.MODEL;
// }
// @Override
// public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
// if (!world.isClient) {
// NamedScreenHandlerFactory screenHandlerFactory = ((MagicChestBlockEntity) world.getBlockEntity(pos));
// if (screenHandlerFactory != null) {
// player.openHandledScreen(screenHandlerFactory);
// }
// }
// return ActionResult.SUCCESS;
// }
// }

View File

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

View File

@ -0,0 +1,125 @@
package jesse.keeblarcraft.EventMgr;
import java.util.HashMap;
import java.util.Map.Entry;
import jesse.keeblarcraft.ConfigMgr.ConfigManager;
import jesse.keeblarcraft.world.dimension.ModDimensions;
import net.minecraft.nbt.NbtElement;
import net.minecraft.nbt.NbtList;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
public class DimensionLoadingEvent {
private static DimensionLoadingEvent static_inst;
/////////////////////////////////////////////////////////////////////////////
/// @fn GetInstance
///
/// @brief Static instance getter for this class
/////////////////////////////////////////////////////////////////////////////
public static DimensionLoadingEvent GetInstance() {
if (static_inst == null) {
static_inst = new DimensionLoadingEvent();
}
return static_inst;
}
// Helper class to manage the single inventory cache of dimension loading
private static class InventoryWrapper {
public HashMap<String, NbtList> inventories = new HashMap<String, NbtList>();
}
private static InventoryWrapper iw = new InventoryWrapper();
private static String CONFIG_LOCATION = "misc/dim_loading_cached_inventories/";
ConfigManager config = new ConfigManager();
public DimensionLoadingEvent() {
// read config
iw.inventories = config.ReadAllNbtListFromDirectory(CONFIG_LOCATION, NbtElement.COMPOUND_TYPE);
}
/////////////////////////////////////////////////////////////////////////////
/// @fn HandleWorldMove
///
/// @param[in] player is the player object
///
/// @param[in] origin is the FROM destination world
///
/// @param[in] destination is the TO destination world
///
/// @brief Callback handler for player world move events on server
/////////////////////////////////////////////////////////////////////////////
public void HandleWorldMove(ServerPlayerEntity player, ServerWorld origin, ServerWorld destination) {
System.out.println("World move event called!");
// Player is ENTERING the custom dimension; strip their inventory!
if (destination.getDimensionEntry().matchesKey(ModDimensions.KEEBLAR_DIM_TYPE) && (!iw.inventories.containsKey(player.getUuidAsString()))) {
// Make sure player is in map. For now we only care about storing OVERWORLD inventory. We DO NOT care about
// the dimension inventory!
// if (!iw.inventories.containsKey(player.getUuidAsString())) {
// Copy the nbt into the list
NbtList inventoryNbt = new NbtList();
player.getInventory().writeNbt(inventoryNbt);
iw.inventories.put(player.getUuidAsString(), inventoryNbt);
player.getInventory().clear();
// }
// Player is LEAVING the custom dimension. Give them their stuff back
} else if (origin.getDimensionEntry().matchesKey(ModDimensions.KEEBLAR_DIM_TYPE) && iw.inventories.containsKey(player.getUuidAsString())) {
// if (iw.inventories.containsKey(player.getUuidAsString())) {
player.getInventory().readNbt(iw.inventories.get(player.getUuidAsString()));
iw.inventories.remove(player.getUuidAsString());
// }
}
FlashConfig();
}
/////////////////////////////////////////////////////////////////////////////
/// @fn SaveInventories
///
/// @brief Flashes the configuration file on disk (call before server exit
/// to not lose memory!)
/////////////////////////////////////////////////////////////////////////////
public void SaveInventories() {
System.out.println("Call to save inventories. Flashing IW.Inventories with size " + iw.inventories.size());
FlashConfig();
}
/////////////////////////////////////////////////////////////////////////////
/// @fn GetInventories
///
/// @param Player uuid
///
/// @brief Gets a player inventory from the map. Calling this action also
/// removes the inventory from the stored map so be sure to use
/// it if you call it!
/////////////////////////////////////////////////////////////////////////////
public NbtList GetInventory(String uuid) {
NbtList nbt = iw.inventories.get(uuid);
iw.inventories.remove(uuid);
return nbt;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn FlashConfig
///
/// @brief Flashes configuration file to disk
/////////////////////////////////////////////////////////////////////////////
public void FlashConfig() {
try {
// config.WriteToJsonFile(CONFIG_LOCATION, iw);
// First, ensure list is size > 0
for (Entry<String, NbtList> list : iw.inventories.entrySet()) {
if (list.getValue().size() > 0) {
config.WriteNbtListToFile(CONFIG_LOCATION + list.getKey() + ".nbt", list.getKey(), list.getValue());
}
}
} catch (Exception e) {
System.out.println("Could not flash dimension loading configuration file");
}
}
}

View File

@ -0,0 +1,135 @@
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;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerPlayNetworkHandler;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
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() {
if (static_inst == null) {
static_inst = new 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
///
/// @param[in] handler is the network handler
///
/// @param[in] sender is the packet sender
///
/// @param[in] server is the MinecraftServer instance
///
/// @brief Callback function for player join event in minecraft server
/////////////////////////////////////////////////////////////////////////////
public void HandleServerJoinEvent(ServerPlayNetworkHandler handler, PacketSender sender, MinecraftServer server) {
var player = handler.player;
// Handle skill tree map instance
if (AttributeMgr.activeTrees.containsKey(player.getUuidAsString()) == false) {
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());
}
/////////////////////////////////////////////////////////////////////////////
/// @fn IsFirstTimeLogin
///
/// @param[in] player is the player who is joining
///
/// @param[in] server is the MinecraftServer instance
///
/// @brief Check to see if player is first time log-in. If so, we teleport
/// them to spawn. This function may be expanded in future
/////////////////////////////////////////////////////////////////////////////
private void IsFirstTimeLogin(ServerPlayerEntity player, MinecraftServer server) {
// Send the MOTD + Spawn in global spawn
player.sendMessage(Text.of(GeneralConfig.GetInstance().GetMOTD()));
if (GeneralConfig.GetInstance().IsNewPlayer(player.getUuidAsString())) {
DirectionalVec coords = GeneralConfig.GetInstance().GetSpawnCoords();
if (coords != null) {
for (ServerWorld world : player.getServer().getWorlds()) {
if (world.getRegistryKey().toString().equals(coords.world.toString())) {
try {
player.teleport(world, coords.x, coords.y, coords.z, coords.yaw, coords.pitch);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}
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,25 @@
package jesse.keeblarcraft.FactionMgr.Callbacks;
import jesse.keeblarcraft.FactionMgr.FactionTier.FactionTierEnum;
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, power, factionTier) -> {
for (PlayerCommandFlightCallback listener : listeners) {
ActionResult result = listener.interact(player, world, power, factionTier);
if (result != ActionResult.PASS) {
return result;
}
}
return ActionResult.PASS;
});
ActionResult interact(PlayerEntity player, World world, Integer factionPower, FactionTierEnum factionTier);
}

View File

@ -0,0 +1,25 @@
package jesse.keeblarcraft.FactionMgr.Callbacks;
import jesse.keeblarcraft.FactionMgr.FactionTier.FactionTierEnum;
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, power, factionTier) -> {
for (PlayerEnteredBaseCallback listener : listeners) {
ActionResult result = listener.interact(player, world, power, factionTier);
if (result != ActionResult.PASS) {
return result;
}
}
return ActionResult.PASS;
});
ActionResult interact(PlayerEntity player, World world, Integer factionPower, FactionTierEnum factionTier);
}

View File

@ -0,0 +1,25 @@
package jesse.keeblarcraft.FactionMgr.Callbacks;
import jesse.keeblarcraft.FactionMgr.FactionTier.FactionTierEnum;
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, power, factionTier) -> {
for (PlayerExitedBaseCallback listener : listeners) {
ActionResult result = listener.interact(player, world, power, factionTier);
if (result != ActionResult.PASS) {
return result;
}
}
return ActionResult.PASS;
});
ActionResult interact(PlayerEntity player, World world, Integer factionPower, FactionTierEnum factionTier);
}

View File

@ -0,0 +1,25 @@
package jesse.keeblarcraft.FactionMgr.Callbacks;
import jesse.keeblarcraft.FactionMgr.FactionTier.FactionTierEnum;
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, power, factionTier) -> {
for (PlayerInBaseCallback listener : listeners) {
ActionResult result = listener.interact(player, world, power, factionTier);
if (result != ActionResult.PASS) {
return result;
}
}
return ActionResult.PASS;
});
ActionResult interact(PlayerEntity player, World world, Integer factionPower, FactionTierEnum factionTier);
}

View File

@ -0,0 +1,552 @@
/*
*
* FactionConfig
*
* This class is the configuration file for factions
*
*/
package jesse.keeblarcraft.FactionMgr;
import static java.util.Map.entry;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.HashMap;
// This class is written to a config file typically and represents
// all the details surrounding a faction
public class FactionConfig {
// Key = Faction identifier
// Val = Faction object
HashMap<String, WriteableFaction> allFactions = new HashMap<String, WriteableFaction>();
// Enum may be extended in future
public static enum VALID_FACTION_ROLES {
OWNER,
COOWNER,
MANAGEMENT,
EMPLOYEE
}
private static Map<VALID_FACTION_ROLES, Integer> ROLE_LEVELS = Map.ofEntries
(
entry (VALID_FACTION_ROLES.EMPLOYEE, 0),
entry (VALID_FACTION_ROLES.MANAGEMENT, 1),
entry (VALID_FACTION_ROLES.COOWNER, 2),
entry (VALID_FACTION_ROLES.OWNER, 3)
);
// The below map is 100x easier to just have statically typed here and maintained manually than expensively getting value by key (I am also lazy)
private static Map<Integer, VALID_FACTION_ROLES> ROLES_BY_LEVEL = Map.ofEntries
(
entry (0, VALID_FACTION_ROLES.EMPLOYEE),
entry (1, VALID_FACTION_ROLES.MANAGEMENT),
entry (2, VALID_FACTION_ROLES.COOWNER),
entry (3, VALID_FACTION_ROLES.OWNER)
);
public class WriteableFaction {
// Key = Player UUID
// Val = Faction role of player
HashMap<String, VALID_FACTION_ROLES> factionPlayerList = new HashMap<String, VALID_FACTION_ROLES>();
// Key = Player DISPLAY name
// Val = Faction role of player
HashMap<String, VALID_FACTION_ROLES> DISPLAY_ONLY_LIST = new HashMap<String, VALID_FACTION_ROLES>();
// List contains UUID of players who are openly invited to this faction
// TODO: Refactor to map so players can un-invite by name not UUID...
List<String> openInvites = new ArrayList<String>();
Integer factionBankBalance;
Integer factionPower;
String factionName;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn CreateFaction
///
/// @param[in] factionName is the name of the faction
///
/// @param[in] creatorUuid is the caller of the command's UUID
///
/// @param[in] creatorDisplayName is the caller's display name
///
/// @brief Creates a faction on the server
///
/// @return True if a faction can be created, false if not
/////////////////////////////////////////////////////////////////////////////
public Boolean CreateFaction(String factionName, String creatorUuid, String creatorDisplayName) {
Boolean success = false;
if (!IsValid(factionName)) {
WriteableFaction newFaction = new WriteableFaction();
newFaction.factionPlayerList.put(creatorUuid, VALID_FACTION_ROLES.OWNER);
newFaction.DISPLAY_ONLY_LIST.put(creatorDisplayName, VALID_FACTION_ROLES.OWNER);
newFaction.factionBankBalance = 0;
newFaction.factionPower = 1;
allFactions.put(factionName, newFaction);
success = true;
}
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;
}
public Integer GetBankBalance(String factionName) {
Integer amount = 0;
if (IsValid(factionName)) {
amount = allFactions.get(factionName).factionBankBalance;
}
return amount;
}
// You should probably verify the player is in the faction before calling this so the object is not empty
public HashMap<String, VALID_FACTION_ROLES> GetMemberNames(String factionName) {
HashMap<String, VALID_FACTION_ROLES> members = new HashMap<String, VALID_FACTION_ROLES>();
if (IsValid(factionName)) {
members = allFactions.get(factionName).DISPLAY_ONLY_LIST;
}
return members;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn DeleteFaction
///
/// @param[in] factionName is the name of the faction
///
/// @param[in] creatorUuid is the caller of the command's UUID
///
/// @brief Deletes a faction on the server
///
/// @return True if a faction can be deleted, false if not
/////////////////////////////////////////////////////////////////////////////
public Boolean DeleteFaction(String factionName, String callerUuid) {
Boolean success = false;
// faction must exist
if (IsValid(factionName)) {
// faction must contain player
if (allFactions.get(factionName).factionPlayerList.containsKey(callerUuid)) {
// player must be owner of faction
if (allFactions.get(factionName).factionPlayerList.get(callerUuid) == VALID_FACTION_ROLES.OWNER) {
//TODO: BankManager will connect with this in future and the money of the faction must go somewhere!
allFactions.remove(factionName);
success = true;
}
}
}
return success;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn CanInvite
///
/// @param[in] factionName is the name of the faction
///
/// @param[in] creatorUuid is the caller of the command's UUID
///
/// @brief Determines if the player is capable of inviting another player
/// to the faction
///
/// @return True if player can invite another player, false if not
/////////////////////////////////////////////////////////////////////////////
private Boolean CanInvite(String factionName, String callerUuid) {
Boolean success = false;
if (IsValid(factionName)) {
if (allFactions.get(factionName).factionPlayerList.containsKey(callerUuid)) {
VALID_FACTION_ROLES callerRole = allFactions.get(factionName).factionPlayerList.get(callerUuid);
if (callerRole == VALID_FACTION_ROLES.MANAGEMENT || callerRole == VALID_FACTION_ROLES.COOWNER || callerRole == VALID_FACTION_ROLES.OWNER) {
success = true;
}
}
}
return success;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn IsOnInviteList
///
/// @param[in] factionName is the name of the faction
///
/// @param[in] playerUuid is the caller of the command's UUID
///
/// @brief Checks to see if a player has been invited to a faction
///
/// @return True if player is on invite list, false if not
/////////////////////////////////////////////////////////////////////////////
private Boolean IsOnInviteList(String factionName, String playerUuid) {
Boolean success = false;
if (IsValid(factionName)) {
if (allFactions.get(factionName).openInvites.contains(playerUuid)) {
success = true;
}
}
return success;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn AddToFaction
///
/// @param[in] factionName is the name of the faction
///
/// @param[in] playerUuid is the caller of the command's UUID
///
/// @param[in] playerDisplayName is the caller's display name
///
/// @brief Adds a player to a faction
/////////////////////////////////////////////////////////////////////////////
private void AddToFaction(String factionName, String playerUuid, String playerDisplayName) {
if (allFactions.containsKey(factionName)) {
allFactions.get(factionName).factionPlayerList.put(playerUuid, VALID_FACTION_ROLES.EMPLOYEE);
allFactions.get(factionName).DISPLAY_ONLY_LIST.put(playerDisplayName, VALID_FACTION_ROLES.EMPLOYEE);
allFactions.get(factionName).openInvites.remove(playerUuid); // Remove them from the invite list if they joined
}
}
/////////////////////////////////////////////////////////////////////////////
/// @fn InvitePlayerToFaction
///
/// @param[in] factionName is the name of the faction
///
/// @param[in] callerUuid is the player inviting another player's UUID
///
/// @param[in] invitedUuid is the player being invited's UUID
///
/// @brief Invites a player to a faction
///
/// @return True if player successfully can invite another player
/////////////////////////////////////////////////////////////////////////////
public Boolean InvitePlayerToFaction(String factionName, String callerUuid, String invitedUuid) {
Boolean success = false;
if (CanInvite(factionName, callerUuid)) {
allFactions.get(factionName).openInvites.add(invitedUuid);
success = true;
}
return success;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn JoinFaction
///
/// @param[in] factionName is the name of the faction
///
/// @param[in] playerUuid is the player inviting another player's UUID
///
/// @param[in] playerDisplayName is the player being invited's UUID
///
/// @brief Function to determine if a player can join a faction
///
/// @return True if they join, false if they cannot
/////////////////////////////////////////////////////////////////////////////
public Boolean JoinFaction(String factionName, String playerUuid, String playerDisplayName) {
Boolean success = false;
if (IsOnInviteList(factionName, playerUuid) ) {
AddToFaction(factionName, playerUuid, playerDisplayName);
success = true;
}
return success;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn LeaveFaction
///
/// @param[in] factionName is the name of the faction
///
/// @param[in] playerUuid is the player inviting another player's UUID
///
/// @param[in] playerName is the player being invited's UUID
///
/// @brief Function to let player leave a faction
///
/// @return True if they leave, false if they did not
/////////////////////////////////////////////////////////////////////////////
public Boolean LeaveFaction(String factionName, String playerUuid, String playerName) {
Boolean success = false;
if (IsValid(factionName)) {
allFactions.get(factionName).factionPlayerList.remove(playerUuid);
allFactions.get(factionName).DISPLAY_ONLY_LIST.remove(playerName);
// TODO: In future add ability if owner leave then promote next person
// Delete faction if all the players are gone
if (allFactions.get(factionName).factionPlayerList.size() == 0) {
allFactions.remove(factionName);
}
success = true;
}
return success;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn HasPlayer
///
/// @param[in] factionName is the name of the faction
///
/// @param[in] playerUuid is the player inviting another player's UUID
///
/// @brief Determines if a faction has a specific player by UUID
///
/// @return True if they have the player, false if not
/////////////////////////////////////////////////////////////////////////////
private Boolean HasPlayer(String factionName, String playerUuid) {
Boolean success = false;
if (IsValid(factionName)) {
success = allFactions.get(factionName).factionPlayerList.containsKey(playerUuid);
}
return success;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn IsValid
///
/// @param[in] factionName is the name of the faction
///
/// @brief Determines if a faction exists
///
/// @return True if a faction exists with the specified name, false if not
/////////////////////////////////////////////////////////////////////////////
public Boolean IsValid(String factionName) {
if (allFactions.containsKey(factionName)) {
return true;
} else {
return false;
}
}
/////////////////////////////////////////////////////////////////////////////
/// @fn FindFactionOfPlayer
///
/// @param[in] playerUuid is the uuid of the player to find
///
/// @brief Determine the faction of a specified player
///
/// @return Returns the faction name of the player if the player is in
/// any faction. If the player is not found in any faction, an
/// empty string is returned
/////////////////////////////////////////////////////////////////////////////
public String FindFactionOfPlayer(String playerUuid) {
String faction = "";
System.out.println("Attempting to find player factions with uuid " + playerUuid);
for (Entry<String, WriteableFaction> entry : allFactions.entrySet()) {
if (entry.getValue().factionPlayerList.containsKey(playerUuid)) {
System.out.println("FAC [" + entry.getKey() + "]: PLAY-LIST: " + entry.getValue().factionPlayerList);
faction = entry.getKey();
break;
}
}
return faction;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn PromotePlayer
///
/// @param[in] factionName is the name of the faction
///
/// @param[in] callerUuid is the caller of the command's UUID
///
/// @param[in] promoteeUuid is the player to be promoted's UUID
///
/// @param[in] promoteeDisplayName is the player ot be promoted's display name
///
/// @brief Attempts to promote a player in a faction. Whether or not a
/// player is promoted is determined by their level in the faction
/// and the promoter's level in the faction. Factors that can affect
/// this are:
/// 1. Both the caller and promotee must exist inside
/// the same faction
/// 2. The promoter must be a higher rank than the promotee
/// 3. The promotee's post-promotion rank still must be below
/// the promoter's rank
///
/// @return True if the player was successfully promoted, false if not
/////////////////////////////////////////////////////////////////////////////
public Boolean PromotePlayer(String factionName, String callerUuid, String promoteeUuid, String promoteeDisplayName) {
Boolean success = false;
if (CanInvite(factionName, callerUuid) && HasPlayer(factionName, promoteeUuid)) {
VALID_FACTION_ROLES callerRole = allFactions.get(factionName).factionPlayerList.get(callerUuid);
VALID_FACTION_ROLES promoteeRole = allFactions.get(factionName).factionPlayerList.get(promoteeUuid);
Integer callerRoleLevel = ROLE_LEVELS.get(callerRole);
Integer promoteeRoleLevel = ROLE_LEVELS.get(promoteeRole);
// Factions is setup so that anyone can promote anybody UNDERNEATH them. However, you CANNOT promote a player to your level!
if (callerRoleLevel > promoteeRoleLevel + 1) {
// Get the new employee role
promoteeRole = ROLES_BY_LEVEL.get(promoteeRoleLevel + 1);
// Update role in faction
allFactions.get(factionName).factionPlayerList.put(promoteeUuid, promoteeRole);
allFactions.get(factionName).DISPLAY_ONLY_LIST.put(promoteeDisplayName, promoteeRole);
success = true;
}
}
return success;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn CanKickPlayer
///
/// @param[in] factionName is the name of the faction
///
/// @param[in] callerUuid is the caller of the command's UUID
///
/// @param[in] kickeeUuid is the player to be kickee's UUID
///
/// @param[in] kickeeDisplayName is the player ot be kickeeDisplayName's
/// display name
///
/// @brief Determines whether or not a player can be kicked. The caller
/// must be a higher rank to kick a player (and they both must
/// exist inside the faction)
///
/// @return True if the player was successfully kicked, false if not
/////////////////////////////////////////////////////////////////////////////
public Boolean CanKickPlayer(String factionName, String callerUuid, String kickeeUuid, String kickeeDisplayName) {
Boolean success = false;
if (IsValid(factionName) && HasPlayer(factionName, kickeeUuid)) {
VALID_FACTION_ROLES callerRole = allFactions.get(factionName).factionPlayerList.get(callerUuid);
VALID_FACTION_ROLES kickeeRole = allFactions.get(factionName).factionPlayerList.get(kickeeUuid);
Integer callerRoleLevel = ROLE_LEVELS.get(callerRole);
Integer kickeeRoleLevel = ROLE_LEVELS.get(kickeeRole);
if (callerRoleLevel > kickeeRoleLevel) {
success = true;
}
}
return success;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn KickPlayer
///
/// @param[in] factionName is the name of the faction
///
/// @param[in] callerUuid is the caller of the command's UUID
///
/// @param[in] kickeeUuid is the player to be kickee's UUID
///
/// @param[in] kickeeDisplayName is the player ot be kickeeDisplayName's
/// display name
///
/// @brief Kicks a player from a faction
///
/// @return True if the player was successfully kicked, false if not
/////////////////////////////////////////////////////////////////////////////
private Boolean KickPlayer(String factionName, String callerUuid, String kickeeUuid, String kickeeDisplayName) {
Boolean success = false;
if (CanKickPlayer(factionName, callerUuid, kickeeUuid, kickeeDisplayName)) {
allFactions.get(factionName).factionPlayerList.remove(kickeeUuid);
allFactions.get(factionName).DISPLAY_ONLY_LIST.remove(kickeeDisplayName);
success = true;
}
return success;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn DemotePlayer
///
/// @param[in] factionName is the name of the faction
///
/// @param[in] callerUuid is the caller of the command's UUID
///
/// @param[in] demoteeUuid is the player to be promoted's UUID
///
/// @param[in] demoteeDisplayName is the player ot be promoted's display name
///
/// @brief Attempts to demote a player in a faction. Whether or not a
/// player is demoted is determined by their level in the faction
/// and the demoter's level in the faction. Factors that can affect
/// this are:
/// 1. Both the caller and demotee must exist inside
/// the same faction
/// 2. The demoter must be a higher rank than the promotee
/// 3. Should there be no lower rank left to demote to, the
/// player is kicked from the faction
///
/// @return True if the player was successfully demoted, false if not
/////////////////////////////////////////////////////////////////////////////
public Boolean DemotePlayer(String factionName, String callerUuid, String demoteeUuid, String demoteeDisplayName) {
Boolean success = false;
if (CanInvite(factionName, callerUuid) && HasPlayer(factionName, demoteeUuid)) {
VALID_FACTION_ROLES callerRole = allFactions.get(factionName).factionPlayerList.get(callerUuid);
VALID_FACTION_ROLES demoteeRole = allFactions.get(factionName).factionPlayerList.get(demoteeUuid);
Integer callerRoleLevel = ROLE_LEVELS.get(callerRole);
Integer demoteeRoleLevel = ROLE_LEVELS.get(demoteeRole);
// Factions is setup so that anyone can demote anybody underneath them & the lowest level will cause a demotion to be a KICK from faction
if (callerRoleLevel > demoteeRoleLevel) {
// If the role level would be lower than bottom level, KICK player
if (demoteeRoleLevel - 1 < ROLE_LEVELS.get(VALID_FACTION_ROLES.EMPLOYEE)) {
success = KickPlayer(factionName, callerUuid, demoteeUuid, demoteeDisplayName);
} else {
// Regular demotion!
demoteeRole = ROLES_BY_LEVEL.get(demoteeRoleLevel - 1);
// Update faction
allFactions.get(factionName).factionPlayerList.put(demoteeUuid, demoteeRole);
allFactions.get(factionName).DISPLAY_ONLY_LIST.put(demoteeDisplayName, demoteeRole);
success = true;
}
}
}
return success;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn ListOfAllFactions
///
/// @brief Get a list of all factions on the server
///
/// @return List of factions
/////////////////////////////////////////////////////////////////////////////
public List<String> ListOfAllFactions() {
List<String> facs = new ArrayList<String>();
System.out.println("ListOfFactions - map size: " + allFactions.size());
for (Entry<String, WriteableFaction> entry : allFactions.entrySet()) {
facs.add(entry.getKey());
}
return facs;
}
}

View File

@ -0,0 +1,347 @@
/*
*
* FactionManager
*
* Class is responsible for keeping track of factions chosen by the players in the game and saves to the configuration
* file for persistent data storage. Class handles checks as well for eligibility purposes (making sure players can join, etc)
*
*/
package jesse.keeblarcraft.FactionMgr;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import jesse.keeblarcraft.ConfigMgr.ConfigManager;
import jesse.keeblarcraft.FactionMgr.FactionConfig.VALID_FACTION_ROLES;
import jesse.keeblarcraft.FactionMgr.FactionTier.FactionTierEnum;
import jesse.keeblarcraft.MailSystem.MailMgr;
import jesse.keeblarcraft.Keeblarcraft;
import jesse.keeblarcraft.ChatStuff.ChatMenu;
import jesse.keeblarcraft.ChatStuff.ChatMsg;
import jesse.keeblarcraft.ChatStuff.ChatFormatting.COLOR_CODE;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
public class FactionManager {
private static String FACTION_CFG_FILE = "factions/factions.json";
ConfigManager config = new ConfigManager();
private static FactionManager static_inst;
public static FactionManager GetInstance() {
if (static_inst == null) {
static_inst = new FactionManager();
}
return static_inst;
}
private class FactionConfigClassWrapper {
FactionConfig factions = new FactionConfig();
}
FactionConfigClassWrapper factionConfig;// = new FactionConfigClassWrapper();
// Constructor
public FactionManager() {
// Read in config at start of object
System.out.println("FACTIONMANAGER CONSTRUCTOR CALLED");
Boolean existingFile = false;
factionConfig = new FactionConfigClassWrapper();
Boolean tmpchck = factionConfig == null;
System.out.println("Is factionConfig null still? " + (tmpchck ? "YES" : "NO"));
try {
factionConfig = config.GetJsonObjectFromFile(FACTION_CFG_FILE, FactionConfigClassWrapper.class);
tmpchck = factionConfig == null;
System.out.println("Is factionconfig null after trying to load stuff? " + (tmpchck ? "YES" : "NO"));
existingFile = true;
} catch (Exception e) {
// Do nothing
}
// Create the file if it didn't exist before
if (!existingFile)
{
try {
config.CreateDirectory(FACTION_CFG_FILE);
FlashConfig();
} catch (Exception e) {
Keeblarcraft.LOGGER.error("Could not write to file");
}
}
if (factionConfig == null) {
// the only way for this to be possible is if the read-in was bad. flash config file then try again
factionConfig = new FactionConfigClassWrapper();
//TODO: Add safe-guard in here to check if default faction dir exists and move it to OLD/CORRUPTED (so data is not nuked from orbit)
factionConfig.factions = new FactionConfig();
FlashConfig();
}
FactionTier.InitializeFactionTiers();
}
public void GetFactionInformation(ServerPlayerEntity player) {
String factionName = GetFactionOfPlayer(player.getUuidAsString());
if (!factionName.equals("")) {
Integer fPower = factionConfig.factions.GetPower(factionName);
HashMap<String, VALID_FACTION_ROLES> displayNames = factionConfig.factions.GetMemberNames(factionName);
Integer fBankBalance = factionConfig.factions.GetBankBalance(factionName);
System.out.println((fPower == null ? "YES":"NO") + " " + (displayNames == null ? "YES":"NO") + " " + (fBankBalance == null ? "YES":"NO"));
ArrayList<String> nameMapToList = new ArrayList<String>();
ChatMsg chatPlayerList = new ChatMsg();
for (Entry<String, VALID_FACTION_ROLES> entry : displayNames.entrySet()) {
nameMapToList.add(chatPlayerList.ColorMsg(entry.getKey() + " - " + entry.getValue().name(), COLOR_CODE.BLUE));
}
System.out.println("name map null? " + nameMapToList == null ? "YES":"NO");
// Let's make our chat objects first so things are copyable and whatnot
ChatMsg chatHeader = new ChatMsg();
chatHeader.ColorMsg(Text.of(factionName), COLOR_CODE.GOLD);
ChatMsg chatBalance = new ChatMsg();
chatBalance.ColorMsg(Text.of(Integer.toString(fBankBalance)), COLOR_CODE.GREEN);
ChatMsg chatPower = new ChatMsg();
chatPower.ColorMsg(Text.of(Integer.toString(fPower)), COLOR_CODE.RED);
ChatMenu chatBlock = new ChatMenu();
chatBlock.SetHeader(chatHeader);
chatBlock.AddMsg(chatPlayerList);
chatBlock.AddMsg(chatBalance);
chatBlock.AddMsg(chatPower);
chatBlock.SendMsg(player);
} else {
player.sendMessage(Text.of("You aren't in a faction!"));
}
}
/////////////////////////////////////////////////////////////////////////////
/// @fn LeaveFaction
///
/// @param[in] player is the player on the server
///
/// @brief Leave a faction
///
/// @return True if player can leave their faction, false if not
/////////////////////////////////////////////////////////////////////////////
public Boolean LeaveFaction(ServerPlayerEntity player) {
Boolean success = false;
String playerFac = factionConfig.factions.FindFactionOfPlayer(player.getUuidAsString());
if (playerFac != "") {
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!"));
}
return success;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn CreateFaction
///
/// @param[in] factionName is the faction to be created
///
/// @param[in] player is the player on the server
///
/// @brief Create a new faction
///
/// @return True if successfully created, false if not
/////////////////////////////////////////////////////////////////////////////
public Boolean CreateFaction(String factionName, ServerPlayerEntity creator) {
Boolean success = false;
String facOfPlayer = factionConfig.factions.FindFactionOfPlayer(creator.getUuidAsString());
if (facOfPlayer == "") {
// 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."));
} else {
creator.sendMessage(Text.of("[Factions]: Successfully created faction!"));
FlashConfig();
}
} else {
creator.sendMessage(Text.of("[Factions]: You are already in a faction! You cannot create one."));
}
return success;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn DeleteFaction
///
/// @param[in] factionName is the faction to be created
///
/// @param[in] caller is the player on the server
///
/// @brief Delete a faction
///
/// @return True if successfully deleted, false if not
/////////////////////////////////////////////////////////////////////////////
public Boolean DeleteFaction(String factionName, ServerPlayerEntity caller) {
Boolean success = factionConfig.factions.DeleteFaction(factionName, caller.getUuidAsString());
if (!success) {
caller.sendMessage(Text.of("[Factions]: Could not delete faction. You must be owner & faction must exist."));
} else {
caller.sendMessage(Text.of("[Factions]: Successfully deleted faction."));
FlashConfig();
}
return success;
}
public Boolean JoinFaction(ServerPlayerEntity player, String factionName) {
Boolean joinedFaction = factionConfig.factions.JoinFaction(factionName, player.getUuidAsString(), player.getEntityName());
if (joinedFaction) {
player.sendMessage(Text.of("Successfully joined the faction " + factionName));
} else {
player.sendMessage(Text.of("Failed to join faction - you were not on the invite list!"));
}
return joinedFaction;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn ListOfFactions
///
/// @brief Get a list of all factions on the server
///
/// @return Faction list. Empty list if no factions
/////////////////////////////////////////////////////////////////////////////
public List<String> ListOfFactions() {
System.out.println("Callthrough of listoffactions");
return factionConfig.factions.ListOfAllFactions();
}
/////////////////////////////////////////////////////////////////////////////
/// @fn GetFactionOfPlayer
///
/// @param[in] playerUuid is the uuid of the player
///
/// @brief Gets the faction of a player on the server
///
/// @return String with faction name. Empty string if no faction tie
/////////////////////////////////////////////////////////////////////////////
public String GetFactionOfPlayer(String playerUuid) {
return factionConfig.factions.FindFactionOfPlayer(playerUuid);
}
public Boolean InvitePlayerToFaction(ServerPlayerEntity caller, String inviteeUuid, String inviteeDisplayName) {
String playerFaction = factionConfig.factions.FindFactionOfPlayer(caller.getUuidAsString());
Boolean success = false;
if (!playerFaction.equals("")) {
success = factionConfig.factions.InvitePlayerToFaction(playerFaction, caller.getUuidAsString(), inviteeUuid);
} else {
caller.sendMessage(Text.of("You aren't in a faction!"));
}
if (success) {
String mailMsg = "You received a faction invite from " + caller.getEntityName() + "! You can join with /faction join " + playerFaction;
MailMgr.GetInstance().SendMail(inviteeUuid, mailMsg);
FlashConfig();
}
return success;
}
public Boolean SetFactionPower(ServerPlayerEntity caller, String factionName, Integer amount) {
Boolean success = false;
if (caller.hasPermissionLevel(4)) {
success = factionConfig.factions.SetPower(factionName, amount);
FlashConfig();
} else {
caller.sendMessage(Text.of("You do not have permission to use this command"));
}
return success;
}
public Integer GetFactionPower(String factionName) {
int fPower = 0;
if (factionConfig.factions.IsValid(factionName)) {
fPower = factionConfig.factions.GetPower(factionName);
}
return fPower;
}
public FactionTierEnum GetFactionTier(String factionName) {
return FactionTier.GetFactionTier(factionConfig.factions.GetPower(factionName));
}
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);
if (!success) {
caller.sendMessage(Text.of("[Factions]: Could not promote player - you need to be a higher rank than them and they cannot be promoted to your level!"));
} else {
caller.sendMessage(Text.of("[Factions]: Successfully promoted player!"));
}
return success;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn DemotePlayer
///
/// @param[in] caller is the player who is demoting another player
///
/// @param[in] demoteeUuid is the player's uuid who is being demoted
///
/// @param[in] demoteeDisplayName is the players display name who is being demoted
///
/// @brief Demote a player from a faction
///
/// @return True if player is demoted. False if not
/////////////////////////////////////////////////////////////////////////////
public Boolean DemotePlayer(ServerPlayerEntity caller, String demoteeUuid, String demoteeDisplayName) {
Boolean success = factionConfig.factions.DemotePlayer(GetFactionOfPlayer(caller.getUuidAsString()), caller.getUuidAsString(), demoteeUuid, demoteeDisplayName);
if (!success) {
caller.sendMessage(Text.of("[Factions]: Could not demote player - you need to be a higher rank than them to demote them!"));
} else {
caller.sendMessage(Text.of("[Factions]: Successfully demoted player!"));
}
return success;
}
/////////////////////////////////////////////////////////////////////////////
/// @fn FlashConfig
///
/// @brief Update the faction configuration file on disk
/////////////////////////////////////////////////////////////////////////////
public void FlashConfig() {
config.WriteToJsonFile(FACTION_CFG_FILE, factionConfig);
}
}

View File

@ -0,0 +1,65 @@
package jesse.keeblarcraft.FactionMgr;
import com.google.common.collect.Range;
import com.google.common.collect.RangeMap;
import com.google.common.collect.TreeRangeMap;
public class FactionTier {
public static enum FactionTierEnum {
TIER_INVALID,
TIER_I,
TIER_II,
TIER_III,
TIER_IV,
TIER_V,
TIER_VI
}
private static RangeMap<Integer, FactionTierEnum> factionTiers = TreeRangeMap.create();
public static void InitializeFactionTiers() {
factionTiers.put(Range.closed(0, 29), FactionTierEnum.TIER_I);
factionTiers.put(Range.closed(30, 74), FactionTierEnum.TIER_II);
factionTiers.put(Range.closed(75, 99), FactionTierEnum.TIER_III);
factionTiers.put(Range.closed(100, 149), FactionTierEnum.TIER_IV);
factionTiers.put(Range.closed(150, 999), FactionTierEnum.TIER_V);
factionTiers.put(Range.closed(1000, Integer.MAX_VALUE), FactionTierEnum.TIER_VI);
}
// Tier 1 can never be greater than anything (and not itself, obviously)
public static Boolean IsGreaterThan(FactionTierEnum tierInQuestion, FactionTierEnum tierToCompareAgainst) {
Boolean isGreater = false;
if (tierInQuestion == FactionTierEnum.TIER_II && tierToCompareAgainst == FactionTierEnum.TIER_I) {
isGreater = true;
} else if (tierInQuestion == FactionTierEnum.TIER_III && (tierToCompareAgainst == FactionTierEnum.TIER_II || tierToCompareAgainst == FactionTierEnum.TIER_I)) {
isGreater = true;
} else if (tierInQuestion == FactionTierEnum.TIER_IV && (tierToCompareAgainst == FactionTierEnum.TIER_III || tierToCompareAgainst == FactionTierEnum.TIER_II || tierToCompareAgainst == FactionTierEnum.TIER_I)) {
isGreater = true;
} else if (tierInQuestion == FactionTierEnum.TIER_V && (tierToCompareAgainst == FactionTierEnum.TIER_IV || tierToCompareAgainst == FactionTierEnum.TIER_III || tierToCompareAgainst == FactionTierEnum.TIER_II || tierToCompareAgainst == FactionTierEnum.TIER_I)) {
isGreater = true;
} else if (tierInQuestion == FactionTierEnum.TIER_VI && (tierToCompareAgainst == FactionTierEnum.TIER_V || tierToCompareAgainst == FactionTierEnum.TIER_IV || tierToCompareAgainst == FactionTierEnum.TIER_III || tierToCompareAgainst == FactionTierEnum.TIER_II || tierToCompareAgainst == FactionTierEnum.TIER_I)) {
isGreater = true;
}
return isGreater;
}
public static Boolean IsEqualTo(FactionTierEnum tierInQuestion, FactionTierEnum tierToCompareAgainst) {
return tierInQuestion == tierToCompareAgainst;
}
public static Boolean IsGreaterOrEqualTo(FactionTierEnum tierInQuestion, FactionTierEnum tierToCompareAgainst) {
return IsEqualTo(tierInQuestion, tierToCompareAgainst) || IsGreaterThan(tierInQuestion, tierToCompareAgainst);
}
// Make sure you initialize tiers by calling the above function first!
public static FactionTierEnum GetFactionTier(Integer value) {
FactionTierEnum tier = factionTiers.get(value);
if (tier == null) {
tier = FactionTierEnum.TIER_INVALID;
}
return tier;
}
}

View File

@ -1,15 +0,0 @@
/*
*
* TeamManager
*
* Class is responsible for keeping track of teams/factions chosen by the players in the game and saves to the configuration
* file for persistent data storage. Class handles checks as well for eligibility purposes (making sure players can join, etc)
*
*/
package jesse.keeblarcraft.FactionMgr;
public class TeamManager {
// Class controls managing teams and pulling from configuration file and loading to configuration file
}

View File

@ -0,0 +1,113 @@
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, -1, 2)); // top row
this.addSlot(new Slot(inventory, 2, 35, 2));
this.addSlot(new Slot(inventory, 4, 71, 2));
this.addSlot(new Slot(inventory, 1, 17, 36));
this.addSlot(new Slot(inventory, 3, 54, 36));
this.addSlot(new Slot(inventory, 5, 90, 36));
this.addSlot(new Slot(inventory, 6, 148, 20));
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) {
int spacing = -8;
for (int i = 0; i < 3; ++i) { // Rows
for (int l = 0; l < 9; ++l) { // Columns
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 = l * 22 + spacing; // Texture draw position on image
int y = 89 + i * 22; // Texture draw position on image
this.addSlot(new Slot(playerInventory, index, x, y));
}
}
}
// From Kaupenjoe video
private void addPlayerHotbar(PlayerInventory playerInventory) {
int spacing = -8;
for (int i = 0; i < 9; ++i) {
int index = i; // Index of hotbar (only 9 slots long in vanilla)
// int x = (8 + i * 18) + spacing; // Texture draw position
int x = i * 22 + spacing; // Texture draw position
int y = 162; // 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

@ -12,7 +12,14 @@
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.networking.v1.ServerPlayConnectionEvents;
import net.kyrptonaught.customportalapi.api.CustomPortalBuilder;
import net.minecraft.block.Blocks;
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;
@ -23,16 +30,19 @@ 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.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";
@ -44,31 +54,27 @@ public class Keeblarcraft implements ModInitializer {
Identifier.of(Keeblarcraft.MOD_ID, "tree_gui"),
new ScreenHandlerType<>(TreeHandler::new, FeatureSet.empty()));
// public static final Block MAGIC_CHEST_BLOCK = Registry.register(Registries.BLOCK, Identifier.of(Keeblarcraft.MOD_ID, "magic_chest_block"),
// new MagicChestBlock(AbstractBlock.Settings.copy(Blocks.CHEST)));
// public static final BlockEntityType<MagicChestBlockEntity> MAGIC_CHEST_BLOCK_ENTITY = Registry.register(Registry.BLOCK_ENTITY_TYPE,
// Identifier.of(Keeblarcraft.MOD_ID, "magic_chest_block_entity"), BlockEntityType.Builder.create(MagicChestBlockEntity::new, MAGIC_CHEST_BLOCK).build());
CustomCommandManager cmdMgr = new CustomCommandManager();
Setup setup = Setup.GetInstance();
@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...");
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);
});
ServerPlayConnectionEvents.DISCONNECT.register((handler, server) -> {
@ -80,6 +86,27 @@ public class Keeblarcraft implements ModInitializer {
}
});
ServerEntityWorldChangeEvents.AFTER_PLAYER_CHANGE_WORLD.register((player, origin, destination) -> {
System.out.println("Calling back...");
DimensionLoadingEvent.GetInstance().HandleWorldMove(player, origin, destination);
});
ServerLifecycleEvents.SERVER_STOPPING.register((server) -> {
// Stuff here
System.out.println("SERVER_STOPPING callback called.");
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();
@ -90,6 +117,13 @@ public class Keeblarcraft implements ModInitializer {
// Register attributes
AttributeMgr.RegisterAttributes();
// 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
@ -97,15 +131,30 @@ public class Keeblarcraft implements ModInitializer {
// Register blocks
BlockList.RegisterBlocks();
BlockEntityRegistration.RegisterBlockEntities();
// World generation
// Custom portal generator
System.out.println("BUILDING CUSTOM PORTAL");
CustomPortalBuilder.beginPortal()
.frameBlock(Blocks.GOLD_BLOCK)
.lightWithItem(Items.ENDER_EYE)
.destDimID(new Identifier(Keeblarcraft.MOD_ID, "keeblarcraftdim"))
.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,157 +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.MutableText;
import net.minecraft.text.Text;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.util.Map.Entry;
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,20 @@
package jesse.keeblarcraft.Utils;
import net.minecraft.registry.RegistryKey;
import net.minecraft.world.World;
/////////////////////////////////////////////////////////////////////////////
/// @class DirectionalVec
///
/// @brief DirectionalVec creates a vector of information that can store
/// world information and a players vector information of where they
/// are in the world + where their camera is looking (yaw & pitch)
/////////////////////////////////////////////////////////////////////////////
public class DirectionalVec {
public RegistryKey<World> world;
public double x;
public double y;
public double z;
public float yaw;
public float pitch;
}

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:
@ -30,10 +29,9 @@ import jesse.keeblarcraft.Utils.CustomExceptions.SETUP_FAILED_EXCEPTION;
// If we do not have these, or only partial - then functionality may be disabled for runtime performance
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() {
@ -57,6 +55,7 @@ public final class Setup {
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
@ -77,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
@ -132,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.");
}
}
@ -142,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,28 @@
package jesse.keeblarcraft.datagen;
import java.util.concurrent.CompletableFuture;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricDynamicRegistryProvider;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.registry.RegistryWrapper;
import net.minecraft.registry.RegistryWrapper.WrapperLookup;
public class WorldGenerator extends FabricDynamicRegistryProvider {
public WorldGenerator(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFeature) {
super(output, registriesFeature);
}
@Override
public String getName() {
return "Keeblarcraft World Generation";
}
@Override
protected void configure(WrapperLookup registries, Entries entries) {
entries.addAll(registries.getWrapperOrThrow(RegistryKeys.PLACED_FEATURE));
entries.addAll(registries.getWrapperOrThrow(RegistryKeys.BIOME));
entries.addAll(registries.getWrapperOrThrow(RegistryKeys.DIMENSION_TYPE));
}
}

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,26 @@
package jesse.keeblarcraft.world;
import jesse.keeblarcraft.datagen.WorldGenerator;
import jesse.keeblarcraft.world.biome.ModBiomes;
import jesse.keeblarcraft.world.dimension.ModDimensions;
import net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint;
import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator;
import net.minecraft.registry.RegistryBuilder;
import net.minecraft.registry.RegistryKeys;
public class DataGeneration implements DataGeneratorEntrypoint {
@Override
public void onInitializeDataGenerator(FabricDataGenerator fabricDataGenerator) {
FabricDataGenerator.Pack pack = fabricDataGenerator.createPack();
pack.addProvider(WorldGenerator::new);
}
@Override
public void buildRegistry(RegistryBuilder registryBuilder) {
registryBuilder.addRegistry(RegistryKeys.BIOME, ModBiomes::bootstrap);
registryBuilder.addRegistry(RegistryKeys.DIMENSION_TYPE, ModDimensions::bootstrapType);
}
}

View File

@ -0,0 +1,140 @@
package jesse.keeblarcraft.world;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.Inventories;
import net.minecraft.inventory.Inventory;
import net.minecraft.item.ItemStack;
import net.minecraft.util.collection.DefaultedList;
/**
* A simple {@code Inventory} implementation with only default methods + an item
* list getter.
*
* @author Juuz
*
* @from https://wiki.fabricmc.net/tutorial:inventory
*/
public interface ImplementedInventory extends Inventory {
/**
* Retrieves the item list of this inventory.
* Must return the same instance every time it's called.
*/
DefaultedList<ItemStack> getItems();
/**
* Creates an inventory from the item list.
*/
static ImplementedInventory of(DefaultedList<ItemStack> items) {
return () -> items;
}
/**
* Creates a new inventory with the specified size.
*/
static ImplementedInventory ofSize(int size) {
return of(DefaultedList.ofSize(size, ItemStack.EMPTY));
}
/**
* Returns the inventory size.
*/
@Override
default int size() {
return getItems().size();
}
/**
* Checks if the inventory is empty.
*
* @return true if this inventory has only empty stacks, false otherwise.
*/
@Override
default boolean isEmpty() {
for (int i = 0; i < size(); i++) {
ItemStack stack = getStack(i);
if (!stack.isEmpty()) {
return false;
}
}
return true;
}
/**
* Retrieves the item in the slot.
*/
@Override
default ItemStack getStack(int slot) {
return getItems().get(slot);
}
/**
* Removes items from an inventory slot.
*
* @param slot The slot to remove from.
* @param count How many items to remove. If there are less items in the slot
* than what are requested,
* takes all items in that slot.
*/
@Override
default ItemStack removeStack(int slot, int count) {
ItemStack result = Inventories.splitStack(getItems(), slot, count);
if (!result.isEmpty()) {
markDirty();
}
return result;
}
/**
* Removes all items from an inventory slot.
*
* @param slot The slot to remove from.
*/
@Override
default ItemStack removeStack(int slot) {
return Inventories.removeStack(getItems(), slot);
}
/**
* Replaces the current stack in an inventory slot with the provided stack.
*
* @param slot The inventory slot of which to replace the itemstack.
* @param stack The replacing itemstack. If the stack is too big for
* this inventory ({@link Inventory#getMaxCountPerStack()}),
* it gets resized to this inventory's maximum amount.
*/
@Override
default void setStack(int slot, ItemStack stack) {
getItems().set(slot, stack);
if (stack.getCount() > stack.getMaxCount()) {
stack.setCount(stack.getMaxCount());
}
}
/**
* Clears the inventory.
*/
@Override
default void clear() {
getItems().clear();
}
/**
* Marks the state as dirty.
* Must be called after changes in the inventory, so that the game can properly
* save
* the inventory contents and notify neighboring blocks of inventory changes.
*/
@Override
default void markDirty() {
// Override if you want behavior.
}
/**
* @return true if the player can use the inventory, false otherwise.
*/
@Override
default boolean canPlayerUse(PlayerEntity player) {
return true;
}
}

View File

@ -0,0 +1,68 @@
package jesse.keeblarcraft.world.biome;
import jesse.keeblarcraft.Keeblarcraft;
import net.minecraft.registry.Registerable;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.util.Identifier;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.BiomeEffects;
import net.minecraft.world.biome.GenerationSettings;
import net.minecraft.world.biome.SpawnSettings;
import net.minecraft.world.gen.GenerationStep;
import net.minecraft.world.gen.feature.DefaultBiomeFeatures;
import net.minecraft.world.gen.feature.VegetationPlacedFeatures;
public class ModBiomes {
public static final RegistryKey<Biome> TEST_BIOME = RegistryKey.of(RegistryKeys.BIOME,
new Identifier(Keeblarcraft.MOD_ID, "test_biome"));
public static void bootstrap(Registerable<Biome> context) {
context.register(TEST_BIOME, testBiome(context));
}
public static void globalOverworldGeneration(GenerationSettings.LookupBackedBuilder builder) {
DefaultBiomeFeatures.addLandCarvers(builder);
DefaultBiomeFeatures.addAmethystGeodes(builder);
// DefaultBiomeFeatures.addDungeons(builder);
DefaultBiomeFeatures.addMineables(builder);
DefaultBiomeFeatures.addSprings(builder);
DefaultBiomeFeatures.addFrozenTopLayer(builder);
}
public static Biome testBiome(Registerable<Biome> context) {
SpawnSettings.Builder spawnBuilder = new SpawnSettings.Builder();
DefaultBiomeFeatures.addFarmAnimals(spawnBuilder);
// DefaultBiomeFeatures.addBatsAndMonsters(spawnBuilder);
GenerationSettings.LookupBackedBuilder biomeBuilder =
new GenerationSettings.LookupBackedBuilder(context.getRegistryLookup(RegistryKeys.PLACED_FEATURE),
context.getRegistryLookup(RegistryKeys.CONFIGURED_CARVER));
globalOverworldGeneration(biomeBuilder);
DefaultBiomeFeatures.addMossyRocks(biomeBuilder);
biomeBuilder.feature(GenerationStep.Feature.VEGETAL_DECORATION, VegetationPlacedFeatures.TREES_PLAINS);
DefaultBiomeFeatures.addForestFlowers(biomeBuilder);
DefaultBiomeFeatures.addLargeFerns(biomeBuilder);
DefaultBiomeFeatures.addDefaultMushrooms(biomeBuilder);
DefaultBiomeFeatures.addDefaultVegetation(biomeBuilder);
return new Biome.Builder()
.precipitation(true)
.downfall(0.6f)
.temperature(0.7f)
.generationSettings(biomeBuilder.build())
.spawnSettings(spawnBuilder.build())
.effects((new BiomeEffects.Builder())
.waterColor(0xeb34a4)
.waterFogColor(0x1b78bf)
.skyColor(0xb41bbf)
.grassColor(0x1bbfb4)
.foliageColor(0xd203fc)
.fogColor(0x1b78bf).build())
.build();
}
}

View File

@ -0,0 +1,27 @@
package jesse.keeblarcraft.world.biome;
import com.mojang.datafixers.util.Pair;
import net.minecraft.registry.Registry;
import net.minecraft.registry.RegistryKey;
import net.minecraft.util.Identifier;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.BiomeKeys;
import net.minecraft.world.biome.source.util.MultiNoiseUtil;
import terrablender.api.Region;
import terrablender.api.RegionType;
import java.util.function.Consumer;
public class ModOverworldRegion extends Region {
public ModOverworldRegion(Identifier name, int weight) {
super(name, RegionType.OVERWORLD, weight);
}
@Override
public void addBiomes(Registry<Biome> registry, Consumer<Pair<MultiNoiseUtil.NoiseHypercube,
RegistryKey<Biome>>> mapper) {
// this.addModifiedVanillaOverworldBiomes(mapper, modifiedVanillaOverworldBuilder -> {
// modifiedVanillaOverworldBuilder.replaceBiome(BiomeKeys.FOREST, ModBiomes.TEST_BIOME);
// });
}
}

View File

@ -0,0 +1,17 @@
package jesse.keeblarcraft.world.biome;
import jesse.keeblarcraft.Keeblarcraft;
import jesse.keeblarcraft.world.biome.surface.ModMaterialRules;
import net.minecraft.util.Identifier;
import terrablender.api.Regions;
import terrablender.api.SurfaceRuleManager;
import terrablender.api.TerraBlenderApi;
public class ModTerrablenderAPI implements TerraBlenderApi {
@Override
public void onTerraBlenderInitialized() {
Regions.register(new ModOverworldRegion(new Identifier(Keeblarcraft.MOD_ID, "overworld"), 4));
SurfaceRuleManager.addSurfaceRules(SurfaceRuleManager.RuleCategory.OVERWORLD, Keeblarcraft.MOD_ID, ModMaterialRules.makeRules());
}
}

View File

@ -0,0 +1,33 @@
package jesse.keeblarcraft.world.biome.surface;
import jesse.keeblarcraft.world.biome.ModBiomes;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.world.gen.surfacebuilder.MaterialRules;
// for landscaping and stuff
public class ModMaterialRules {
private static final MaterialRules.MaterialRule DIRT = makeStateRule(Blocks.DIRT);
private static final MaterialRules.MaterialRule GRASS_BLOCK = makeStateRule(Blocks.GRASS_BLOCK);
private static final MaterialRules.MaterialRule STONE_BLOCK = makeStateRule(Blocks.STONE);
private static final MaterialRules.MaterialRule GRANITE_BLOCK = makeStateRule(Blocks.GRANITE);
// private static final MaterialRules.MaterialRule RUBY = makeStateRule(ModBlocks.RUBY_BLOCK);
// private static final MaterialRules.MaterialRule RAW_RUBY = makeStateRule(ModBlocks.RAW_RUBY_BLOCK);
public static MaterialRules.MaterialRule makeRules() {
MaterialRules.MaterialCondition isAtOrAboveWaterLevel = MaterialRules.water(-1, 0);
MaterialRules.MaterialRule grassSurface = MaterialRules.sequence(MaterialRules.condition(isAtOrAboveWaterLevel, GRASS_BLOCK), DIRT);
return MaterialRules.sequence(MaterialRules.sequence(MaterialRules.condition(MaterialRules.biome(ModBiomes.TEST_BIOME),
MaterialRules.condition(MaterialRules.STONE_DEPTH_FLOOR, STONE_BLOCK)),
MaterialRules.condition(MaterialRules.STONE_DEPTH_CEILING, GRANITE_BLOCK)),
// Default to a grass and dirt surface
MaterialRules.condition(MaterialRules.STONE_DEPTH_FLOOR, grassSurface)
);
}
private static MaterialRules.MaterialRule makeStateRule(Block block) {
return MaterialRules.block(block.getDefaultState());
}
}

View File

@ -0,0 +1,45 @@
package jesse.keeblarcraft.world.dimension;
import java.util.OptionalLong;
import jesse.keeblarcraft.Keeblarcraft;
import net.minecraft.registry.Registerable;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.registry.tag.BlockTags;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.intprovider.UniformIntProvider;
import net.minecraft.world.World;
import net.minecraft.world.dimension.DimensionOptions;
import net.minecraft.world.dimension.DimensionType;
import net.minecraft.world.dimension.DimensionTypes;
public class ModDimensions {
public static final RegistryKey<DimensionOptions> KEEBLAR_KEY = RegistryKey.of(RegistryKeys.DIMENSION,
new Identifier(Keeblarcraft.MOD_ID, "keeblarcraftdim"));
public static final RegistryKey<World> KEEBLAR_LEVEL_KEY = RegistryKey.of(RegistryKeys.WORLD,
new Identifier(Keeblarcraft.MOD_ID, "keeblarcraftdim"));
public static final RegistryKey<DimensionType> KEEBLAR_DIM_TYPE = RegistryKey.of(RegistryKeys.DIMENSION_TYPE,
new Identifier(Keeblarcraft.MOD_ID, "keeblarcraftdim_type"));
public static void bootstrapType(Registerable<DimensionType> context) {
context.register(KEEBLAR_DIM_TYPE, new DimensionType(
OptionalLong.of(12750), // fixedTime
true, // hasSkylight
false, // hasCeiling
false, // ultraWarm
false, // natural
1.0, // coordinateScale
true, // bedWorks
false, // respawnAnchorWorks
0, // minY
480, // height DO NOT LOWER ANYMORE. IN PRODUCTION
256, // logicalHeight
BlockTags.INFINIBURN_OVERWORLD, // infiniburn
DimensionTypes.OVERWORLD_ID, // effectsLocation
0.5f, // ambientLight
new DimensionType.MonsterSettings(false, false, UniformIntProvider.create(0, 0), 0)));
}
}

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

@ -1,6 +1,7 @@
{
"replace": false,
"values": [
"keeblarcraft:example_block_ore"
"keeblarcraft:example_block_ore",
"keeblarcraft:faction_base_block"
]
}

Some files were not shown because too many files have changed in this diff Show More