From b048e34eda7b9b6990837ccdea3349150b53512c Mon Sep 17 00:00:00 2001 From: Jkibbels Date: Sat, 23 Nov 2024 22:06:00 -0500 Subject: [PATCH] [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 --- build.gradle | 10 +- .../27b8b1d6af601e15f202616061490ff2b85aa40c | 3 + .../dimension_type/keeblarcraftdim_type.json | 26 ++ .../worldgen/biome/test_biome.json | 99 ++++++ .../keeblarcraft/BankMgr/BankManager.java | 74 ++++- .../BankMgr/IndividualAccount.java | 2 +- .../keeblarcraft/BankMgr/IndividualBank.java | 30 ++ .../Commands/AttributeCommands.java | 8 +- .../keeblarcraft/Commands/BankCommands.java | 45 +-- .../Commands/CustomCommandManager.java | 3 +- .../Commands/FactionCommands.java | 95 +++++- .../EventMgr/DimensionLoadingEvent.java | 55 ++++ .../FactionMgr/FactionConfig.java | 290 ++++++++++++++++++ .../FactionMgr/FactionManager.java | 167 ++++++++++ .../keeblarcraft/FactionMgr/TeamManager.java | 15 - .../java/jesse/keeblarcraft/Keeblarcraft.java | 33 ++ .../keeblarcraft/datagen/WorldGenerator.java | 28 ++ .../keeblarcraft/world/DataGeneration.java | 26 ++ .../keeblarcraft/world/biome/ModBiomes.java | 68 ++++ .../world/biome/ModOverworldRegion.java | 27 ++ .../world/biome/ModTerrablenderAPI.java | 17 + .../world/biome/surface/ModMaterialRules.java | 33 ++ .../world/dimension/ModDimensions.java | 45 +++ .../dimension/keeblarcraftdim.json | 36 +++ src/main/resources/fabric.mod.json | 8 +- 25 files changed, 1183 insertions(+), 60 deletions(-) create mode 100644 src/main/generated/.cache/27b8b1d6af601e15f202616061490ff2b85aa40c create mode 100644 src/main/generated/data/keeblarcraft/dimension_type/keeblarcraftdim_type.json create mode 100644 src/main/generated/data/keeblarcraft/worldgen/biome/test_biome.json create mode 100644 src/main/java/jesse/keeblarcraft/EventMgr/DimensionLoadingEvent.java create mode 100644 src/main/java/jesse/keeblarcraft/FactionMgr/FactionConfig.java create mode 100644 src/main/java/jesse/keeblarcraft/FactionMgr/FactionManager.java delete mode 100644 src/main/java/jesse/keeblarcraft/FactionMgr/TeamManager.java create mode 100644 src/main/java/jesse/keeblarcraft/datagen/WorldGenerator.java create mode 100644 src/main/java/jesse/keeblarcraft/world/DataGeneration.java create mode 100644 src/main/java/jesse/keeblarcraft/world/biome/ModBiomes.java create mode 100644 src/main/java/jesse/keeblarcraft/world/biome/ModOverworldRegion.java create mode 100644 src/main/java/jesse/keeblarcraft/world/biome/ModTerrablenderAPI.java create mode 100644 src/main/java/jesse/keeblarcraft/world/biome/surface/ModMaterialRules.java create mode 100644 src/main/java/jesse/keeblarcraft/world/dimension/ModDimensions.java create mode 100644 src/main/resources/data/keeblarcraft/dimension/keeblarcraftdim.json diff --git a/build.gradle b/build.gradle index 70cb7b3..be194d8 100644 --- a/build.gradle +++ b/build.gradle @@ -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 { @@ -46,6 +51,9 @@ dependencies { modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" //modCompileOnly "cc.tweaked:cc-tweaked-1.20-fabric-api:1.105.0" //modRuntimeOnly "cc.tweaked:cc-tweaked-1.20-fabric-api:1.105.0" + modImplementation 'net.kyrptonaught:customportalapi:0.0.1-beta65-1.20' + include 'net.kyrptonaught:customportalapi:0.0.1-beta65-1.20' + modImplementation 'com.github.glitchfiend:TerraBlender-fabric:1.20.1-3.0.1.7' } processResources { diff --git a/src/main/generated/.cache/27b8b1d6af601e15f202616061490ff2b85aa40c b/src/main/generated/.cache/27b8b1d6af601e15f202616061490ff2b85aa40c new file mode 100644 index 0000000..2ff77c4 --- /dev/null +++ b/src/main/generated/.cache/27b8b1d6af601e15f202616061490ff2b85aa40c @@ -0,0 +1,3 @@ +// 1.20 2024-11-23T21:42:28.919839077 keeblarcraft/Keeblarcraft World Generation +afc3340283d1101601bd4d2ca96341a58eceaf83 data/keeblarcraft/dimension_type/keeblarcraftdim_type.json +4398eda2b0c28b2c754c45f5805534bf1921b243 data/keeblarcraft/worldgen/biome/test_biome.json diff --git a/src/main/generated/data/keeblarcraft/dimension_type/keeblarcraftdim_type.json b/src/main/generated/data/keeblarcraft/dimension_type/keeblarcraftdim_type.json new file mode 100644 index 0000000..b980671 --- /dev/null +++ b/src/main/generated/data/keeblarcraft/dimension_type/keeblarcraftdim_type.json @@ -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 +} \ No newline at end of file diff --git a/src/main/generated/data/keeblarcraft/worldgen/biome/test_biome.json b/src/main/generated/data/keeblarcraft/worldgen/biome/test_biome.json new file mode 100644 index 0000000..5ffbc11 --- /dev/null +++ b/src/main/generated/data/keeblarcraft/worldgen/biome/test_biome.json @@ -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 +} \ No newline at end of file diff --git a/src/main/java/jesse/keeblarcraft/BankMgr/BankManager.java b/src/main/java/jesse/keeblarcraft/BankMgr/BankManager.java index d98e053..8f3754c 100644 --- a/src/main/java/jesse/keeblarcraft/BankMgr/BankManager.java +++ b/src/main/java/jesse/keeblarcraft/BankMgr/BankManager.java @@ -5,6 +5,8 @@ import java.util.List; import java.util.ArrayList; import java.util.Map.Entry; +import org.apache.logging.log4j.core.jmx.Server; + import jesse.keeblarcraft.ConfigMgr.ConfigManager; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.Text; @@ -22,11 +24,24 @@ public final class BankManager { return static_inst; } - private static Integer KEEBLARCRAFT_SERVER_BANK_ID = 1000; + private class PlayerBankConfig { + List activeBanks = new ArrayList(); // List of all banks a player has accounts in + String defaultSelectedBank; + } + // Key = player uuid + // Val = player config + HashMap playerConfigs = new HashMap(); // 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 banks = new HashMap(); + + // KEY = Bank name + // Val = Bank routing number private HashMap bankNameFastMap = new HashMap(); public BankManager() {} @@ -71,6 +86,26 @@ public final class BankManager { return bank; } + public void ChangeDefaultPlayerAccount(ServerPlayerEntity player, String newDefaultAccount) { + String bankName = AccountNumberGenerator.GetFinancialSymbolFromId(newDefaultAccount); + System.out.println("ChangeDefaultPlayerAccount: Received bankName " + bankName); + System.out.println(bankNameFastMap); + + // Verify bank exists first + 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()).defaultSelectedBank = newDefaultAccount; + } + } else { + player.sendMessage(Text.of("Could not change default selected bank. Bank does not exist!")); + } + } + // Change the funds of an account from an administrative perspective public void AdminChangeFunds(ServerPlayerEntity initiator, String accountId, Integer amount, String changeType, String optionalReason) { // Check to make sure account id exists @@ -106,14 +141,49 @@ public final class BankManager { } } - public void InitiateBankFundsTransfer(String fromAccount, String toAccount) { + public void InitiateBankFundsTransfer(ServerPlayerEntity fromPlayer, String toAccount, Integer amount) { + // Get player default selection + String fromAccount = playerConfigs.get(fromPlayer.getUuidAsString()).defaultSelectedBank; + 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 { + fromPlayer.sendMessage(Text.of("Something went wrong! Either your bank or their bank does not exist. You shouldn't get this error!")); + } } public void InitiateBankAccountClosure(String bankIdentifier, ServerPlayerEntity player, String bankAccountId) { } + public String GetDefaultSelectedAccount(String playerUuid, String bankIdentifier) { + String account = ""; + + if (playerConfigs.containsKey(playerUuid)) { + account = playerConfigs.get(playerUuid).defaultSelectedBank; + } + + return account; + } + public void InitiateBankAccountCreation(String bankIdentifier, ServerPlayerEntity player, String accountType) { Boolean success = false; System.out.println("initiating bank creation"); diff --git a/src/main/java/jesse/keeblarcraft/BankMgr/IndividualAccount.java b/src/main/java/jesse/keeblarcraft/BankMgr/IndividualAccount.java index c249e2d..d3fdcdb 100644 --- a/src/main/java/jesse/keeblarcraft/BankMgr/IndividualAccount.java +++ b/src/main/java/jesse/keeblarcraft/BankMgr/IndividualAccount.java @@ -99,7 +99,7 @@ public class IndividualAccount { public Boolean CanWithdraw(Integer amount) { Boolean canWithdraw = false; - if (!accountLocked && accountBalance - amount >= 0) { + if (!accountLocked && (accountBalance - amount >= 0 || allowNegativeBalance)) { canWithdraw = true; } diff --git a/src/main/java/jesse/keeblarcraft/BankMgr/IndividualBank.java b/src/main/java/jesse/keeblarcraft/BankMgr/IndividualBank.java index b537f5d..6f6b449 100644 --- a/src/main/java/jesse/keeblarcraft/BankMgr/IndividualBank.java +++ b/src/main/java/jesse/keeblarcraft/BankMgr/IndividualBank.java @@ -45,7 +45,12 @@ public class IndividualBank { // Key = ACCOUNT NUMBER // Value = ACCOUNT private class Accounts { + // Key = account identifier + // Val = account object private HashMap accountsList = new HashMap(); + + // Key = user uuid + // Val = List of account identifiers private HashMap> accountsListFromName = new HashMap>(); // This is a list that just points to a list of account numbers by person. USEFUL } @@ -334,6 +339,31 @@ public class IndividualBank { return containsAccount; } + 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; + } + + 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 /// diff --git a/src/main/java/jesse/keeblarcraft/Commands/AttributeCommands.java b/src/main/java/jesse/keeblarcraft/Commands/AttributeCommands.java index ad60637..612c0b1 100644 --- a/src/main/java/jesse/keeblarcraft/Commands/AttributeCommands.java +++ b/src/main/java/jesse/keeblarcraft/Commands/AttributeCommands.java @@ -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); diff --git a/src/main/java/jesse/keeblarcraft/Commands/BankCommands.java b/src/main/java/jesse/keeblarcraft/Commands/BankCommands.java index bf6b398..1718273 100644 --- a/src/main/java/jesse/keeblarcraft/Commands/BankCommands.java +++ b/src/main/java/jesse/keeblarcraft/Commands/BankCommands.java @@ -18,9 +18,6 @@ import jesse.keeblarcraft.Utils.HelpBuilder.COLOR_CODE; import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.text.ClickEvent; -import net.minecraft.text.MutableText; -import net.minecraft.text.Style; import net.minecraft.text.Text; import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; @@ -250,10 +247,10 @@ public class BankCommands { CloseCommand(context.getSource().getPlayer(), formattedArgList); break; case "select": - SelectCommand(context.getSource().getPlayer(), formattedArgList); + SelectCommand(context.getSource().getPlayer(), formattedArgList.subList(1, formattedArgList.size())); break; case "wire": - WireCommand(context.getSource().getPlayer(), formattedArgList); + WireCommand(context.getSource().getPlayer(), formattedArgList.subList(1, formattedArgList.size())); break; case "balance": BalanceCommand(context.getSource().getPlayer(), formattedArgList); @@ -304,7 +301,7 @@ public class BankCommands { HelpCommand(player, List.of(helpCmd)); } - System.out.println("ParseToInteger was called. The input int was " + possibleInt + " and the parsed int is " + amount); + System.out.println("ParseToInteger was called. The input was " + possibleInt + " and the parsed int is " + amount); return amount; } @@ -705,20 +702,16 @@ public class BankCommands { // optional = [default|secondary|backup] public int SelectCommand(ServerPlayerEntity sourcePlayer, List argList) { if (argList.size() > 0) { - String requiredArg = argList.get(0).toLowerCase(); + String requiredArg = argList.get(0); // If the optional args exist; fetch them String optionalArg = ""; if (argList.size() == 2) { - optionalArg = argList.get(1).toLowerCase(); + optionalArg = argList.get(1); } - /* - * - * - * BANKMANAGER CALL-THROUGHS HERE - * - */ + BankManager.GetInstance().ChangeDefaultPlayerAccount(sourcePlayer, requiredArg); + } else { sourcePlayer.sendMessage(Text.of("Unrecognized select command. Please run /bank help select for more information.")); } @@ -726,29 +719,21 @@ public class BankCommands { } // Possible code paths: - // REQUIRED = {AMOUNT} {ACCOUNT_ID|PLAYER_NAME} [optional] NOTE: A wire CANNOT be performed on an alias; as a possible conflict can happen between player accounts since aliases are ONLY unique PER player - // OPTIONAL = [account id | alias] [reason] NOTE: This is the account the wire comes from. If none selected, DEFAULT is chosen (if exists) + // REQUIRED = {AMOUNT} {ACCOUNT_ID} [optional] + // OPTIONAL = [reason] public int WireCommand(ServerPlayerEntity sourcePlayer, List argList) { + System.out.println("WireCommand called with arg size " + argList.size()); if (argList.size() >= 2) { - String destAccount = argList.get(0).toLowerCase(); - String amountToWire = argList.get(1).toLowerCase(); - - String optionalNonDefaultAccount = ""; - if (argList.size() >= 3) { - optionalNonDefaultAccount = argList.get(2).toLowerCase(); - } + Integer amountToWire = ParseToInteger(sourcePlayer, argList.get(0), HELPCMD_WIRE); + String destAccount = argList.get(1); String optionalReason = ""; - if (argList.size() >= 4) { + if (argList.size() >= 3) { optionalReason = argList.get(3); } + System.out.println("optional reason: " + optionalReason); - /* - * - * - * CALL THROUGHS TO BANK MGR HERE - * - */ + BankManager.GetInstance().InitiateBankFundsTransfer(sourcePlayer, destAccount, amountToWire); } else { sourcePlayer.sendMessage(Text.of("Unrecognized wire command. Please run /bank help wire for more information.")); } diff --git a/src/main/java/jesse/keeblarcraft/Commands/CustomCommandManager.java b/src/main/java/jesse/keeblarcraft/Commands/CustomCommandManager.java index 0605bdd..bdb91bf 100644 --- a/src/main/java/jesse/keeblarcraft/Commands/CustomCommandManager.java +++ b/src/main/java/jesse/keeblarcraft/Commands/CustomCommandManager.java @@ -22,6 +22,7 @@ public class CustomCommandManager { NoteCommands noteCommands = new NoteCommands(); BankCommands bankCommands = new BankCommands(); AttributeCommands attributeCommands = new AttributeCommands(); + FactionCommands factionCommands = new FactionCommands(); // REGISTER COMMANDS BELOW System.out.println(ChatUtil.ColoredString("REGISTERING CUSTOM COMMAND EXTENSIONS BELOW", CONSOLE_COLOR.BLUE)); @@ -29,6 +30,6 @@ public class CustomCommandManager { noteCommands.RegisterNoteCommands(); bankCommands.RegisterCommands(); attributeCommands.RegisterCommands(); - + factionCommands.RegisterFactionCommands(); } } diff --git a/src/main/java/jesse/keeblarcraft/Commands/FactionCommands.java b/src/main/java/jesse/keeblarcraft/Commands/FactionCommands.java index 1736cc6..cc3937c 100644 --- a/src/main/java/jesse/keeblarcraft/Commands/FactionCommands.java +++ b/src/main/java/jesse/keeblarcraft/Commands/FactionCommands.java @@ -1,21 +1,89 @@ package jesse.keeblarcraft.Commands; +import java.util.List; + +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.context.CommandContext; + +import jesse.keeblarcraft.FactionMgr.FactionManager; +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 FactionCommands { // Register function for commands 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(); + + // 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 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); + + createFaction.addChild(createFactionName); + disbandFaction.addChild(disbandFactionName); + }); } /// PRIVATE HANDLERS BELOW - private int CreateFaction() { - int retValue = -1; + private int CreateFaction(CommandContext 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; } - private int DeleteFaction() { - int retValue = -1; + private int DeleteFaction(CommandContext context, String newFactionName) { + int retValue = 0; + + ServerPlayerEntity player = context.getSource().getPlayer(); + FactionManager.GetInstance().DeleteFaction(newFactionName, player); return retValue; } @@ -26,6 +94,14 @@ public class FactionCommands { return retValue; } + private int LeaveFaction(CommandContext context) { + ServerPlayerEntity player = context.getSource().getPlayer(); + + FactionManager.GetInstance().LeaveFaction(player); + + return 0; + } + private int KickPlayerFromFaction() { int retValue = -1; @@ -87,9 +163,18 @@ public class FactionCommands { return retValue; } - private int ListAllFactions() { + private int ListAllFactions(ServerPlayerEntity player) { int retValue = -1; + System.out.println("Listing factions"); + List 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; } diff --git a/src/main/java/jesse/keeblarcraft/EventMgr/DimensionLoadingEvent.java b/src/main/java/jesse/keeblarcraft/EventMgr/DimensionLoadingEvent.java new file mode 100644 index 0000000..f3a0c44 --- /dev/null +++ b/src/main/java/jesse/keeblarcraft/EventMgr/DimensionLoadingEvent.java @@ -0,0 +1,55 @@ +package jesse.keeblarcraft.EventMgr; + +import java.util.HashMap; +import java.util.Map.Entry; + +import jesse.keeblarcraft.world.dimension.ModDimensions; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; + +public class DimensionLoadingEvent { + + // private static List inventories = new ArrayList(); + public static HashMap inventories = new HashMap(); + + // TODO: In the future when the attribute system is more complete this will need to filter a whitelist of items + // from the that system + story mode because some items will be able to transcend dimensions! + public static void HandleWorldMove(ServerPlayerEntity player, ServerWorld origin, ServerWorld destination) { + if (destination.getDimensionEntry().matchesKey(ModDimensions.KEEBLAR_DIM_TYPE)) { + // Make sure player is in map. For now we only care about storing OVERWORLD inventory. We DO NOT care about + // the dimension inventory! + if (!inventories.containsKey(player.getUuidAsString())) { + PlayerInventory copyInv = new PlayerInventory(player); + copyInv.clone(player.getInventory()); + inventories.put(player.getUuidAsString(), copyInv); + player.getInventory().clear(); + } else { + System.out.println("Player in system. Ignoring"); + } + } else if (origin.getDimensionEntry().matchesKey(ModDimensions.KEEBLAR_DIM_TYPE)) { + if (inventories.containsKey(player.getUuidAsString())) { + System.out.println("Player is in map. Cloning our inventory back to them..."); + player.getInventory().clone(inventories.get(player.getUuidAsString())); + inventories.remove(player.getUuidAsString()); + } else { + System.out.println("Player not in system. Ignoring"); + } + } else { + System.out.println("dest TYPE - KEY" + destination.getDimensionEntry().getType().toString() + " -- " + destination.getDimensionEntry().getKey().toString()); + System.out.println("orig TYPE - KEY: " + origin.getDimensionEntry().getType().toString() + " -- "+ origin.getDimensionEntry().getKey().toString()); + } + } + + // needs to be tested + public static void ResetInventories() { + System.out.println("ResetInventories: inventory size: " + inventories.size()); + for (Entry entry : inventories.entrySet()) { + PlayerEntity player = entry.getValue().player; + + System.out.println("Found PlayerEntity"); + player.getInventory().clone(entry.getValue()); + } + } +} diff --git a/src/main/java/jesse/keeblarcraft/FactionMgr/FactionConfig.java b/src/main/java/jesse/keeblarcraft/FactionMgr/FactionConfig.java new file mode 100644 index 0000000..5d2470e --- /dev/null +++ b/src/main/java/jesse/keeblarcraft/FactionMgr/FactionConfig.java @@ -0,0 +1,290 @@ +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 { + // Enum may be extended in future + public static enum VALID_FACTION_ROLES { + OWNER, + COOWNER, + MANAGEMENT, + EMPLOYEE + } + + private static Map 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 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 factionPlayerList = new HashMap(); + // Key = Player DISPLAY name + // Val = Faction role of player + HashMap DISPLAY_ONLY_LIST = new HashMap(); + + // List contains UUID of players who are openly invited to this faction + List openInvites = new ArrayList(); + + Integer factionBankBalance; + Integer factionPower; + String factionName; + } + + 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; + } + + 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; + } + + 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; + } + + private Boolean IsOnInviteList(String factionName, String playerUuid) { + Boolean success = false; + + if (IsValid(factionName)) { + if (allFactions.get(factionName).openInvites.contains(playerUuid)) { + success = true; + } + } + + return success; + } + + 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); + } + } + + 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; + } + + public Boolean JoinFaction(String factionName, String playerUuid, String playerDisplayName) { + Boolean success = false; + + if (IsOnInviteList(factionName, playerUuid) ) { + AddToFaction(factionName, playerUuid, playerDisplayName); + success = true; + } + + return success; + } + + 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; + } + + private Boolean HasPlayer(String factionName, String playerUuid) { + Boolean success = false; + + if (IsValid(factionName)) { + success = allFactions.get(factionName).factionPlayerList.containsKey(playerUuid); + } + + return success; + } + + public Boolean IsValid(String factionName) { + if (allFactions.containsKey(factionName)) { + return true; + } else { + return false; + } + } + + // Empty string means no faction found. This is expensive! + public String FindFactionOfPlayer(String playerUuid) { + String faction = ""; + + System.out.println("Attempting to find player factions with uuid " + playerUuid); + for (Entry 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; + } + + 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; + } + + // Factions is setup in a way where anybody can demote anybody underneath them and demotions of the lowest level lead to an automatic kick. The + // same behavior is kept here + 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; + } + + 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; + } + + 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; + } + + public List ListOfAllFactions() { + List facs = new ArrayList(); + + System.out.println("ListOfFactions - map size: " + allFactions.size()); + for (Entry entry : allFactions.entrySet()) { + System.out.println("Adding fac " + entry.getKey() + " to fac"); + facs.add(entry.getKey()); + } + + return facs; + } + + // Key = Faction identifier + // Val = Faction object + HashMap allFactions = new HashMap(); +} diff --git a/src/main/java/jesse/keeblarcraft/FactionMgr/FactionManager.java b/src/main/java/jesse/keeblarcraft/FactionMgr/FactionManager.java new file mode 100644 index 0000000..3576f3d --- /dev/null +++ b/src/main/java/jesse/keeblarcraft/FactionMgr/FactionManager.java @@ -0,0 +1,167 @@ +/* + * + * 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.List; + +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; +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("bank/" + "factions.json"); + FlashConfig(); + } catch (Exception e) { + System.out.println(ChatUtil.ColoredString("Could not write to file", CONSOLE_COLOR.RED)); + } + } + + 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(); + } + } + + 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.getDisplayName().toString()); + player.sendMessage(Text.of("[Factions]: You left your faction!")); + } else { + player.sendMessage(Text.of("[Factions]: You are not in a faction!")); + } + + return success; + } + + public Boolean CreateFaction(String factionName, ServerPlayerEntity creator) { + Boolean success = false; + String facOfPlayer = factionConfig.factions.FindFactionOfPlayer(creator.getUuidAsString()); + + if (facOfPlayer == "") { + success = factionConfig.factions.CreateFaction(factionName, creator.getUuidAsString(), creator.getDisplayName().toString()); + + 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; + } + + 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 List ListOfFactions() { + System.out.println("Callthrough of listoffactions"); + return factionConfig.factions.ListOfAllFactions(); + } + + public String GetFactionOfPlayer(String playerUuid) { + return factionConfig.factions.FindFactionOfPlayer(playerUuid); + } + + 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; + } + + public Boolean DemotePlayer(ServerPlayerEntity caller, String promoteeUuid, String promoteeDisplayName) { + Boolean success = factionConfig.factions.DemotePlayer(GetFactionOfPlayer(caller.getUuidAsString()), caller.getUuidAsString(), promoteeUuid, promoteeDisplayName); + + 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; + } + + public void FlashConfig() { + try { + config.WriteToJsonFile(FACTION_CFG_FILE, factionConfig); + } catch (FILE_WRITE_EXCEPTION e) { + System.out.println("config writing of faction file failed. oh well!"); + } + } +} diff --git a/src/main/java/jesse/keeblarcraft/FactionMgr/TeamManager.java b/src/main/java/jesse/keeblarcraft/FactionMgr/TeamManager.java deleted file mode 100644 index e63785b..0000000 --- a/src/main/java/jesse/keeblarcraft/FactionMgr/TeamManager.java +++ /dev/null @@ -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 - -} diff --git a/src/main/java/jesse/keeblarcraft/Keeblarcraft.java b/src/main/java/jesse/keeblarcraft/Keeblarcraft.java index ac005aa..a1fbe7b 100644 --- a/src/main/java/jesse/keeblarcraft/Keeblarcraft.java +++ b/src/main/java/jesse/keeblarcraft/Keeblarcraft.java @@ -12,7 +12,17 @@ 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.ServerLifecycleEvents; +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents.ServerStopping; import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; +import net.kyrptonaught.customportalapi.api.CustomPortalBuilder; +import net.minecraft.block.Blocks; +import net.minecraft.entity.EntityDimensions; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.item.Items; import net.minecraft.registry.Registries; import net.minecraft.registry.Registry; import net.minecraft.resource.featuretoggle.FeatureSet; @@ -28,6 +38,7 @@ import jesse.keeblarcraft.BankMgr.BankManager; import jesse.keeblarcraft.Commands.CustomCommandManager; import jesse.keeblarcraft.CustomBlocks.BlockList; import jesse.keeblarcraft.CustomItems.ItemManager; +import jesse.keeblarcraft.EventMgr.DimensionLoadingEvent; import jesse.keeblarcraft.EventMgr.ServerTickListener; import jesse.keeblarcraft.GuiMgr.TreeHandler; import jesse.keeblarcraft.Utils.CustomExceptions.SETUP_FAILED_EXCEPTION; @@ -81,6 +92,17 @@ public class Keeblarcraft implements ModInitializer { } }); + ServerEntityWorldChangeEvents.AFTER_PLAYER_CHANGE_WORLD.register((player, origin, destination) -> { + System.out.println("Calling back..."); + DimensionLoadingEvent.HandleWorldMove(player, origin, destination); + }); + + ServerLifecycleEvents.SERVER_STOPPING.register((server) ->{ + // Stuff here + System.out.println("SERVER_STOPPING callback called."); + DimensionLoadingEvent.ResetInventories(); + }); + // Initialize our ticks!! ServerTickListener.InitializeServerTicks(); @@ -102,6 +124,17 @@ public class Keeblarcraft implements ModInitializer { // Register blocks BlockList.RegisterBlocks(); + // 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(); + } 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)); diff --git a/src/main/java/jesse/keeblarcraft/datagen/WorldGenerator.java b/src/main/java/jesse/keeblarcraft/datagen/WorldGenerator.java new file mode 100644 index 0000000..1a1214a --- /dev/null +++ b/src/main/java/jesse/keeblarcraft/datagen/WorldGenerator.java @@ -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 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)); + } +} diff --git a/src/main/java/jesse/keeblarcraft/world/DataGeneration.java b/src/main/java/jesse/keeblarcraft/world/DataGeneration.java new file mode 100644 index 0000000..c05a159 --- /dev/null +++ b/src/main/java/jesse/keeblarcraft/world/DataGeneration.java @@ -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); + } + +} diff --git a/src/main/java/jesse/keeblarcraft/world/biome/ModBiomes.java b/src/main/java/jesse/keeblarcraft/world/biome/ModBiomes.java new file mode 100644 index 0000000..a969b9d --- /dev/null +++ b/src/main/java/jesse/keeblarcraft/world/biome/ModBiomes.java @@ -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 TEST_BIOME = RegistryKey.of(RegistryKeys.BIOME, + new Identifier(Keeblarcraft.MOD_ID, "test_biome")); + + public static void bootstrap(Registerable 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 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(); + } +} diff --git a/src/main/java/jesse/keeblarcraft/world/biome/ModOverworldRegion.java b/src/main/java/jesse/keeblarcraft/world/biome/ModOverworldRegion.java new file mode 100644 index 0000000..9680999 --- /dev/null +++ b/src/main/java/jesse/keeblarcraft/world/biome/ModOverworldRegion.java @@ -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 registry, Consumer>> mapper) { + // this.addModifiedVanillaOverworldBiomes(mapper, modifiedVanillaOverworldBuilder -> { + // modifiedVanillaOverworldBuilder.replaceBiome(BiomeKeys.FOREST, ModBiomes.TEST_BIOME); + // }); + } +} diff --git a/src/main/java/jesse/keeblarcraft/world/biome/ModTerrablenderAPI.java b/src/main/java/jesse/keeblarcraft/world/biome/ModTerrablenderAPI.java new file mode 100644 index 0000000..c9eee2b --- /dev/null +++ b/src/main/java/jesse/keeblarcraft/world/biome/ModTerrablenderAPI.java @@ -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()); + } +} \ No newline at end of file diff --git a/src/main/java/jesse/keeblarcraft/world/biome/surface/ModMaterialRules.java b/src/main/java/jesse/keeblarcraft/world/biome/surface/ModMaterialRules.java new file mode 100644 index 0000000..c58880f --- /dev/null +++ b/src/main/java/jesse/keeblarcraft/world/biome/surface/ModMaterialRules.java @@ -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()); + } +} diff --git a/src/main/java/jesse/keeblarcraft/world/dimension/ModDimensions.java b/src/main/java/jesse/keeblarcraft/world/dimension/ModDimensions.java new file mode 100644 index 0000000..159d550 --- /dev/null +++ b/src/main/java/jesse/keeblarcraft/world/dimension/ModDimensions.java @@ -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 KEEBLAR_KEY = RegistryKey.of(RegistryKeys.DIMENSION, + new Identifier(Keeblarcraft.MOD_ID, "keeblarcraftdim")); + + public static final RegistryKey KEEBLAR_LEVEL_KEY = RegistryKey.of(RegistryKeys.WORLD, + new Identifier(Keeblarcraft.MOD_ID, "keeblarcraftdim")); + + public static final RegistryKey KEEBLAR_DIM_TYPE = RegistryKey.of(RegistryKeys.DIMENSION_TYPE, + new Identifier(Keeblarcraft.MOD_ID, "keeblarcraftdim_type")); + + public static void bootstrapType(Registerable 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))); + } +} diff --git a/src/main/resources/data/keeblarcraft/dimension/keeblarcraftdim.json b/src/main/resources/data/keeblarcraft/dimension/keeblarcraftdim.json new file mode 100644 index 0000000..3d4c330 --- /dev/null +++ b/src/main/resources/data/keeblarcraft/dimension/keeblarcraftdim.json @@ -0,0 +1,36 @@ +{ + "type": "keeblarcraft:keeblarcraftdim_type", + "generator": { + "type": "minecraft:noise", + "settings": "minecraft:overworld", + "biome_source": { + "type": "minecraft:multi_noise", + "biomes": [ + { + "biome": "minecraft:plains", + "parameters": { + "temperature": 0.3, + "humidity": 0.1, + "continentalness": 0.2, + "erosion": 0.1, + "weirdness": 0.1, + "depth": 0, + "offset": 0 + } + }, + { + "biome": "keeblarcraft:test_biome", + "parameters": { + "temperature": 0, + "humidity": 0, + "continentalness": 0.1, + "erosion": 0, + "weirdness": 0, + "depth": 0, + "offset": 0 + } + } + ] + } + } + } diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index c3d360f..e9b1b75 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -20,6 +20,12 @@ ], "client": [ "jesse.keeblarcraft.KeeblarcraftClient" + ], + "fabric-datagen": [ + "jesse.keeblarcraft.world.DataGeneration" + ], + "terrablender": [ + "jesse.keeblarcraft.world.biome.ModTerrablenderAPI" ] }, "depends": { @@ -27,7 +33,7 @@ "minecraft": "~1.20", "java": ">=17", "fabric-api": "*", - "fabric-key-binding-api-v1": "*" + "terrablender": "*" }, "suggests": { "another-mod": "*"