diff --git a/.github/workflows/auto_changelog.yml b/.github/workflows/auto_changelog.yml
index c1fcf82e76890..45303ec0c92af 100644
--- a/.github/workflows/auto_changelog.yml
+++ b/.github/workflows/auto_changelog.yml
@@ -11,7 +11,7 @@ permissions:
jobs:
auto_changelog:
runs-on: ubuntu-latest
- if: github.event.pull_request.merged == true && github.head_ref != 'merge-upstream'
+ if: github.event.pull_request.merged == true
steps:
- name: Checkout
uses: actions/checkout@v4
diff --git a/.github/workflows/compile_changelogs.yml b/.github/workflows/compile_changelogs.yml
index aaf01306a806e..902791316452c 100644
--- a/.github/workflows/compile_changelogs.yml
+++ b/.github/workflows/compile_changelogs.yml
@@ -44,7 +44,7 @@ jobs:
- name: "Compile"
if: steps.value_holder.outputs.ACTIONS_ENABLED
run: |
- python tools/ss13_genchangelog.py html/changelogs
+ python tools/ss13_genchangelog.py html/changelogs/bandastation
- name: Commit
if: steps.value_holder.outputs.ACTIONS_ENABLED
@@ -52,7 +52,7 @@ jobs:
git config --local user.name "tgstation-ci[bot]"
git config --local user.email "179393467+tgstation-ci[bot]@users.noreply.github.com"
git pull origin master
- git add html/changelogs
+ git add html/changelogs/bandastation
git commit -m "Automatic changelog compile [ci skip]" -a || true
- name: Generate App Token
diff --git a/html/changelogs/bandastation/archive/2025-01.yml b/html/changelogs/bandastation/archive/2025-01.yml
new file mode 100644
index 0000000000000..beec62969a6a8
--- /dev/null
+++ b/html/changelogs/bandastation/archive/2025-01.yml
@@ -0,0 +1,3 @@
+2025-01-18:
+ AyIong:
+ - bugfix: Лейтджоин ИИ, больше не будут смотреть на лобби арт и общаться IC
diff --git a/modular_bandastation/changelog/_changelog.dm b/modular_bandastation/changelog/_changelog.dm
new file mode 100644
index 0000000000000..b9a97b6aa02e6
--- /dev/null
+++ b/modular_bandastation/changelog/_changelog.dm
@@ -0,0 +1,8 @@
+/datum/modpack/changelog
+ name = "Чейнджлог"
+ desc = "Кастомизация чейнджлога BandaStation."
+ author = "Maxiemar"
+
+/datum/modpack/changelog/initialize()
+ var/latest_changelog = file("[global.config.directory]/../html/changelogs/bandastation/archive/" + time2text(world.timeofday, "YYYY-MM") + ".yml")
+ GLOB.changelog_hash = fexists(latest_changelog) ? md5(latest_changelog) : 0 //for telling if the changelog has changed recently
diff --git a/modular_bandastation/changelog/_changelog.dme b/modular_bandastation/changelog/_changelog.dme
new file mode 100644
index 0000000000000..9e591e9595295
--- /dev/null
+++ b/modular_bandastation/changelog/_changelog.dme
@@ -0,0 +1,4 @@
+#include "_changelog.dm"
+
+#include "code/changelog.dm"
+#include "code/changelog_item.dm"
diff --git a/modular_bandastation/changelog/code/changelog.dm b/modular_bandastation/changelog/code/changelog.dm
new file mode 100644
index 0000000000000..5a2f97cdef778
--- /dev/null
+++ b/modular_bandastation/changelog/code/changelog.dm
@@ -0,0 +1,15 @@
+/datum/changelog/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if (!ui)
+ ui = new(user, src, "ChangelogBandaStation")
+ ui.open()
+
+/datum/changelog/ui_static_data()
+ var/list/data = list("dates" = list())
+ var/static/regex/yml_regex = regex(@"\.yml", "g")
+
+ for(var/archive_file in sort_list(flist("html/changelogs/bandastation/archive/")))
+ var/archive_date = yml_regex.Replace(archive_file, "")
+ data["dates"] = list(archive_date) + data["dates"]
+
+ return data
diff --git a/modular_bandastation/changelog/code/changelog_item.dm b/modular_bandastation/changelog/code/changelog_item.dm
new file mode 100644
index 0000000000000..266ac6cedb4d6
--- /dev/null
+++ b/modular_bandastation/changelog/code/changelog_item.dm
@@ -0,0 +1,3 @@
+/datum/asset/changelog_item/New(date)
+ item_filename = SANITIZE_FILENAME("[date].yml")
+ SSassets.transport.register_asset(item_filename, file("html/changelogs/bandastation/archive/" + item_filename))
diff --git a/modular_bandastation/modular_bandastation.dme b/modular_bandastation/modular_bandastation.dme
index 057aa3a0243dd..f171704432e88 100644
--- a/modular_bandastation/modular_bandastation.dme
+++ b/modular_bandastation/modular_bandastation.dme
@@ -16,6 +16,7 @@
#include "autohiss/_autohiss.dme"
#include "balance/_balance.dme"
#include "barsigns/_barsigns.dme"
+#include "changelog/_changelog.dme"
#include "chat_badges/_chat_badges.dme"
#include "communication/_communication.dme"
#include "customization/_customization.dme"
diff --git a/tgui/packages/tgui/interfaces/ChangelogBandaStation.jsx b/tgui/packages/tgui/interfaces/ChangelogBandaStation.jsx
new file mode 100644
index 0000000000000..c9f84a1e04538
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/ChangelogBandaStation.jsx
@@ -0,0 +1,388 @@
+import dateformat from 'dateformat';
+import yaml from 'js-yaml';
+import { Component, Fragment } from 'react';
+import {
+ Box,
+ Button,
+ Dropdown,
+ Icon,
+ Section,
+ Stack,
+ Table,
+} from 'tgui-core/components';
+import { classes } from 'tgui-core/react';
+
+import { resolveAsset } from '../assets';
+import { useBackend } from '../backend';
+import { Window } from '../layouts';
+
+const icons = {
+ add: { icon: 'check-circle', color: 'green' },
+ admin: { icon: 'user-shield', color: 'purple' },
+ balance: { icon: 'balance-scale-right', color: 'yellow' },
+ bugfix: { icon: 'bug', color: 'green' },
+ code_imp: { icon: 'code', color: 'green' },
+ config: { icon: 'cogs', color: 'purple' },
+ expansion: { icon: 'check-circle', color: 'green' },
+ experiment: { icon: 'radiation', color: 'yellow' },
+ image: { icon: 'image', color: 'green' },
+ imageadd: { icon: 'tg-image-plus', color: 'green' },
+ imagedel: { icon: 'tg-image-minus', color: 'red' },
+ qol: { icon: 'hand-holding-heart', color: 'green' },
+ refactor: { icon: 'tools', color: 'green' },
+ rscadd: { icon: 'check-circle', color: 'green' },
+ rscdel: { icon: 'times-circle', color: 'red' },
+ server: { icon: 'server', color: 'purple' },
+ sound: { icon: 'volume-high', color: 'green' },
+ soundadd: { icon: 'tg-sound-plus', color: 'green' },
+ sounddel: { icon: 'tg-sound-minus', color: 'red' },
+ spellcheck: { icon: 'spell-check', color: 'green' },
+ map: { icon: 'map', color: 'green' },
+ tgs: { icon: 'toolbox', color: 'purple' },
+ tweak: { icon: 'wrench', color: 'green' },
+ unknown: { icon: 'info-circle', color: 'label' },
+ wip: { icon: 'hammer', color: 'orange' },
+};
+
+export class ChangelogBandaStation extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ data: 'Loading changelog data...',
+ selectedDate: '',
+ selectedIndex: 0,
+ };
+ this.dateChoices = [];
+ }
+
+ setData(data) {
+ this.setState({ data });
+ }
+
+ setSelectedDate(selectedDate) {
+ this.setState({ selectedDate });
+ }
+
+ setSelectedIndex(selectedIndex) {
+ this.setState({ selectedIndex });
+ }
+
+ getData = (date, attemptNumber = 1) => {
+ const { act } = useBackend();
+ const self = this;
+ const maxAttempts = 6;
+
+ if (attemptNumber > maxAttempts) {
+ return this.setData(
+ 'Failed to load data after ' + maxAttempts + ' attempts',
+ );
+ }
+
+ act('get_month', { date });
+
+ fetch(resolveAsset(date + '.yml')).then(async (changelogData) => {
+ const result = await changelogData.text();
+ const errorRegex = /^Cannot find/;
+
+ if (errorRegex.test(result)) {
+ const timeout = 50 + attemptNumber * 50;
+
+ self.setData('Loading changelog data' + '.'.repeat(attemptNumber + 3));
+ setTimeout(() => {
+ self.getData(date, attemptNumber + 1);
+ }, timeout);
+ } else {
+ self.setData(yaml.load(result, { schema: yaml.CORE_SCHEMA }));
+ }
+ });
+ };
+
+ componentDidMount() {
+ const {
+ data: { dates = [] },
+ } = useBackend();
+
+ if (dates) {
+ dates.forEach((date) =>
+ this.dateChoices.push(dateformat(date, 'mmmm yyyy', true)),
+ );
+ this.setSelectedDate(this.dateChoices[0]);
+ this.getData(dates[0]);
+ }
+ }
+
+ render() {
+ const { data, selectedDate, selectedIndex } = this.state;
+ const {
+ data: { dates },
+ } = useBackend();
+ const { dateChoices } = this;
+
+ const dateDropdown = dateChoices.length > 0 && (
+
+
+ {
+ const index = selectedIndex - 1;
+
+ this.setData('Loading changelog data...');
+ this.setSelectedIndex(index);
+ this.setSelectedDate(dateChoices[index]);
+ window.scrollTo(
+ 0,
+ document.body.scrollHeight ||
+ document.documentElement.scrollHeight,
+ );
+ return this.getData(dates[index]);
+ }}
+ />
+
+
+ {
+ const index = dateChoices.indexOf(value);
+
+ this.setData('Loading changelog data...');
+ this.setSelectedIndex(index);
+ this.setSelectedDate(value);
+ window.scrollTo(
+ 0,
+ document.body.scrollHeight ||
+ document.documentElement.scrollHeight,
+ );
+ return this.getData(dates[index]);
+ }}
+ selected={selectedDate}
+ width="150px"
+ />
+
+
+ {
+ const index = selectedIndex + 1;
+
+ this.setData('Loading changelog data...');
+ this.setSelectedIndex(index);
+ this.setSelectedDate(dateChoices[index]);
+ window.scrollTo(
+ 0,
+ document.body.scrollHeight ||
+ document.documentElement.scrollHeight,
+ );
+ return this.getData(dates[index]);
+ }}
+ />
+
+
+ );
+
+ const header = (
+
+ Space Station 13 | BandaStation
+
+ Чейнджлог билда Space Station 13 BandaStation . Изменения,
+ относящиеся к родительскому проекту - Traditional Games (TG) -
+ сгруппированы и отмечены здесь авторством tgstation. Действительные
+ псевдонимы и имена авторов изменений можно найти
+ здесь . Все иные
+ изменения имеют непосредственное отношение к проекту BandaStation и
+ имеют сведения об их авторах.
+
+
+ {'Текущие мейнтейнеры проекта перечислены '}
+
+ здесь
+
+ {', недавние контрибьюторы проекта отмечены '}
+
+ тут
+
+ .
+
+ {dateDropdown}
+
+ );
+
+ const footer_tg = (
+
+ Traditional Games Space Station 13
+
+ Thanks to:
+ Baystation 12, /vg/station, NTstation, CDK Station devs,
+ FacepunchStation, GoonStation devs, the original Space Station 13
+ developers, Invisty for the title image and the countless others who
+ have contributed to the game, issue tracker or wiki over the years.
+
+
+ {'Current organization members can be found '}
+ here
+ {', recent GitHub contributors can be found '}
+
+ here
+
+ .
+
+
+ {'You can also join our discord '}
+ here .
+
+
+ );
+
+ const footer_goon = (
+
+ GoonStation 13 Development Team
+
+ Coders:
+ Stuntwaffle, Showtime, Pantaloons, Nannek, Keelin, Exadv1, hobnob,
+ Justicefries, 0staf, sniperchance, AngriestIBM, BrianOBlivion
+
+
+ Spriters:
+ Supernorn, Haruhi, Stuntwaffle, Pantaloons, Rho, SynthOrange, I Said
+ No
+
+
+ Traditional Games Space Station 13 is thankful to the GoonStation 13
+ Development Team for its work on the game up to the
+ {' r4407 release. The changelog for changes up to r4407 can be seen '}
+ here .
+
+
+ {'Except where otherwise noted, Goon Station 13 is licensed under a '}
+
+ Creative Commons Attribution-Noncommercial-Share Alike 3.0 License
+
+ {'. Rights are currently extended to '}
+ SomethingAwful Goons
+ {' only.'}
+
+ Traditional Games Space Station 13 License
+
+ {'All code after '}
+
+ commit 333c566b88108de218d882840e61928a9b759d8f on 2014/31/12 at
+ 4:38 PM PST
+
+ {' is licensed under '}
+ GNU AGPL v3
+ {'. All code before that commit is licensed under '}
+ GNU GPL v3
+ {', including tools unless their readme specifies otherwise. See '}
+
+ LICENSE
+
+ {' and '}
+
+ GPLv3.txt
+
+ {' for more details.'}
+
+
+ The TGS DMAPI API is licensed as a subproject under the MIT license.
+ {' See the footer of '}
+
+ code/__DEFINES/tgs.dm
+
+ {' and '}
+
+ code/modules/tgs/LICENSE
+
+ {' for the MIT license.'}
+
+
+ {'All assets including icons and sound are under a '}
+
+ Creative Commons 3.0 BY-SA license
+
+ {' unless otherwise indicated.'}
+
+
+ );
+
+ const changes =
+ typeof data === 'object' &&
+ Object.keys(data).length > 0 &&
+ Object.entries(data)
+ .reverse()
+ .map(([date, authors]) => (
+
+
+ {Object.entries(authors).map(([name, changes]) => (
+
+ {name} changed:
+
+
+ {changes.map((change) => {
+ const changeType = Object.keys(change)[0];
+ return (
+
+
+
+
+
+ {change[changeType]}
+
+
+ );
+ })}
+
+
+
+ ))}
+
+
+ ));
+
+ return (
+
+
+ {header}
+ {changes}
+ {typeof data === 'string' && {data}
}
+ {footer_tg}
+ {footer_goon}
+
+
+ );
+ }
+}
diff --git a/tools/ci/check_changelogs.sh b/tools/ci/check_changelogs.sh
index d90c93e35b009..12bac0bd255af 100755
--- a/tools/ci/check_changelogs.sh
+++ b/tools/ci/check_changelogs.sh
@@ -2,4 +2,4 @@
set -euo pipefail
md5sum -c - <<< "4d783933c74290b3a219068790b2046f *html/changelogs/example.yml"
-python3 tools/ss13_genchangelog.py html/changelogs
+python3 tools/ss13_genchangelog.py html/changelogs/bandastation
diff --git a/tools/makeChangelog.bat b/tools/makeChangelog.bat
index e2e959b375ccd..57a947cbd03f4 100644
--- a/tools/makeChangelog.bat
+++ b/tools/makeChangelog.bat
@@ -1,4 +1,4 @@
@echo off
rem Cheridan asked for this. - N3X
-call "%~dp0\bootstrap\python" ss13_genchangelog.py ../html/changelogs
+call "%~dp0\bootstrap\python" ss13_genchangelog.py ../html/changelogs/bandastation
pause
diff --git a/tools/pull_request_hooks/autoChangelog.js b/tools/pull_request_hooks/autoChangelog.js
index bc24481f182bf..d10b1d7e9c4a2 100644
--- a/tools/pull_request_hooks/autoChangelog.js
+++ b/tools/pull_request_hooks/autoChangelog.js
@@ -35,7 +35,7 @@ export async function processAutoChangelog({ github, context }) {
github.rest.repos.createOrUpdateFileContents({
owner: context.repo.owner,
repo: context.repo.repo,
- path: `html/changelogs/AutoChangeLog-pr-${context.payload.pull_request.number}.yml`,
+ path: `html/changelogs/bandastation/AutoChangeLog-pr-${context.payload.pull_request.number}.yml`,
message: `Automatic changelog for PR #${context.payload.pull_request.number} [ci skip]`,
content: Buffer.from(yml).toString("base64"),
});
diff --git a/tools/ss13_genchangelog.py b/tools/ss13_genchangelog.py
index bb5cb58afce35..04a03788d324e 100644
--- a/tools/ss13_genchangelog.py
+++ b/tools/ss13_genchangelog.py
@@ -143,4 +143,4 @@ def dictToTuples(inp):
os.remove(fileName)
with open(monthFile, 'w', encoding='utf-8') as f:
- yaml.dump(currentEntries, f, default_flow_style=False)
+ yaml.dump(currentEntries, f, default_flow_style=False, allow_unicode=True)