diff --git a/apps/atlas/kbve_atlas/api/clients/__init__.py b/apps/atlas/kbve_atlas/api/clients/__init__.py
index 91f61cebd..206d08212 100644
--- a/apps/atlas/kbve_atlas/api/clients/__init__.py
+++ b/apps/atlas/kbve_atlas/api/clients/__init__.py
@@ -5,4 +5,5 @@
from .screen_client import ScreenClient
from .novnc_client import NoVNCClient
from .runelite_client import RuneLiteClient
-from .chrome_client import ChromeClient
\ No newline at end of file
+from .chrome_client import ChromeClient
+from .discord_client import DiscordClient
\ No newline at end of file
diff --git a/apps/atlas/kbve_atlas/api/clients/discord_client.py b/apps/atlas/kbve_atlas/api/clients/discord_client.py
new file mode 100644
index 000000000..1f35aca91
--- /dev/null
+++ b/apps/atlas/kbve_atlas/api/clients/discord_client.py
@@ -0,0 +1,99 @@
+import os
+import json
+from ..clients.chrome_client import ChromeClient
+import logging
+import re
+from asyncio import sleep
+
+logger = logging.getLogger("uvicorn")
+
+class DiscordClient:
+ def __init__(self, headless=True, display=":1"):
+ self.headless = headless
+ self.display = display
+ self.chrome_client = ChromeClient(headless=headless, display=display)
+
+ async def login_with_passkey(self, discord_url="https://discord.com/login", passkey=None, retries=3):
+ """
+ Logs into Discord by injecting the passkey into localStorage.
+
+ :param discord_url: URL for Discord login
+ :param passkey: Discord passkey (token). If None, retrieves from environment variable.
+ :param retries: Number of retry attempts for login in case of failure.
+ :return: Success or error message.
+ """
+ passkey = passkey or os.getenv("DISCORD_PASSKEY")
+ if not passkey:
+ raise ValueError("Passkey not provided. Set it as an argument or in the DISCORD_PASSKEY environment variable.")
+
+ # Validate the token format (alphanumeric with optional underscores, hyphens, or dots)
+ if not re.match(r"^[A-Za-z0-9_\-\.]+$", passkey):
+ raise ValueError("Invalid token format. Discord tokens should be alphanumeric with optional underscores, hyphens, or dots.")
+
+
+ for attempt in range(retries):
+ try:
+ logger.info(f"Attempt {attempt + 1} to log into Discord")
+ await self.chrome_client.start_chrome_async()
+
+ logger.info(f"Opening Discord URL: {discord_url}")
+ await self.chrome_client.perform_task_with_chrome(discord_url)
+
+ logger.info("Injecting passkey into localStorage")
+ self.chrome_client.sb.execute_script(f'''
+ window.localStorage.setItem('token', '{passkey}');
+ ''')
+
+ logger.info("Refreshing the page to apply the token")
+ self.chrome_client.sb.refresh()
+
+ logger.info("Checking for successful login")
+ if self.chrome_client.sb.is_element_visible('[data-testid="user-settings"]', timeout=10):
+ logger.info("Discord login verified successfully.")
+ return "Logged into Discord using passkey successfully."
+ else:
+ logger.warning("Failed to verify Discord login.")
+ return "Failed to verify Discord login."
+ except Exception as e:
+ logger.warning(f"Attempt {attempt + 1} failed: {e}")
+ if attempt < retries - 1:
+ await sleep(2) # Wait before retrying
+ else:
+ raise e
+ finally:
+ await self.chrome_client.stop_chrome_async()
+
+ async def verify_login(self):
+ """
+ Verifies if the user is logged into Discord by checking for an authenticated element.
+ :return: Boolean indicating login success or failure.
+ """
+ try:
+ # Check if a Discord-specific element is visible after login
+ if self.chrome_client.sb.is_element_visible('[data-testid="user-settings"]'):
+ logger.info("Discord login verified successfully.")
+ return True
+ else:
+ logger.warning("Discord login verification failed.")
+ return False
+ except Exception as e:
+ logger.error(f"Failed to verify login: {e}")
+ return False
+
+ async def fetch_discord_data(self):
+ """
+ Example method to demonstrate fetching data from Discord after login.
+ You can customize this based on your requirements.
+ """
+ try:
+ # Navigate to a page and extract data
+ guild_url = "https://discord.com/channels/@me"
+ await self.chrome_client.perform_task_with_chrome(guild_url)
+
+ # Extract some example data (like user settings or guild info)
+ user_data = self.chrome_client.sb.get_text('[data-testid="user-settings"]')
+ logger.info(f"Fetched user data: {user_data}")
+ return user_data
+ except Exception as e:
+ logger.error(f"Failed to fetch Discord data: {e}")
+ return f"Failed to fetch Discord data: {e}"
diff --git a/apps/atlas/main.py b/apps/atlas/main.py
index 1bdab8db9..d3126cf40 100644
--- a/apps/atlas/main.py
+++ b/apps/atlas/main.py
@@ -10,7 +10,7 @@
from contextlib import asynccontextmanager
-from kbve_atlas.api.clients import CoinDeskClient, WebsocketEchoClient, PoetryDBClient, ScreenClient, NoVNCClient, RuneLiteClient, ChromeClient
+from kbve_atlas.api.clients import CoinDeskClient, WebsocketEchoClient, PoetryDBClient, ScreenClient, NoVNCClient, RuneLiteClient, ChromeClient, DiscordClient
from kbve_atlas.api.utils import RSSUtility, KRDecorator, CORSUtil, ThemeCore, BroadcastUtility
@@ -127,4 +127,8 @@ def gitlab_navigation_message(navigation_message):
@kr_decorator.k_r("/go-to-greenboard", ChromeClient, "fetch_embedded_job_board")
def fetch_embedded_job_board(navigation_message):
- return navigation_message
\ No newline at end of file
+ return navigation_message
+
+@kr_decorator.k_r("/discord-login", DiscordClient, "login_with_passkey")
+def discord_login_message(message):
+ return message
\ No newline at end of file
diff --git a/apps/kbve.com/src/content/docs/gaming/rimworld.mdx b/apps/kbve.com/src/content/docs/gaming/rimworld.mdx
index 55f9b0c75..2d0c53f80 100644
--- a/apps/kbve.com/src/content/docs/gaming/rimworld.mdx
+++ b/apps/kbve.com/src/content/docs/gaming/rimworld.mdx
@@ -41,6 +41,11 @@ Modders have created an extensive array of modifications, ranging from quality-o
Popular mods include those that introduce new biomes, factions, weapons, and animals, as well as those that enhance colony management and automation.
The community is highly active, with modders continually updating their work to stay compatible with the latest game updates and adding innovative features to keep the game fresh and engaging for both new and veteran players.
+### Star Wars Mod Collection
+
+This is a quick link to the Rat series for [clone armies](https://steamcommunity.com/sharedfiles/filedetails/?id=2986463286&insideModal=0&requirelogin=1)!
+There might be some issues with the 1.5 compatiblity as of 1/1/2025 but got my mando clone army up and running.
+
### Clean Pathfinding 2
[Official SteamWorkshop Link](https://steamcommunity.com/sharedfiles/filedetails/?id=3260446812)
diff --git a/apps/kbve.com/src/content/journal/01-01.mdx b/apps/kbve.com/src/content/journal/01-01.mdx
index 2747d6829..bb3db3ccf 100644
--- a/apps/kbve.com/src/content/journal/01-01.mdx
+++ b/apps/kbve.com/src/content/journal/01-01.mdx
@@ -1,7 +1,7 @@
---
title: "January: 01"
category: Daily
-date: 2024-01-01 12:00:00
+date: 2025-01-01 12:00:00
client: Self
unsplash: 1703511606233-9c7537658701
img: https://images.unsplash.com/photo-1703511606233-9c7537658701?crop=entropy&cs=srgb&fm=jpg&ixid=MnwzNjM5Nzd8MHwxfHJhbmRvbXx8fHx8fHx8fDE2ODE3NDg2ODY&ixlib=rb-4.0.3&q=85
@@ -29,13 +29,35 @@ import { Adsense } from '@kbve/astropad';
- [X] - No Tasks!
+## 2025
-
+- 09:04AM
+
+ **Morning**
+
+ Next day! Almost refreshed and ready for this whole year!
+ Its actually cool to be able to loop back finally, but this year is going to be wild and amazing.
+
+- 10:00AM
+
+ **Rimworld**
+
+ As tradition, the first session of the year should be a rimworld playthrough, I been dying to try that rimworld clone wars mod!
+ I am going to update the rimworld notes to quickly grab them.
+- 02:42PM
+
+ **Kilobase**
+
+ Updated the kanban board from the postgres side and made sure the older kanban tables were removed.
+ We will store all that date inside of the Amazon dynamodb but I need to figure out the best way to handle the timestamps for the tables, hmm.
+ Looks like that TTL is an option in from the Amazon docs but I will have switch back and look through how to call it in Rust.
+
+
+
-### 2024
-#### Personal
+## 2024
- 10:22am - It is 2024, this might be a bit out there but I think 2025 will come really fast.
diff --git a/apps/kbve.com/src/content/journal/12-29.mdx b/apps/kbve.com/src/content/journal/12-29.mdx
new file mode 100644
index 000000000..cb3617dce
--- /dev/null
+++ b/apps/kbve.com/src/content/journal/12-29.mdx
@@ -0,0 +1,34 @@
+---
+title: 'Decemeber: 29th'
+category: Daily
+date: 2024-12-29 12:00:00
+client: Self
+unsplash: 1511512578047-dfb367046420
+img: https://images.unsplash.com/photo-1511512578047-dfb367046420?crop=entropy&cs=srgb&fm=jpg&ixid=MnwzNjM5Nzd8MHwxfHJhbmRvbXx8fHx8fHx8fDE2ODE3NDg2ODY&ixlib=rb-4.0.3&q=85
+description: Decemeber 29th.
+tags:
+ - daily
+---
+
+import { Adsense, Tasks } from '@kbve/astropad';
+
+## 2024
+
+- 01:27PM
+
+ **2024**
+
+ The year is about to wrap over, kinda weird.
+ There were some changes to account for!
+
+- 04:01PM
+
+ **Salt**
+
+ I hate to have this entry but it is what it is.
+
+- 06:06PM
+
+ **Unity**
+
+ After yesterday, I been spending some time to become better at Unity
\ No newline at end of file
diff --git a/apps/kbve.com/src/content/journal/12-30.mdx b/apps/kbve.com/src/content/journal/12-30.mdx
new file mode 100644
index 000000000..7a5e80145
--- /dev/null
+++ b/apps/kbve.com/src/content/journal/12-30.mdx
@@ -0,0 +1,27 @@
+---
+title: 'Decemeber: 30th'
+category: Daily
+date: 2024-12-30 12:00:00
+client: Self
+unsplash: 1511512578047-dfb367046420
+img: https://images.unsplash.com/photo-1511512578047-dfb367046420?crop=entropy&cs=srgb&fm=jpg&ixid=MnwzNjM5Nzd8MHwxfHJhbmRvbXx8fHx8fHx8fDE2ODE3NDg2ODY&ixlib=rb-4.0.3&q=85
+description: Decemeber 30th.
+tags:
+ - daily
+---
+
+import { Adsense, Tasks } from '@kbve/astropad';
+
+## 2024
+
+- 10:35AM
+
+ **SPY**
+
+ Damn $585? Wild.
+
+- 05:40PM
+
+ **Time?***
+
+ xD.... we deal with it as family
\ No newline at end of file
diff --git a/apps/kbve.com/src/content/journal/12-31.mdx b/apps/kbve.com/src/content/journal/12-31.mdx
new file mode 100644
index 000000000..5b179ff84
--- /dev/null
+++ b/apps/kbve.com/src/content/journal/12-31.mdx
@@ -0,0 +1,23 @@
+---
+title: 'Decemeber: 31st'
+category: Daily
+date: 2024-12-31 12:00:00
+client: Self
+unsplash: 1511512578047-dfb367046420
+img: https://images.unsplash.com/photo-1511512578047-dfb367046420?crop=entropy&cs=srgb&fm=jpg&ixid=MnwzNjM5Nzd8MHwxfHJhbmRvbXx8fHx8fHx8fDE2ODE3NDg2ODY&ixlib=rb-4.0.3&q=85
+description: Decemeber 31st.
+tags:
+ - daily
+---
+
+import { Adsense, Tasks } from '@kbve/astropad';
+
+## 2024
+
+- 05:19PM
+
+ **New Years**
+
+ I am super excited for the new year, this is the last entry for this year too?
+ Its going to be more interesting that I can go back to my early entries.
+ I will have to also get used of updating the 2024 to 2025.
\ No newline at end of file
diff --git a/apps/kilobase/sql/kanban/20241222144000_uninstall_kanban.sql b/apps/kilobase/sql/kanban/20241222144000_uninstall_kanban.sql
index 2a38655dd..c5d0ae186 100644
--- a/apps/kilobase/sql/kanban/20241222144000_uninstall_kanban.sql
+++ b/apps/kilobase/sql/kanban/20241222144000_uninstall_kanban.sql
@@ -1,21 +1,6 @@
-- Start the transaction
BEGIN;
--- Drop the validation trigger on the kanban_boards table
-DROP TRIGGER IF EXISTS validate_kanban_data_trigger ON public.kanban_boards;
-
--- Drop the validation function for kanban_boards JSONB data
-DROP FUNCTION IF EXISTS validate_kanban_data;
-
--- Drop the update trigger on the kanban_items table
-DROP TRIGGER IF EXISTS trigger_update_kanban_data ON public.kanban_items;
-
--- Drop the update function for kanban_boards JSONB data
-DROP FUNCTION IF EXISTS update_kanban_data;
-
--- Drop the access control helper function
-DROP FUNCTION IF EXISTS can_access_board;
-
-- Remove RLS policies from kanban_items
DROP POLICY IF EXISTS allow_all_select_items ON public.kanban_items;
DROP POLICY IF EXISTS allow_all_insert_items ON public.kanban_items;
@@ -32,6 +17,21 @@ DROP POLICY IF EXISTS allow_all_delete_boards ON public.kanban_boards;
ALTER TABLE public.kanban_boards DISABLE ROW LEVEL SECURITY;
ALTER TABLE public.kanban_items DISABLE ROW LEVEL SECURITY;
+-- Drop the access control helper function with CASCADE
+DROP FUNCTION IF EXISTS can_access_board CASCADE;
+
+-- Drop the validation trigger on the kanban_boards table
+DROP TRIGGER IF EXISTS validate_kanban_data_trigger ON public.kanban_boards;
+
+-- Drop the validation function for kanban_boards JSONB data
+DROP FUNCTION IF EXISTS validate_kanban_data;
+
+-- Drop the update trigger on the kanban_items table
+DROP TRIGGER IF EXISTS trigger_update_kanban_data ON public.kanban_items;
+
+-- Drop the update function for kanban_boards JSONB data
+DROP FUNCTION IF EXISTS update_kanban_data;
+
-- Drop tables
DROP TABLE IF EXISTS public.kanban_items CASCADE;
DROP TABLE IF EXISTS public.kanban_boards CASCADE;
diff --git a/apps/rust_kanban/src/main.rs b/apps/rust_kanban/src/main.rs
index 3aeab3ae3..4e2d478dc 100644
--- a/apps/rust_kanban/src/main.rs
+++ b/apps/rust_kanban/src/main.rs
@@ -130,6 +130,7 @@ async fn main() {
.allow_origin([
"https://kbve.com".parse::().unwrap(), // Main domain
"https://kanban.kbve.com".parse::().unwrap(), // Subdomain
+ "https://websocketking.com".parse::().unwrap(), // Websocket King Test
"http://localhost".parse::().unwrap(), // Localhost for development
"http://127.0.0.1".parse::().unwrap(), // Localhost alternative
])
diff --git a/packages/mmextensions/mmextensions/Ai/AiAllyBrain.cs b/packages/mmextensions/mmextensions/Ai/AiAllyBrain.cs
index bd23b8c0c..a2cc8f42c 100644
--- a/packages/mmextensions/mmextensions/Ai/AiAllyBrain.cs
+++ b/packages/mmextensions/mmextensions/Ai/AiAllyBrain.cs
@@ -20,6 +20,7 @@ public class AiAllyBrain : AIBrain
private AIDecisionDetectTargetRadius2D detectPlayerDecision;
private AIDecisionDetectTargetRadius2D detectEnemyDecision;
private AIDecisionDistanceToTarget distanceToTargetDecision;
+ private AIDecisionDistanceToTarget distanceToTargetFarDecision;
private AIDecisionTargetIsAlive targetIsAliveDecision;
private AIDecisionTimeInState timeInStateDecision;
private CharacterHandleWeapon handleWeapon;
@@ -75,10 +76,12 @@ protected override void Awake()
gameObject.MMGetOrAddComponent();
gameObject.MMGetOrAddComponent();
gameObject.MMGetOrAddComponent();
+ gameObject.MMGetOrAddComponent().sharedMaterial =
+ CreateFrictionlessPhysicsMaterial();
handleWeapon = gameObject.MMGetOrAddComponent();
handleWeapon.InitialWeapon = initialWeapon;
handleWeapon.ForceWeaponAimControl = true;
- handleWeapon.ForcedWeaponAimControl = WeaponAim.AimControls.Off;
+ handleWeapon.ForcedWeaponAimControl = WeaponAim.AimControls.Script;
SetupDecisionsAndActions();
SetupAllyStates();
base.Awake();
@@ -86,12 +89,16 @@ protected override void Awake()
protected virtual void SetupDecisionsAndActions()
{
- detectPlayerDecision = CreateDetectTarget2DDecision(PLAYER_LAYER_INT, 20f);
+ detectPlayerDecision = CreateDetectTarget2DDecision(PLAYER_LAYER_INT, 100f, false);
detectEnemyDecision = CreateDetectTarget2DDecision(ENEMY_LAYER_INT, 20f);
distanceToTargetDecision = CreateDistanceToTarget2DDecision(
2f,
AIDecisionDistanceToTarget.ComparisonModes.LowerThan
);
+ distanceToTargetFarDecision = CreateDistanceToTarget2DDecision(
+ 4f,
+ AIDecisionDistanceToTarget.ComparisonModes.LowerThan
+ );
targetIsAliveDecision = CreateTargetIsAliveDecision();
timeInStateDecision = CreateTimeInStateDecision(2f, 2f);
}
@@ -137,7 +144,8 @@ private AIState CreateFollowPlayerState()
followState.Transitions = new AITransitionsList
{
- new AITransition() { Decision = detectEnemyDecision, TrueState = "ChaseEnemy" }
+ new AITransition() { Decision = detectEnemyDecision, TrueState = "ChaseEnemy" },
+ new AITransition() { Decision = distanceToTargetFarDecision, TrueState = "Idle" }
};
return followState;
@@ -168,10 +176,9 @@ private AIState CreateAttackState()
AIState attackState = new AIState();
attackState.StateName = "Attack";
- attackState.Actions = new AIActionsList()
- {
- gameObject.MMGetOrAddComponent()
- };
+ AIActionShoot2D aIActionShoot2D = gameObject.MMGetOrAddComponent();
+ aIActionShoot2D.AimAtTarget = true;
+ attackState.Actions = new AIActionsList() { aIActionShoot2D };
attackState.Transitions = new AITransitionsList
{
@@ -184,12 +191,14 @@ private AIState CreateAttackState()
private AIDecisionDetectTargetRadius2D CreateDetectTarget2DDecision(
int targetLayerInt,
- float radius
+ float radius,
+ bool obstacleDetection = true
)
{
AIDecisionDetectTargetRadius2D detectTargetDecision =
gameObject.AddComponent();
detectTargetDecision.TargetLayer = 1 << targetLayerInt;
+ detectTargetDecision.ObstacleDetection = obstacleDetection;
detectTargetDecision.Radius = radius;
return detectTargetDecision;
@@ -221,6 +230,11 @@ private AIDecisionTimeInState CreateTimeInStateDecision(float afterTimeMin, floa
return timeInState;
}
+ public PhysicsMaterial2D CreateFrictionlessPhysicsMaterial()
+ {
+ return new PhysicsMaterial2D() { friction = 0 };
+ }
+
// var AllyPlayer = null; So an empty hashmap (dictionary) of all "ally players"
// funnction -^ set the AllyPlayer via its ID.
}