diff --git a/code/__defines/text.dm b/code/__defines/text.dm
index b48754dd32..6885d859cb 100644
--- a/code/__defines/text.dm
+++ b/code/__defines/text.dm
@@ -11,3 +11,5 @@
/// Simply removes the < and > characters, and limits the length of the message.
#define STRIP_HTML_SIMPLE(text, limit) (GLOB.angular_brackets.Replace(copytext(text, 1, limit), ""))
+
+#define MAX_MESSAGE_CHUNKS 130
diff --git a/code/modules/tgui/tgui.dm b/code/modules/tgui/tgui.dm
index f337b41cdc..105db02945 100644
--- a/code/modules/tgui/tgui.dm
+++ b/code/modules/tgui/tgui.dm
@@ -45,6 +45,8 @@
var/datum/tgui/parent_ui
/// Children of this UI
var/list/children = list()
+ /// Any partial packets that we have received from TGUI, waiting to be sent
+ var/partial_packets
/**
* public
@@ -349,6 +351,28 @@
// Pass act type messages to tgui_act
if(type && copytext(type, 1, 5) == "act/")
var/act_type = copytext(type, 5)
+ var/id = href_list["packetId"]
+ if(!isnull(id))
+ id = text2num(id)
+
+ var/total = text2num(href_list["totalPackets"])
+ if(id == 1)
+ if(total > MAX_MESSAGE_CHUNKS)
+ return
+
+ partial_packets = new /list(total)
+
+ partial_packets[id] = href_list["packet"]
+
+ if(id != total)
+ return
+
+ var/assembled_payload = ""
+ for(var/packet in partial_packets)
+ assembled_payload += packet
+
+ payload = json_decode(assembled_payload)
+ partial_packets = null
#ifdef TGUI_DEBUGGING
log_tgui(user, "Action: [act_type] [href_list["payload"]], Window: [window.id], Source: [src_object]")
#endif
diff --git a/code/modules/tgui_input/say_modal/modal.dm b/code/modules/tgui_input/say_modal/modal.dm
index 17f229da49..ce48695ef3 100644
--- a/code/modules/tgui_input/say_modal/modal.dm
+++ b/code/modules/tgui_input/say_modal/modal.dm
@@ -31,6 +31,8 @@
var/datum/tgui_window/window
/// Boolean for whether the tgui_say was opened by the user.
var/window_open
+ /// Any partial packets that we have received from TGUI, waiting to be sent
+ var/partial_packets
/** Creates the new input window to exist in the background. */
/datum/tgui_say/New(client/client, id)
@@ -64,14 +66,14 @@
/datum/tgui_say/proc/load()
window_open = FALSE
- var/minimum_height = client?.prefs?.read_preference(/datum/preference/numeric/tgui_say_height) || 1
- var/minimu_width = client?.prefs?.read_preference(/datum/preference/numeric/tgui_say_width) || 1
+ var/minimum_width = client?.prefs?.read_preference(/datum/preference/numeric/tgui_say_width) || 1
+ var/minimum_height = (client?.prefs?.read_preference(/datum/preference/numeric/tgui_say_height) || 1) * 20 + 10
winset(client, "tgui_say", "pos=410,400;size=360,30;is-visible=0;")
window.send_message("props", list(
lightMode = client?.prefs?.read_preference(/datum/preference/toggle/tgui_say_light),
+ minimumWidth = minimum_width,
minimumHeight = minimum_height,
- minimumWidth = minimu_width,
maxLength = max_length,
))
@@ -106,7 +108,7 @@
* The equivalent of ui_act, this waits on messages from the window
* and delegates actions.
*/
-/datum/tgui_say/proc/on_message(type, payload)
+/datum/tgui_say/proc/on_message(type, payload, href_list)
if(type == "ready")
load()
return TRUE
@@ -128,6 +130,28 @@
start_typing(payload["channel"])
return TRUE
if(type == "entry" || type == "force")
+ var/id = href_list["packetId"]
+ if(!isnull(id))
+ id = text2num(id)
+
+ var/total = text2num(href_list["totalPackets"])
+ if(id == 1)
+ if(total > MAX_MESSAGE_CHUNKS)
+ return
+
+ partial_packets = new /list(total)
+
+ partial_packets[id] = href_list["packet"]
+
+ if(id != total)
+ return
+
+ var/assembled_payload = ""
+ for(var/packet in partial_packets)
+ assembled_payload += packet
+
+ payload = json_decode(assembled_payload)
+ partial_packets = null
handle_entry(type, payload)
return TRUE
if(type == "lenwarn")
diff --git a/code/modules/tgui_input/text.dm b/code/modules/tgui_input/text.dm
index a4a7f080a5..b1b02e2052 100644
--- a/code/modules/tgui_input/text.dm
+++ b/code/modules/tgui_input/text.dm
@@ -15,7 +15,7 @@
* * encode - Toggling this determines if input is filtered via html_encode. Setting this to FALSE gives raw input.
* * timeout - The timeout of the textbox, after which the modal will close and qdel itself. Set to zero for no timeout.
*/
-/proc/tgui_input_text(mob/user, message = "", title = "Text Input", default, max_length = INFINITY, multiline = FALSE, encode = FALSE, timeout = 0, prevent_enter = FALSE)
+/proc/tgui_input_text(mob/user, message = "", title = "Text Input", default, max_length = 130000, multiline = FALSE, encode = FALSE, timeout = 0, prevent_enter = FALSE) // 130k limit due to chunking limit... if we need longer that needs fixing
if (!user)
user = usr
if (!istype(user))
diff --git a/tgui/packages/tgui-panel/styles/components/Ping.scss b/tgui/packages/tgui-panel/styles/components/Ping.scss
index 251b0fd953..b3796c343d 100644
--- a/tgui/packages/tgui-panel/styles/components/Ping.scss
+++ b/tgui/packages/tgui-panel/styles/components/Ping.scss
@@ -14,6 +14,7 @@ $border-color: rgba(140, 140, 140, 0.5) !default;
border-radius: 0.25em;
width: 3.75em;
text-align: right;
+ user-select: 'none';
}
.Ping__indicator {
diff --git a/tgui/packages/tgui-say/TguiSay.tsx b/tgui/packages/tgui-say/TguiSay.tsx
index 2d93c4b835..ffa9c74355 100644
--- a/tgui/packages/tgui-say/TguiSay.tsx
+++ b/tgui/packages/tgui-say/TguiSay.tsx
@@ -20,6 +20,8 @@ import { byondMessages } from './timers';
type ByondOpen = {
channel: Channel;
+ minimumWidth: number;
+ minimumHeight: number;
};
type ByondProps = {
@@ -287,8 +289,8 @@ export function TguiSay() {
function handleOpen(data: ByondOpen): void {
setTimeout(() => {
innerRef.current?.focus();
- windowSet(WindowSize.Width, WindowSize.Small);
- setSize(WindowSize.Width);
+ setSize(minimumHeight);
+ windowSet(minimumWidth, minimumHeight);
}, 1);
const { channel } = data;
@@ -339,7 +341,7 @@ export function TguiSay() {
} else {
newSize = WindowSize.Small;
}
- newSize = clamp(newSize, minimumHeight * 20 + 10, WindowSize.Max);
+ newSize = clamp(newSize, minimumHeight, WindowSize.Max);
if (size !== newSize) {
setSize(newSize);
@@ -370,16 +372,24 @@ export function TguiSay() {
{buttonContent}
+
>
);
diff --git a/tgui/packages/tgui-say/styles/styles.scss b/tgui/packages/tgui-say/styles/styles.scss
index 7f561ba4e4..71f2e06e88 100644
--- a/tgui/packages/tgui-say/styles/styles.scss
+++ b/tgui/packages/tgui-say/styles/styles.scss
@@ -118,7 +118,7 @@
background-color: black;
display: grid;
font: 'tgfont';
- grid-template-columns: 3.5rem 1fr;
+ grid-template-columns: 7rem 1fr 2rem;
inset: 2px;
overflow: hidden;
padding: 2px;
diff --git a/tgui/packages/tgui/constants.ts b/tgui/packages/tgui/constants.ts
index 909f804179..6884549cd9 100644
--- a/tgui/packages/tgui/constants.ts
+++ b/tgui/packages/tgui/constants.ts
@@ -33,6 +33,7 @@ export const COLORS = {
science: '#9b59b6',
engineering: '#f1c40f',
cargo: '#f39c12',
+ service: '#7cc46a',
centcom: '#00c100',
other: '#c38312',
},
@@ -66,24 +67,28 @@ export const COLORS = {
// Colors defined in CSS
export const CSS_COLORS = [
- 'black',
- 'white',
- 'red',
- 'orange',
- 'yellow',
- 'olive',
- 'green',
- 'teal',
- 'blue',
- 'violet',
- 'purple',
- 'pink',
- 'brown',
- 'grey',
- 'good',
'average',
'bad',
+ 'black',
+ 'blue',
+ 'brown',
+ 'darkgray',
+ 'darkgreen',
+ 'maroon',
+ 'good',
+ 'green',
+ 'grey',
'label',
+ 'olive',
+ 'orange',
+ 'pink',
+ 'purple',
+ 'red',
+ 'teal',
+ 'transparent',
+ 'violet',
+ 'white',
+ 'yellow',
];
// VOREStation Edit Start
diff --git a/tgui/packages/tgui/interfaces/common/RankIcon.tsx b/tgui/packages/tgui/interfaces/common/RankIcon.tsx
index 67746ffa37..6d51fecc20 100644
--- a/tgui/packages/tgui/interfaces/common/RankIcon.tsx
+++ b/tgui/packages/tgui/interfaces/common/RankIcon.tsx
@@ -591,10 +591,10 @@ const rank2color = {
'Off-duty Explorer': 'white',
'Off-duty Worker': 'white',
// AI / Robot
- AI: 'darkgrey',
- Cyborg: 'darkgrey',
- Robot: 'darkgrey',
- Drone: 'darkgrey',
+ AI: 'maroon',
+ Cyborg: 'maroon',
+ Robot: 'maroon',
+ Drone: 'maroon',
// Clown / Mime
Clown: 'green',
Jester: 'green',
@@ -627,11 +627,11 @@ const rank2color = {
Security: 'red',
Combat: 'yellow',
Engineering: 'orange',
- Gravekeeper: 'dark-grey',
+ Gravekeeper: 'maroon',
Lost: 'grey',
- Protector: 'darkred',
- Mechanist: 'darkred',
- 'Combat Medic': 'darkred',
+ Protector: 'maroon',
+ Mechanist: 'maroon',
+ 'Combat Medic': 'maroon',
};
type rank_icon = { rank: string; color: string };
diff --git a/tgui/public/tgui.html b/tgui/public/tgui.html
index 87b07c7d42..2f1138b602 100644
--- a/tgui/public/tgui.html
+++ b/tgui/public/tgui.html
@@ -204,7 +204,25 @@
// JSON-encode the payload
if (message.payload !== null && message.payload !== undefined) {
message.payload = JSON.stringify(message.payload);
+
+ if(!Byond.TRIDENT && message.payload.length > 1024) {
+ var chunks = [];
+
+ for(var i = 0, charsLength = message.payload.length; i < charsLength; i += 1024) {
+ chunks.push(message.payload.substring(i, i + 1024))
+ }
+
+ for(var i = 0; i < chunks.length; i++) {
+ var to_send = chunks[i]
+
+ message = { type: type, packet: to_send, packetId: i + 1, totalPackets: chunks.length, tgui: 1, window_id: Byond.windowId };
+ Byond.topic(message);
+ }
+
+ return;
+ }
}
+
// Append an identifying header
assign(message, {
tgui: 1,
diff --git a/tools/build/build.js b/tools/build/build.js
index 29169441e8..4a8eee2d84 100644
--- a/tools/build/build.js
+++ b/tools/build/build.js
@@ -152,6 +152,7 @@ export const IconCutterTarget = new Juke.Target({
'icons/**/*.png',
`icons/**/*${CUTTER_SUFFIX}`,
`cutter_templates/**/*${CUTTER_SUFFIX}`,
+ `tgui/public/tgui.html`,
cutter_path,
],
outputs: ({ get }) => {