mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-14 16:44:33 +01:00
Adds a basic AI controller info panel to VV. (#29898)
This commit is contained in:
committed by
GitHub
parent
06f19cdecb
commit
2a81f86af7
@@ -45,6 +45,7 @@
|
||||
#define VV_HK_EDITREAGENTS "editreagents"
|
||||
#define VV_HK_EXPLODE "explode"
|
||||
#define VV_HK_EMP "emp"
|
||||
#define VV_HK_DEBUG_AI_CONTROLLER "debug_ai_controller"
|
||||
|
||||
// /obj
|
||||
#define VV_HK_DELALL "delall"
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
VV_DROPDOWN_OPTION(VV_HK_EDITREAGENTS, "Edit reagents")
|
||||
VV_DROPDOWN_OPTION(VV_HK_EXPLODE, "Trigger explosion")
|
||||
VV_DROPDOWN_OPTION(VV_HK_EMP, "Trigger EM pulse")
|
||||
if(istype(ai_controller))
|
||||
VV_DROPDOWN_OPTION(VV_HK_DEBUG_AI_CONTROLLER, "Debug AI Controller")
|
||||
|
||||
/atom/proc/vv_modify_name_link()
|
||||
return "byond://?_src_=vars;datumedit=[UID()];varnameedit=name"
|
||||
@@ -100,3 +102,14 @@
|
||||
message_admins("[key_name_admin(usr)] is manipulating the colour matrix for [src]")
|
||||
var/datum/ui_module/colour_matrix_tester/CMT = new(target=src)
|
||||
CMT.ui_interact(usr)
|
||||
|
||||
if(href_list[VV_HK_DEBUG_AI_CONTROLLER])
|
||||
if(!check_rights(R_DEBUG|R_DEV_TEAM))
|
||||
return
|
||||
|
||||
if(!istype(ai_controller))
|
||||
to_chat(usr, "Could not find atom [href_list[VV_HK_DEBUG_AI_CONTROLLER]] with AI controller")
|
||||
return
|
||||
|
||||
var/datum/ui_module/ai_controller_debugger/debugger = new(ai_controller)
|
||||
debugger.ui_interact(usr)
|
||||
|
||||
@@ -1305,3 +1305,23 @@ GLOBAL_LIST_INIT(view_logs_verbs, list(
|
||||
|
||||
B.to_backup_disk(get_turf(usr))
|
||||
|
||||
/proc/ghost_follow_uid(mob/user, uid)
|
||||
var/client/client = user.client
|
||||
if(!isobserver(user))
|
||||
if(!check_rights(R_ADMIN|R_MOD)) // Need to be mod or admin to aghost
|
||||
return
|
||||
user.client.admin_ghost()
|
||||
var/datum/target = locateUID(uid)
|
||||
if(QDELETED(target))
|
||||
to_chat(user, "<span class='warning'>This datum has been deleted!</span>")
|
||||
return
|
||||
|
||||
if(istype(target, /datum/mind))
|
||||
var/datum/mind/mind = target
|
||||
if(!ismob(mind.current))
|
||||
to_chat(user, "<span class='warning'>This can only be used on instances of type /mob</span>")
|
||||
return
|
||||
target = mind.current
|
||||
|
||||
var/mob/dead/observer/A = client.mob
|
||||
A.ManualFollow(target)
|
||||
|
||||
@@ -149,25 +149,7 @@ RESTRICT_TYPE(/datum/ui_module/admin/antagonist_menu)
|
||||
if("pm")
|
||||
ui.user.client.cmd_admin_pm(params["ckey"], null)
|
||||
if("follow")
|
||||
var/client/C = ui.user.client
|
||||
if(!isobserver(ui.user))
|
||||
if(!check_rights(R_ADMIN|R_MOD)) // Need to be mod or admin to aghost
|
||||
return
|
||||
C.admin_ghost()
|
||||
var/datum/target = locateUID(params["datum_uid"])
|
||||
if(QDELETED(target))
|
||||
to_chat(ui.user, "<span class='warning'>This datum has been deleted!</span>")
|
||||
return
|
||||
|
||||
if(istype(target, /datum/mind))
|
||||
var/datum/mind/mind = target
|
||||
if(!ismob(mind.current))
|
||||
to_chat(ui.user, "<span class='warning'>This can only be used on instances of type /mob</span>")
|
||||
return
|
||||
target = mind.current
|
||||
|
||||
var/mob/dead/observer/A = C.mob
|
||||
A.ManualFollow(target)
|
||||
ghost_follow_uid(ui.user, params["datum_uid"])
|
||||
if("obs")
|
||||
var/client/C = ui.user.client
|
||||
var/datum/mind/mind = locateUID(params["mind_uid"])
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
/datum/ui_module/ai_controller_debugger
|
||||
name = "AI Controller Debugger"
|
||||
var/datum/ai_controller/controller
|
||||
var/paused = FALSE
|
||||
var/list/data = list()
|
||||
|
||||
/datum/ui_module/ai_controller_debugger/New(datum/ai_controller/controller_)
|
||||
..()
|
||||
if(!istype(controller_))
|
||||
stack_trace("Attempted to create an AI controller debugger on an invalid target!")
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
controller = controller_
|
||||
|
||||
/datum/ui_module/ai_controller_debugger/ui_state(mob/user)
|
||||
return GLOB.admin_state
|
||||
|
||||
/datum/ui_module/ai_controller_debugger/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "AIControllerDebugger", name)
|
||||
ui_data(user)
|
||||
ui.open()
|
||||
|
||||
/datum/ui_module/ai_controller_debugger/ui_data(mob/user)
|
||||
data["paused"] = paused
|
||||
if(paused)
|
||||
return data
|
||||
|
||||
data["controller"] = list(
|
||||
"type" = "[controller.type]",
|
||||
"current_behaviors" = list(),
|
||||
"planned_behaviors" = list(),
|
||||
"blackboard" = list(),
|
||||
)
|
||||
if(controller.pawn)
|
||||
data["controller"]["pawn"] = list(
|
||||
"name" = "[controller.pawn]",
|
||||
"uid" = controller.pawn.UID(),
|
||||
)
|
||||
data["controller"]["type"] = "[controller.type]"
|
||||
data["controller"]["idle_behavior"] = "[controller.idle_behavior]"
|
||||
data["controller"]["movement"] = "[controller.ai_movement]"
|
||||
var/datum/movement_target = controller.current_movement_target
|
||||
if(istype(movement_target))
|
||||
data["controller"]["movement_target"] = list(
|
||||
"name" = "[movement_target]",
|
||||
"uid" = "[movement_target.UID()]",
|
||||
"source" = "[controller.movement_target_source]",
|
||||
)
|
||||
if(LAZYLEN(controller.current_behaviors))
|
||||
for(var/datum/ai_behavior/behavior in controller.current_behaviors)
|
||||
data["controller"]["current_behaviors"] += "[behavior.type]"
|
||||
|
||||
if(LAZYLEN(controller.planned_behaviors))
|
||||
for(var/datum/ai_behavior/behavior in controller.planned_behaviors)
|
||||
data["controller"]["planned_behaviors"] += "[behavior.type]"
|
||||
|
||||
for(var/name in controller.blackboard)
|
||||
var/value = controller.blackboard[name]
|
||||
|
||||
var/list/item = list(
|
||||
"name" = name,
|
||||
"value" = "[value]",
|
||||
)
|
||||
var/datum/valid_uid = locateUID(value)
|
||||
if(istype(valid_uid))
|
||||
item["uid"] = value
|
||||
if(isdatum(value))
|
||||
var/datum/D = value
|
||||
item["uid"] = D.UID()
|
||||
if(islist(value))
|
||||
item["value"] = json_encode(value)
|
||||
data["controller"]["blackboard"] += list(item)
|
||||
return data
|
||||
|
||||
/datum/ui_module/ai_controller_debugger/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
|
||||
if(..())
|
||||
return
|
||||
|
||||
switch(action)
|
||||
if("vv")
|
||||
ui.user.client.debug_variables(locateUID(params["uid"]))
|
||||
if("flw")
|
||||
ghost_follow_uid(ui.user, params["uid"])
|
||||
|
||||
return TRUE
|
||||
@@ -3180,6 +3180,7 @@
|
||||
#include "code\modules\tgui\states.dm"
|
||||
#include "code\modules\tgui\tgui_datum.dm"
|
||||
#include "code\modules\tgui\tgui_window.dm"
|
||||
#include "code\modules\tgui\modules\ai_controller_debugger.dm"
|
||||
#include "code\modules\tgui\modules\appearance_changer.dm"
|
||||
#include "code\modules\tgui\modules\atmos_control.dm"
|
||||
#include "code\modules\tgui\modules\colour_matrix_tester.dm"
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
import { ReactNode } from 'react';
|
||||
import { Box, Button, Flex, LabeledList, NoticeBox, Section, Stack, Table, Tabs, Tooltip } from 'tgui-core/components';
|
||||
import { BooleanLike } from 'tgui-core/react';
|
||||
|
||||
import { useBackend } from '../backend';
|
||||
import { Window } from '../layouts';
|
||||
import { truncate } from 'lodash';
|
||||
|
||||
interface AIControllerDebuggerData {
|
||||
controller: AIController;
|
||||
}
|
||||
|
||||
interface ObjRef {
|
||||
name: string;
|
||||
uid: string;
|
||||
}
|
||||
|
||||
interface AIController {
|
||||
type: string;
|
||||
pawn?: ObjRef;
|
||||
idle_behavior: string;
|
||||
movement: string;
|
||||
movement_target?: MovementTarget;
|
||||
current_behaviors: string[];
|
||||
planned_behaviors: string[];
|
||||
blackboard: BlackboardItem[];
|
||||
}
|
||||
|
||||
interface MovementTarget extends ObjRef {
|
||||
source: string;
|
||||
}
|
||||
|
||||
interface BlackboardItem {
|
||||
name: string;
|
||||
value: string;
|
||||
uid?: string;
|
||||
}
|
||||
|
||||
export const CopyableValue = ({ text }) => {
|
||||
return (
|
||||
<>
|
||||
<Button icon="clipboard-list" onClick={() => navigator.clipboard.writeText(text)} />
|
||||
<span style={{ fontFamily: 'monospace' }}>{text}</span>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const ObjectReference = (props: { obj_ref: ObjRef }) => {
|
||||
const { act } = useBackend();
|
||||
const { obj_ref } = props;
|
||||
return (
|
||||
<>
|
||||
<Button onClick={() => act('vv', { uid: obj_ref.uid })}>VV</Button>
|
||||
<Button onClick={() => act('flw', { uid: obj_ref.uid })}>FLW</Button>
|
||||
{obj_ref.name}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const AIControllerDebugger = (props) => {
|
||||
const { data, act } = useBackend<AIControllerDebuggerData>();
|
||||
const { controller } = data;
|
||||
return (
|
||||
<Window width={675} height={600}>
|
||||
<Window.Content scrollable>
|
||||
<Stack fill vertical>
|
||||
<Section title="Basic Info">
|
||||
<Table>
|
||||
{controller.pawn && (
|
||||
<Table.Row>
|
||||
<Table.Cell>Pawn</Table.Cell>
|
||||
<Table.Cell>
|
||||
<ObjectReference obj_ref={controller.pawn} />
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
)}
|
||||
<Table.Row>
|
||||
<Table.Cell>Type</Table.Cell>
|
||||
<Table.Cell>
|
||||
<CopyableValue text={controller.type} />
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
<Table.Cell>Idle Behavior</Table.Cell>
|
||||
<Table.Cell>
|
||||
<CopyableValue text={controller.idle_behavior} />
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
<Table.Cell>Movement</Table.Cell>
|
||||
<Table.Cell>
|
||||
<CopyableValue text={controller.movement} />
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
{controller.movement_target && (
|
||||
<>
|
||||
<Table.Row>
|
||||
<Table.Cell>Movement Target</Table.Cell>
|
||||
<Table.Cell>
|
||||
<ObjectReference obj_ref={controller.movement_target} />
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
<Table.Cell>Target Source</Table.Cell>
|
||||
<Table.Cell>
|
||||
<CopyableValue text={controller.movement_target.source} />
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
</>
|
||||
)}
|
||||
</Table>
|
||||
</Section>
|
||||
<Section title="Blackboard">
|
||||
<Table className="AIControllerDebugger__Blackboard">
|
||||
{controller.blackboard.map((blackboard_item) => (
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
{blackboard_item.name.length > 30 ? (
|
||||
<Tooltip content={blackboard_item.name}>
|
||||
<Box>{truncate(blackboard_item.name)}</Box>
|
||||
</Tooltip>
|
||||
) : (
|
||||
blackboard_item.name
|
||||
)}
|
||||
</Table.Cell>
|
||||
<Table.Cell className="bb_value">
|
||||
{blackboard_item.uid && (
|
||||
<>
|
||||
<Button onClick={() => act('vv', { uid: blackboard_item.uid })}>VV</Button>
|
||||
<Button onClick={() => act('flw', { uid: blackboard_item.uid })}>FLW</Button>
|
||||
|
||||
</>
|
||||
)}
|
||||
{blackboard_item.value || 'null'}
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
))}
|
||||
</Table>
|
||||
</Section>
|
||||
<Section title="Current Behaviors">
|
||||
<Table>
|
||||
{controller.current_behaviors.map((behavior) => (
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
<CopyableValue text={behavior} />
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
))}
|
||||
</Table>
|
||||
</Section>
|
||||
<Section title="Planned Behaviors">
|
||||
<Table>
|
||||
{controller.planned_behaviors.map((behavior) => (
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
<CopyableValue text={behavior} />
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
))}
|
||||
</Table>
|
||||
</Section>
|
||||
</Stack>
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
@@ -10,6 +10,7 @@
|
||||
"highlight.js": "^11.10.0",
|
||||
"jest": "^29.7.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"lodash": "^4.17.21",
|
||||
"marked": "^4.3.0",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
@@ -17,6 +18,7 @@
|
||||
"tgui-dev-server": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/lodash": "^4.17.20",
|
||||
"@types/marked": "4.3.2",
|
||||
"@types/react": "^19.1.3",
|
||||
"@types/react-dom": "^19.1.3",
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
.AIControllerDebugger__Blackboard {
|
||||
.Table__row:nth-child(odd) {
|
||||
background-color: #222;
|
||||
}
|
||||
}
|
||||
|
||||
.bb_value {
|
||||
vertical-align: top;
|
||||
overflow-wrap: break-word;
|
||||
text-wrap: wrap;
|
||||
word-wrap: break-word;
|
||||
-ms-word-break: break-all;
|
||||
word-break: break-all;
|
||||
display: inline-block;
|
||||
}
|
||||
@@ -26,6 +26,7 @@
|
||||
// Interfaces
|
||||
@include meta.load-css('./interfaces/AccountsUplinkTerminal.scss');
|
||||
@include meta.load-css('./interfaces/AdminAntagMenu.scss');
|
||||
@include meta.load-css('./interfaces/AIControllerDebugger.scss');
|
||||
@include meta.load-css('./interfaces/AlertModal.scss');
|
||||
@include meta.load-css('./interfaces/BrigCells.scss');
|
||||
@include meta.load-css('./interfaces/CameraConsole.scss');
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -3905,6 +3905,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/lodash@npm:^4.17.20":
|
||||
version: 4.17.20
|
||||
resolution: "@types/lodash@npm:4.17.20"
|
||||
checksum: 10c0/98cdd0faae22cbb8079a01a3bb65aa8f8c41143367486c1cbf5adc83f16c9272a2a5d2c1f541f61d0d73da543c16ee1d21cf2ef86cb93cd0cc0ac3bced6dd88f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/marked@npm:4.3.2":
|
||||
version: 4.3.2
|
||||
resolution: "@types/marked@npm:4.3.2"
|
||||
@@ -19314,6 +19321,7 @@ __metadata:
|
||||
version: 0.0.0-use.local
|
||||
resolution: "tgui@workspace:packages/tgui"
|
||||
dependencies:
|
||||
"@types/lodash": "npm:^4.17.20"
|
||||
"@types/marked": "npm:4.3.2"
|
||||
"@types/react": "npm:^19.1.3"
|
||||
"@types/react-dom": "npm:^19.1.3"
|
||||
@@ -19324,6 +19332,7 @@ __metadata:
|
||||
highlight.js: "npm:^11.10.0"
|
||||
jest: "npm:^29.7.0"
|
||||
js-yaml: "npm:^4.1.0"
|
||||
lodash: "npm:^4.17.21"
|
||||
marked: "npm:^4.3.0"
|
||||
react: "npm:^19.1.0"
|
||||
react-dom: "npm:^19.1.0"
|
||||
|
||||
Reference in New Issue
Block a user