Changelog Overhaul (#13051)

* Changelog Overhaul

* SQL Update

* This is why I hate merge conflicts

* Comment Correction

* Farie Fixes + Tested with blank DB

* Colours + Titles

* Colour tweaks

* I fell victim to my own CI Chains!

* Cleans up the remains of the old changelogs

* Fixes formatting

* Kyet Changes

* Date
This commit is contained in:
AffectedArc07
2020-05-18 08:34:28 +01:00
committed by GitHub
parent b2b12c36e8
commit 7ea6f190c5
62 changed files with 15167 additions and 14542 deletions
-1
View File
@@ -23,7 +23,6 @@ jobs:
- find . -name "*.json" -not -path "./nano/node_modules/*" -print0 | xargs -0 python3 ./tools/travis/json_verifier.py
- tools/travis/build_nanoui.sh
- tools/travis/check_grep.sh
- tools/travis/check_changelogs.sh
- python3 tools/travis/check_line_endings.py
- ~/dreamchecker
+15 -1
View File
@@ -594,4 +594,18 @@ CREATE TABLE `connection_log` (
`ip` varchar(32) NOT NULL,
`computerid` varchar(32) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
--
-- Table structure for table `changelog`
--
DROP TABLE IF EXISTS `changelog`;
CREATE TABLE `changelog` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`pr_number` INT(11) NOT NULL,
`date_merged` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`author` VARCHAR(32) NOT NULL,
`cl_type` ENUM('FIX','WIP','TWEAK','SOUNDADD','SOUNDDEL','CODEADD','CODEDEL','IMAGEADD','IMAGEDEL','SPELLCHECK','EXPERIMENT') NOT NULL,
`cl_entry` TEXT NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+15 -1
View File
@@ -591,4 +591,18 @@ CREATE TABLE `SS13_connection_log` (
`ip` varchar(32) NOT NULL,
`computerid` varchar(32) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
--
-- Table structure for table `SS13_changelog`
--
DROP TABLE IF EXISTS `SS13_changelog`;
CREATE TABLE `SS13_changelog` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`pr_number` INT(11) NOT NULL,
`date_merged` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`author` VARCHAR(32) NOT NULL,
`cl_type` ENUM('FIX','WIP','TWEAK','SOUNDADD','SOUNDDEL','CODEADD','CODEDEL','IMAGEADD','IMAGEDEL','SPELLCHECK','EXPERIMENT') NOT NULL,
`cl_entry` TEXT NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+1 -1
View File
@@ -38,4 +38,4 @@ ALTER TABLE feedback.population CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4
ALTER TABLE feedback.privacy CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE feedback.vpn_whitelist CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE feedback.watch CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE feedback.whitelist CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE feedback.whitelist CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+13
View File
@@ -0,0 +1,13 @@
#Updating the SQL from version 11 to version 12. -AffectedArc07
#Creating a table for the new changelog system
DROP TABLE IF EXISTS `changelog`;
CREATE TABLE IF NOT EXISTS `changelog` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`pr_number` INT(11) NOT NULL,
`date_merged` TIMESTAMP NOT NULL DEFAULT current_timestamp(),
`author` VARCHAR(32) NOT NULL,
`cl_type` ENUM('FIX','WIP','TWEAK','SOUNDADD','SOUNDDEL','CODEADD','CODEDEL','IMAGEADD','IMAGEDEL','SPELLCHECK','EXPERIMENT') NOT NULL,
`cl_entry` TEXT NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+1 -1
View File
@@ -319,7 +319,7 @@
#define INVESTIGATE_BOMB "bombs"
// The SQL version required by this version of the code
#define SQL_VERSION 11
#define SQL_VERSION 12
// Vending machine stuff
#define CAT_NORMAL 1
-1
View File
@@ -4,7 +4,6 @@ GLOBAL_VAR(host)
GLOBAL_VAR(join_motd)
GLOBAL_VAR(join_tos)
GLOBAL_VAR_INIT(game_version, "ParaCode")
GLOBAL_VAR_INIT(changelog_hash, md5('html/changelog.html')) //used to check if the CL changed
GLOBAL_VAR_INIT(game_year, (text2num(time2text(world.realtime, "YYYY")) + 544))
GLOBAL_VAR_INIT(aliens_allowed, 1)
+230
View File
@@ -0,0 +1,230 @@
/*
Subsystem core for ParadiseSS13 changelogs
Author: AffectedArc07
Basically this SS extracts changelogs from the past 30 days from the database, and cleanly formats them into HTML that the players can see
It only runs the extraction on initialize to ensure that the changelog doesnt change mid round, and to reduce the amount of DB calls that need to be done
The changelog entries are generated from the PHP scripts in tools/githubChangelogProcessor.php
This SS also handles the checking of player CL dates and informing them if it has changed
*/
SUBSYSTEM_DEF(changelog)
name = "Changelog"
flags = SS_NO_FIRE
var/current_cl_timestamp = "0" // Timestamp is seconds since UNIX epoch (1st January 1970). ITs also a string because BYOND doesnt like big numbers.
var/ss_ready = FALSE // Is the SS ready? We dont want to run procs if we have not generated yet
var/list/startup_clients_button = list() // Clients who connected before initialization who need their button color updating
var/list/startup_clients_open = list() // Clients who connected before initialization who need the CL opening
var/changelogHTML = "" // HTML that the changelog will use to display
/datum/controller/subsystem/changelog/Initialize()
// This entire subsystem relies on SQL being here.
if(!GLOB.dbcon.IsConnected())
return ..()
var/DBQuery/latest_cl_date = GLOB.dbcon.NewQuery("SELECT UNIX_TIMESTAMP(date_merged) AS ut FROM [format_table_name("changelog")] ORDER BY date_merged DESC LIMIT 1")
if(!latest_cl_date.Execute())
var/err = latest_cl_date.ErrorMsg()
log_game("SQL ERROR during SSchangelog initialization L24. Error: \[[err]\]\n")
message_admins("SQL ERROR during SSchangelog initialization L24. Error: \[[err]\]\n")
// Abort if we cant do this
return ..()
while(latest_cl_date.NextRow())
current_cl_timestamp = latest_cl_date.item[1]
if(!GenerateChangelogHTML()) // if this failed to generate
to_chat(world, "<span class='alert'>WARNING: Changelog failed to generate. Please inform a coder/server dev</span>")
return ..()
ss_ready = TRUE
// Now we can alert anyone who wanted to check the changelog
for(var/x in startup_clients_button)
var/client/C = x
UpdatePlayerChangelogButton(C)
// Now we can alert anyone who wanted to check the changelog
for(var/client/C in startup_clients_open)
OpenChangelog(C)
return ..()
/datum/controller/subsystem/changelog/proc/UpdatePlayerChangelogDate(client/C)
if(!ss_ready)
return // Only return here, we dont have to worry about a queue list because this will be called from ShowChangelog()
// Technically this is only for the date but we can also do the UI button at the same time
var/datum/preferences/P = GLOB.preferences_datums[C.ckey]
if(P.toggles & UI_DARKMODE)
winset(C, "rpane.changelog", "background-color=#40628a;font-color=#ffffff;font-style=none")
else
winset(C, "rpane.changelog", "background-color=none;font-style=none")
C.prefs.lastchangelog = current_cl_timestamp
var/DBQuery/updatePlayerCLTime = GLOB.dbcon.NewQuery("UPDATE [format_table_name("player")] SET lastchangelog='[sanitizeSQL(current_cl_timestamp)]' WHERE ckey='[C.ckey]'")
if(!updatePlayerCLTime.Execute())
var/err = updatePlayerCLTime.ErrorMsg()
log_game("SQL ERROR during lastchangelog updating. Error: \[[err]\]\n")
message_admins("SQL ERROR during lastchangelog updating. Error: \[[err]\]\n")
to_chat(C, "Couldn't update your last seen changelog, please try again later.")
return FALSE
return TRUE
/datum/controller/subsystem/changelog/proc/UpdatePlayerChangelogButton(client/C)
// If SQL aint even enabled, just set the button to default style
if(!GLOB.dbcon.IsConnected())
if(C.prefs.toggles & UI_DARKMODE)
winset(C, "rpane.changelog", "background-color=#40628a;text-color=#FFFFFF")
else
winset(C, "rpane.changelog", "background-color=none;text-color=#000000")
return
// If SQL is enabled but we aint ready, queue them up, and use the default style
if(!ss_ready)
startup_clients_button |= C
if(C.prefs.toggles & UI_DARKMODE)
winset(C, "rpane.changelog", "background-color=#40628a;text-color=#FFFFFF")
else
winset(C, "rpane.changelog", "background-color=none;text-color=#000000")
return
// If we are ready, process the button style
if(C.prefs.lastchangelog != current_cl_timestamp)
winset(C, "rpane.changelog", "background-color=#bb7700;text-color=#FFFFFF;font-style=bold")
to_chat(C, "<span class='info'>Changelog has changed since your last visit.</span>")
else
if(C.prefs.toggles & UI_DARKMODE)
winset(C, "rpane.changelog", "background-color=#40628a;text-color=#FFFFFF")
else
winset(C, "rpane.changelog", "background-color=none;text-color=#000000")
/datum/controller/subsystem/changelog/proc/OpenChangelog(client/C)
// If SQL isnt enabled, dont even queue them, just tell them it wont work
if(!GLOB.dbcon.IsConnected())
to_chat(C, "<span class='notice'>This server is not running with an SQL backend. Changelog is unavailable.</span>")
return
// If SQL is enabled but we aint ready, queue them up
if(!ss_ready)
startup_clients_open |= C
to_chat(C, "<span class='notice'>The changelog system is still initializing. The changelog will open for you once it has initialized.</span>")
return
UpdatePlayerChangelogDate(C)
UpdatePlayerChangelogButton(C)
var/datum/browser/cl_popup = new(C.mob, "changelog", "Changelog", 700, 800)
cl_popup.set_content(changelogHTML)
cl_popup.open()
/client/verb/changes()
set name = "Changelog"
set desc = "View the changelog."
set category = "OOC"
// Just invoke the actual CL thing
SSchangelog.OpenChangelog(src)
// Helper to turn CL types into a fontawesome icon instead of an image
// The colors are #28a745 for green, #fd7e14 for orange, and #dc3545 for red.
// These colours are from bootstrap and look good with black and white
/datum/controller/subsystem/changelog/proc/Text2Icon(text)
switch(text)
if("FIX")
return "<i title='Fix' class='fas fa-tools'></i></span>" // Fixes are white because while they are good, they have no negative coutnerpart
if("WIP")
return "<span style='color: #fd7e14;'><i title='Work In Progress' class='fas fa-hard-hat'></i></span>" // WIP stuff is orange because new code is good but its not done yet
if("TWEAK")
return "<i title='Tweak' class='fas fa-sliders-h'></i>" // Tweaks are white because they could be good or bad, and theres no specific add or remove
if("SOUNDADD")
return "<span style='color: #28a745;'><i title='Sound Added' class='fas fa-volume-up'></i></span>" // Sound additions are green because its something new
if("SOUNDDEL")
return "<span style='color: #dc3545;'><i title='Sound Removed' class='fas fa-volume-mute'></i></span>" // Sound removals are red because something has been removed
if("CODEADD")
return "<span style='color: #28a745;'><i title='Code Addition' class='fas fa-plus'></i></span>" // Code additions are green because its something new
if("CODEDEL")
return "<span style='color: #dc3545;'><i title='Code Removal' class='fas fa-minus'></i></span>" // Code removals are red becuase someting has been removed
if("IMAGEADD")
return "<span style='color: #28a745;'><i title='Image/Sprite Addition' class='fas fa-folder-plus'></i></span>" // Image additions are green because something has been added
if("IMAGEDEL")
return "<span style='color: #dc3545;'><i title='Image/Sprite Removal' class='fas fa-folder-minus'></i></span>" // Image removals are red because something has been removed
if("SPELLCHECK")
return "<i title='Spelling/Grammar Fix' class='fas fa-font'></i>" // Spellcheck is white because theres no dedicated negative to it, so theres no red for it to collate with
if("EXPERIMENT")
return "<span style='color: #fd7e14;'><i title='Experimental' class='fas fa-exclamation-triangle'></i></span>" // Experimental stuff is orange because while its a new feature, its unstable
else // Just incase the DB somehow breaks
return "<span style='color: #28a745;'><i title='Code Addition' class='fas fa-plus'></i></span>" // Same here
// This proc is the star of the show
/datum/controller/subsystem/changelog/proc/GenerateChangelogHTML()
// Modify the code below to modify the header of the changelog
var/changelog_header = {"
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.12.1/css/all.min.css" rel="stylesheet">
<title>ParadiseSS13 Changelog</title>
<base target='_blank' />
<link rel='styelsheet' href='fontawesome.min.css'>
<center>
<p style='font-size: 20px'><b>Paradise Station Changelog</b></p>
<p><a href='[config.forum_link_url]'>Forum</a> - <a href='[config.wikiurl]'>Wiki</a> - <a href='[config.githuburl]'>GitHub</a></p>
</center>
"}
var/list/prs_to_process = list()
// Grab all from last 30 days
var/DBQuery/pr_list_query = GLOB.dbcon.NewQuery("SELECT DISTINCT pr_number FROM changelog WHERE date_merged BETWEEN NOW() - INTERVAL 30 DAY AND NOW() ORDER BY date_merged DESC")
if(!pr_list_query.Execute())
var/err = pr_list_query.ErrorMsg()
log_game("SQL ERROR during CL generation L143. Error: \[[err]\]\n")
message_admins("SQL ERROR during CL generation L143. Error: \[[err]\]\n")
return FALSE
while(pr_list_query.NextRow())
prs_to_process += text2num(pr_list_query.item[1])
// Load in the header
changelogHTML += changelog_header
// Make blocks for all the PRs
for(var/pr_number in prs_to_process)
// Initial declarations
var/pr_block = "" // HTML for the changelog section
var/author = "" // Author of the PR
var/merge_date = "" // Timestamp of when the PR was merged
// Now we gather the data from the DB
// Also we probably dont need to sanitize the PR number but you never know
var/DBQuery/pr_meta = GLOB.dbcon.NewQuery("SELECT author,DATE(date_merged) AS date FROM changelog WHERE pr_number = [sanitizeSQL(pr_number)] LIMIT 1")
if(!pr_meta.Execute())
var/err = pr_meta.ErrorMsg()
log_game("SQL ERROR during CL generation L190. Error: \[[err]\]\n")
message_admins("SQL ERROR during CL generation L190. Error: \[[err]\]\n")
return FALSE
while(pr_meta.NextRow())
author = pr_meta.item[1]
merge_date = pr_meta.item[2]
// Now for each actual entry
var/DBQuery/db_entries = GLOB.dbcon.NewQuery("SELECT cl_type, cl_entry FROM changelog WHERE pr_number = [sanitizeSQL(pr_number)]")
if(!db_entries.Execute())
var/err = db_entries.ErrorMsg()
log_game("SQL ERROR during CL generation L204. Error: \[[err]\]\n")
message_admins("SQL ERROR during CL generation L204. Error: \[[err]\]\n")
return FALSE
// Now we make a changelog block
pr_block += "<div class='statusDisplay'>"
// If the github URL in the config has a trailing slash, it doesnt matter here, thankfully github accepts having a double slash: https://github.com/org/repo//pull/1
pr_block += "<p class='white'><a href='[config.githuburl]/pull/[pr_number]'>#[pr_number]</a> by <b>[author]</b> (Merged on [merge_date])</span>"
while(db_entries.NextRow())
pr_block += "<p>[Text2Icon(db_entries.item[1])] [db_entries.item[2]]</p>"
pr_block += "</div><br>"
changelogHTML += pr_block
// Make sure we return TRUE so we know it worked
return TRUE
+6 -24
View File
@@ -373,13 +373,11 @@
send_resources()
if(prefs.toggles & UI_DARKMODE) // activates dark mode if its flagged. -AA07
if(establish_db_connection())
activate_darkmode()
activate_darkmode()
else
// activate_darkmode() calls the CL update button proc, so we dont want it double called
SSchangelog.UpdatePlayerChangelogButton(src)
if(prefs.lastchangelog != GLOB.changelog_hash) //bolds the changelog button on the interface so we know there are updates. -CP
if(establish_db_connection())
to_chat(src, "<span class='info'>Changelog has changed since your last visit.</span>")
update_changelog_button()
if(prefs.toggles & DISABLE_KARMA) // activates if karma is disabled
if(establish_db_connection())
@@ -825,7 +823,7 @@
// IF YOU CHANGE ANYTHING IN ACTIVATE, MAKE SURE IT HAS A DEACTIVATE METHOD, -AA07
/client/proc/activate_darkmode()
///// BUTTONS /////
update_changelog_button()
SSchangelog.UpdatePlayerChangelogButton(src)
/* Rpane */
winset(src, "rpane.textb", "background-color=#40628a;text-color=#FFFFFF")
winset(src, "rpane.infob", "background-color=#40628a;text-color=#FFFFFF")
@@ -857,7 +855,7 @@
/client/proc/deactivate_darkmode()
///// BUTTONS /////
update_changelog_button()
SSchangelog.UpdatePlayerChangelogButton(src)
/* Rpane */
winset(src, "rpane.textb", "background-color=none;text-color=#000000")
winset(src, "rpane.infob", "background-color=none;text-color=#000000")
@@ -887,22 +885,6 @@
///// NOTIFY USER /////
to_chat(src, "<span class='notice'>Darkmode Disabled</span>") // what a sick fuck
// Better changelog button handling
/client/proc/update_changelog_button()
if(establish_db_connection())
if(prefs.lastchangelog != GLOB.changelog_hash)
winset(src, "rpane.changelog", "background-color=#bb7700;text-color=#FFFFFF;font-style=bold")
else
if(prefs.toggles & UI_DARKMODE)
winset(src, "rpane.changelog", "background-color=#40628a;text-color=#FFFFFF")
else
winset(src, "rpane.changelog", "background-color=none;text-color=#000000")
else
if(prefs.toggles & UI_DARKMODE)
winset(src, "rpane.changelog", "background-color=#40628a;text-color=#FFFFFF")
else
winset(src, "rpane.changelog", "background-color=none;text-color=#000000")
/client/proc/generate_clickcatcher()
if(!void)
void = new()
@@ -79,7 +79,7 @@ GLOBAL_LIST_INIT(special_role_times, list( //minimum age (in days) for accounts
var/last_id
//game-preferences
var/lastchangelog = "" //Saved changlog filesize to detect if there was a change
var/lastchangelog = "1" //Saved changlog timestamp (unix epoch) to detect if there was a change. Dont set this to 0 unless you want the last changelog date to be 4x longer than the expected lifespan of the universe.
var/exp
var/ooccolor = "#b82e00"
var/list/be_special = list() //Special role selection
@@ -491,18 +491,3 @@
load_character(C,pick(saves))
return 1
/datum/preferences/proc/SetChangelog(client/C,hash)
lastchangelog=hash
var/datum/preferences/P = GLOB.preferences_datums[C.ckey]
if(P.toggles & UI_DARKMODE)
winset(C, "rpane.changelog", "background-color=#40628a;font-color=#ffffff;font-style=none")
else
winset(C, "rpane.changelog", "background-color=none;font-style=none")
var/DBQuery/query = GLOB.dbcon.NewQuery("UPDATE [format_table_name("player")] SET lastchangelog='[lastchangelog]' WHERE ckey='[C.ckey]'")
if(!query.Execute())
var/err = query.ErrorMsg()
log_game("SQL ERROR during lastchangelog updating. Error : \[[err]\]\n")
message_admins("SQL ERROR during lastchangelog updating. Error : \[[err]\]\n")
to_chat(C, "Couldn't update your last seen changelog, please try again later.")
return
return 1

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

+1
View File
@@ -0,0 +1 @@
This directory has the old changelog system, no longer used

Before

Width:  |  Height:  |  Size: 657 B

After

Width:  |  Height:  |  Size: 657 B

Before

Width:  |  Height:  |  Size: 727 B

After

Width:  |  Height:  |  Size: 727 B

File diff suppressed because it is too large Load Diff
@@ -11811,3 +11811,45 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- tweak: Cult whispering now uses your real name
- bugfix: Fixed the invisible blob zombies
- bugfix: A runtime in blob/factory/run_action
2020-04-26:
Cazdon:
- bugfix: Admin Roles no longer appear on manifest.
- tweak: Central Command PDA's no longer appear on the messenger list.
- bugfix: Potential Convertee's being unable to be converted.
Drakeven:
- bugfix: Fixed mislabeled traitor and mindslave special role.
Ionward:
- tweak: Grey, Tajaran, Unathi, and Vulpkanin now properly have species specific
fits for soft space suits.
- tweak: Vox can now wear soft space suits, such as EVA (Clown and Mime included),
NASA Void, and Syndicate suits.
- imageadd: Added Vox soft suit sprites.
JKnutson101:
- tweak: Combined the Rite of Tribute and Rite of Enlightenment into one Rite of
Offering.
- bugfix: Sacrificing now properly puts victims that have at one point had CKeys
into soul stones, or polls dead-chat to do so.
Kyep:
- tweak: Tweaked Greater Hellhound, added more non-violent options and one unique
combat spell.
SteelSlayer:
- bugfix: Fixes the "List SSDs and AFKs panel" showing everyone as the target of
an assassinate objective
- bugfix: The global objectives list is now viewable in the MC Globals menu
- bugfix: Reverts some terrible changes that are causing some bugs with traitors
- bugfix: Fixes AIs with the combat module not being able to hack APCs
TDSSS:
- rscdel: duplicate mecha definitions
- bugfix: blobbernaut vision blur now clears as intended.
- bugfix: fixed a bug preventing ticket system from working under some circumstances.
VeteranKyl:
- bugfix: DNA Samplers now check if the target species has DNA.
- bugfix: Fixed the envenomed blob's spore toxin not causing harm.
craftxbox:
- bugfix: fixed colors not working without regex
- bugfix: fixed text panel not loading when an invalid regex is added
- rscadd: polyfilled string.prototype.includes
moxian:
- bugfix: being in a locker no longer interferes with tracking implant tracking
- bugfix: locator no longer locates tracking implants on other z levels.
- bugfix: fixed singulo being unable to expand when placed next to containment wall

Before

Width:  |  Height:  |  Size: 495 B

After

Width:  |  Height:  |  Size: 495 B

Before

Width:  |  Height:  |  Size: 498 B

After

Width:  |  Height:  |  Size: 498 B

Before

Width:  |  Height:  |  Size: 651 B

After

Width:  |  Height:  |  Size: 651 B

Before

Width:  |  Height:  |  Size: 678 B

After

Width:  |  Height:  |  Size: 678 B

Before

Width:  |  Height:  |  Size: 535 B

After

Width:  |  Height:  |  Size: 535 B

Before

Width:  |  Height:  |  Size: 580 B

After

Width:  |  Height:  |  Size: 580 B

Before

Width:  |  Height:  |  Size: 403 B

After

Width:  |  Height:  |  Size: 403 B

Before

Width:  |  Height:  |  Size: 462 B

After

Width:  |  Height:  |  Size: 462 B

+10
View File
@@ -0,0 +1,10 @@
body {padding:0px;margin:0px;}
#top {position:fixed;top:5px;left:10%;width:80%;text-align:center;background-color:#fff;border:2px solid #ccc;}
#main {position:relative;top:50px;left:3%;width:96%;text-align:center;z-index:0;}
#searchable {table-layout:fixed;width:100%;text-align:center;"#f4f4f4";}
tr.norm {background-color:#f4f4f4;}
tr.title {background-color:#ccc;}
tr.alt {background-color:#e7e7e7;}
.small {font-size:80%;}
a {text-decoration:none;color:#a0a;}
a:hover {color:#d3d;}
+33
View File
@@ -0,0 +1,33 @@
function selectTextField(){
var filter_text = document.getElementById('filter');
filter_text.focus();
filter_text.select();
}
function updateSearch(){
var input_form = document.getElementById('filter');
var filter = input_form.value.toLowerCase();
input_form.value = filter;
var table = document.getElementById('searchable');
var alt_style = 'norm';
for(var i = 0; i < table.rows.length; i++){
try{
var row = table.rows[i];
if(row.className == 'title') continue;
var found=0;
for(var j = 0; j < row.cells.length; j++){
var cell = row.cells[j];
if(cell.innerText.toLowerCase().indexOf(filter) != -1){
found=1;
break;
}
}
if(found == 0) row.style.display='none';
else{
row.style.display='block';
row.className = alt_style;
if(alt_style == 'alt') alt_style = 'norm';
else alt_style = 'alt';
}
}catch(err) { }
}
}

Before

Width:  |  Height:  |  Size: 509 B

After

Width:  |  Height:  |  Size: 509 B

Before

Width:  |  Height:  |  Size: 660 B

After

Width:  |  Height:  |  Size: 660 B

Before

Width:  |  Height:  |  Size: 684 B

After

Width:  |  Height:  |  Size: 684 B

@@ -1,4 +0,0 @@
author: "Kyep"
delete-after: True
changes:
- tweak: "Tweaked Greater Hellhound, added more non-violent options and one unique combat spell."
@@ -1,5 +0,0 @@
author: "JKnutson101"
delete-after: True
changes:
- tweak: "Combined the Rite of Tribute and Rite of Enlightenment into one Rite of Offering."
- bugfix: "Sacrificing now properly puts victims that have at one point had CKeys into soul stones, or polls dead-chat to do so."
@@ -1,6 +0,0 @@
author: "Ionward"
delete-after: True
changes:
- tweak: "Grey, Tajaran, Unathi, and Vulpkanin now properly have species specific fits for soft space suits."
- tweak: "Vox can now wear soft space suits, such as EVA (Clown and Mime included), NASA Void, and Syndicate suits."
- imageadd: "Added Vox soft suit sprites."
@@ -1,5 +0,0 @@
author: "SteelSlayer"
delete-after: True
changes:
- bugfix: "Fixes the \"List SSDs and AFKs panel\" showing everyone as the target of an assassinate objective"
- bugfix: "The global objectives list is now viewable in the MC Globals menu"
@@ -1,6 +0,0 @@
author: "craftxbox"
delete-after: True
changes:
- bugfix: "fixed colors not working without regex"
- bugfix: "fixed text panel not loading when an invalid regex is added"
- rscadd: "polyfilled string.prototype.includes"
@@ -1,4 +0,0 @@
author: "TDSSS"
delete-after: True
changes:
- rscdel: "duplicate mecha definitions"
@@ -1,5 +0,0 @@
author: "moxian"
delete-after: True
changes:
- bugfix: "being in a locker no longer interferes with tracking implant tracking"
- bugfix: "locator no longer locates tracking implants on other z levels."
@@ -1,4 +0,0 @@
author: "moxian"
delete-after: True
changes:
- bugfix: "fixed singulo being unable to expand when placed next to containment wall"
@@ -1,4 +0,0 @@
author: "TDSSS"
delete-after: True
changes:
- bugfix: "blobbernaut vision blur now clears as intended."
@@ -1,4 +0,0 @@
author: "Drakeven"
delete-after: True
changes:
- bugfix: "Fixed mislabeled traitor and mindslave special role."
@@ -1,5 +0,0 @@
author: "Cazdon"
delete-after: True
changes:
- bugfix: "Admin Roles no longer appear on manifest."
- tweak: "Central Command PDA's no longer appear on the messenger list."
@@ -1,4 +0,0 @@
author: "TDSSS"
delete-after: True
changes:
- bugfix: "fixed a bug preventing ticket system from working under some circumstances."
@@ -1,4 +0,0 @@
author: "SteelSlayer"
delete-after: True
changes:
- bugfix: "Reverts some terrible changes that are causing some bugs with traitors"
@@ -1,4 +0,0 @@
author: "VeteranKyl"
delete-after: True
changes:
- bugfix: "DNA Samplers now check if the target species has DNA."
@@ -1,4 +0,0 @@
author: "SteelSlayer"
delete-after: True
changes:
- bugfix: "Fixes AIs with the combat module not being able to hack APCs"
@@ -1,4 +0,0 @@
author: "VeteranKyl"
delete-after: True
changes:
- bugfix: "Fixed the envenomed blob's spore toxin not causing harm."
@@ -1,4 +0,0 @@
author: "Cazdon"
delete-after: True
changes:
- bugfix: "Potential Convertee's being unable to be converted."
-29
View File
@@ -13,35 +13,6 @@
to_chat(src, "<span class='danger'>The wiki URL is not set in the server configuration.</span>")
return
/client/verb/changes()
set name = "Changelog"
set desc = "View the changelog."
set hidden = 1
getFiles(
'html/88x31.png',
'html/bug-minus.png',
'html/cross-circle.png',
'html/hard-hat-exclamation.png',
'html/image-minus.png',
'html/image-plus.png',
'html/music-minus.png',
'html/music-plus.png',
'html/tick-circle.png',
'html/wrench-screwdriver.png',
'html/spell-check.png',
'html/burn-exclamation.png',
'html/chevron.png',
'html/chevron-expand.png',
'html/changelog.css',
'html/changelog.js',
'html/changelog.html'
)
src << browse('html/changelog.html', "window=changes;size=675x650")
update_changelog_button()
if(prefs.lastchangelog != GLOB.changelog_hash) //if it's already opened, no need to tell them they have unread changes
prefs.SetChangelog(src, GLOB.changelog_hash)
/client/verb/forum()
set name = "forum"
set desc = "Visit the forum."
+1
View File
@@ -216,6 +216,7 @@
#include "code\controllers\subsystem\alarm.dm"
#include "code\controllers\subsystem\assets.dm"
#include "code\controllers\subsystem\atoms.dm"
#include "code\controllers\subsystem\changelog.dm"
#include "code\controllers\subsystem\chat.dm"
#include "code\controllers\subsystem\events.dm"
#include "code\controllers\subsystem\fires.dm"
+351
View File
@@ -0,0 +1,351 @@
<?php
/*
* Github webhook In-game PR Announcer and SQL Changelog Generator for ParadiseSS13
* Modified for Paradise by: AffectedArc07
* Original code by: MrStonedOne
*
* For documentation on the changelog generator see https://tgstation13.org/phpBB/viewtopic.php?f=5&t=5157
* To hide prs from being announced in game, place a [s] in front of the title
* All runtime errors are echo'ed to the webhook's logs in github
*/
/**CREDITS:
* GitHub webhook handler template.
*
* @see https://developer.github.com/webhooks/
* @author Miloslav Hula (https://github.com/milo)
*/
//CONFIG START (all defaults are random examples, do change them)
//Use single quotes for config options that are strings.
//Github lets you have it sign the message with a secret that you can validate. This prevents people from faking events.
//This var should match the secret you configured for this webhook on github.
//This is required as otherwise somebody could trick the script into leaking variables.
$hookSecret = '08ajh0qj93209qj90jfq932j32r';
// To store PR changelogs, this script requires access to the game database
// Making an account just for this service is highly recommended
// For maximum security, grant it INSERT on `changelog` ONLY.
$dbServer = "localhost"; // Hostname of the database server (default localhost)
$dbPort = "3306"; // Port of the database server (default 3306) | MUST BE A STRING
$dbUser = "root"; // Database username (default root)
$dbPassword = ""; // Database password (default blank)
$dbDatabase = "feedback"; // Database name (default feedback)
//servers to announce PRs to.
$servers = array();
/*
$servers[0] = array();
$servers[0]['address'] = 'game.tgstation13.org';
$servers[0]['port'] = '1337';
$servers[0]['comskey'] = '89aj90cq2fm0amc90832mn9rm90';
$servers[1] = array();
$servers[1]['address'] = 'game.tgstation13.org';
$servers[1]['port'] = '2337';
$servers[1]['comskey'] = '89aj90cq2fm0amc90832mn9rm90';
*/
//CONFIG END
set_error_handler(function($severity, $message, $file, $line) {
throw new \ErrorException($message, 0, $severity, $file, $line);
});
set_exception_handler(function($e) {
header('HTTP/1.1 500 Internal Server Error');
echo "Error on line {$e->getLine()}: " . htmlSpecialChars($e->getMessage());
die();
});
$rawPost = NULL;
if (!$hookSecret || $hookSecret == '08ajh0qj93209qj90jfq932j32r')
throw new \Exception("Hook secret is required and can not be default");
if (!isset($_SERVER['HTTP_X_HUB_SIGNATURE'])) {
throw new \Exception("HTTP header 'X-Hub-Signature' is missing.");
} elseif (!extension_loaded('hash')) {
throw new \Exception("Missing 'hash' extension to check the secret code validity.");
}
list($algo, $hash) = explode('=', $_SERVER['HTTP_X_HUB_SIGNATURE'], 2) + array('', '');
if (!in_array($algo, hash_algos(), TRUE)) {
throw new \Exception("Hash algorithm '$algo' is not supported.");
}
$rawPost = file_get_contents('php://input');
if ($hash !== hash_hmac($algo, $rawPost, $hookSecret)) {
throw new \Exception('Hook secret does not match.');
}
$contenttype = null;
//apache and nginx/fastcgi/phpfpm call this two different things.
if (!isset($_SERVER['HTTP_CONTENT_TYPE'])) {
if (!isset($_SERVER['CONTENT_TYPE']))
throw new \Exception("Missing HTTP 'Content-Type' header.");
else
$contenttype = $_SERVER['CONTENT_TYPE'];
} else {
$contenttype = $_SERVER['HTTP_CONTENT_TYPE'];
}
if (!isset($_SERVER['HTTP_X_GITHUB_EVENT'])) {
throw new \Exception("Missing HTTP 'X-Github-Event' header.");
}
switch ($contenttype) {
case 'application/json':
$json = $rawPost ?: file_get_contents('php://input');
break;
case 'application/x-www-form-urlencoded':
$json = $_POST['payload'];
break;
default:
throw new \Exception("Unsupported content type: $contenttype");
}
# Payload structure depends on triggered event
# https://developer.github.com/v3/activity/events/types/
$payload = json_decode($json, true);
switch (strtolower($_SERVER['HTTP_X_GITHUB_EVENT'])) {
case 'ping':
echo 'pong';
break;
case 'pull_request':
handle_pr($payload);
break;
default:
header('HTTP/1.0 404 Not Found');
echo "Event:$_SERVER[HTTP_X_GITHUB_EVENT] Payload:\n";
print_r($payload); # For debug only. Can be found in GitHub hook log.
die();
}
function handle_pr($payload) {
$action = 'opened';
switch ($payload["action"]) {
case 'opened':
case 'reopened':
$action = $payload['action'];
break;
case 'closed':
if (!$payload['pull_request']['merged']) {
$action = 'closed';
}
else {
$action = 'merged';
checkchangelog($payload, true);
}
break;
default:
return;
}
if (strtolower(substr($payload['pull_request']['title'], 0, 3)) == '[s]') {
echo "PR Announcement Halted; Secret tag detected.\n";
return;
}
$msg = 'Pull Request '.$action.' by '.htmlSpecialChars($payload['sender']['login']).': <a href="'.$payload['pull_request']['html_url'].'">'.htmlSpecialChars('#'.$payload['pull_request']['number'].' '.$payload['pull_request']['user']['login'].' - '.$payload['pull_request']['title']).'</a>';
sendtoallservers('?announce='.urlencode($msg));
}
function checkchangelog($payload, $merge = false) {
global $dbServer, $dbUser, $dbPassword, $dbDatabase, $dbPort;
if (!$merge)
return;
if (!isset($payload['pull_request']) || !isset($payload['pull_request']['body'])) {
return;
}
if (!isset($payload['pull_request']['user']) || !isset($payload['pull_request']['user']['login'])) {
return;
}
$body = $payload['pull_request']['body'];
$prNumber = $payload['pull_request']['number'];
$body = str_replace("\r\n", "\n", $body);
$body = explode("\n", $body);
$username = $payload['pull_request']['user']['login'];
$incltag = false;
$changelogbody = array();
$currentchangelogblock = array();
$foundcltag = false;
foreach ($body as $line) {
$line = trim($line);
if (substr($line,0,4) == ':cl:' || substr($line,0,4) == '🆑') {
$incltag = true;
$foundcltag = true;
$pos = strpos($line, " ");
if ($pos)
$username = substr($line, $pos+1);
continue;
} else if (substr($line,0,5) == '/:cl:' || substr($line,0,6) == '/ :cl:' || substr($line,0,5) == ':/cl:' || substr($line,0,5) == '/🆑' || substr($line,0,6) == '/ 🆑' ) {
$incltag = false;
$changelogbody = array_merge($changelogbody, $currentchangelogblock);
continue;
}
if (!$incltag)
continue;
$firstword = explode(' ', $line)[0];
$pos = strpos($line, " ");
$item = '';
if ($pos) {
$firstword = trim(substr($line, 0, $pos));
$item = trim(substr($line, $pos+1));
} else {
$firstword = $line;
}
if (!strlen($firstword)) {
$currentchangelogblock[count($currentchangelogblock)-1]['body'] .= "\n";
continue;
}
//not a prefix line.
//so we add it to the last changelog entry as a separate line
if (!strlen($firstword) || $firstword[strlen($firstword)-1] != ':') {
if (count($currentchangelogblock) <= 0)
continue;
$currentchangelogblock[count($currentchangelogblock)-1]['body'] .= "\n".$line;
continue;
}
$cltype = strtolower(substr($firstword, 0, -1));
switch ($cltype) {
case 'fix':
case 'fixes':
case 'bugfix':
$currentchangelogblock[] = array('type' => 'FIX', 'body' => $item);
break;
case 'wip':
$currentchangelogblock[] = array('type' => 'WIP', 'body' => $item);
break;
case 'rsctweak':
case 'tweaks':
case 'tweak':
$currentchangelogblock[] = array('type' => 'TWEAK', 'body' => $item);
break;
case 'soundadd':
$currentchangelogblock[] = array('type' => 'SOUNDADD', 'body' => $item);
break;
case 'sounddel':
$currentchangelogblock[] = array('type' => 'SOUNDDEL', 'body' => $item);
break;
case 'add':
case 'adds':
case 'rscadd':
$currentchangelogblock[] = array('type' => 'CODEADD', 'body' => $item);
break;
case 'del':
case 'dels':
case 'rscdel':
$currentchangelogblock[] = array('type' => 'CODEDEL', 'body' => $item);
break;
case 'imageadd':
$currentchangelogblock[] = array('type' => 'IMAGEADD', 'body' => $item);
break;
case 'imagedel':
$currentchangelogblock[] = array('type' => 'IMAGEDEL', 'body' => $item);
break;
case 'typo':
case 'spellcheck':
$currentchangelogblock[] = array('type' => 'SPELLCHECK', 'body' => $item);
break;
case 'experimental':
case 'experiment':
$currentchangelogblock[] = array('type' => 'EXPERIMENT', 'body' => $item);
break;
default:
//we add it to the last changelog entry as a separate line
if (count($currentchangelogblock) > 0)
$currentchangelogblock[count($currentchangelogblock)-1]['body'] .= "\n".$line;
break;
}
}
if (!count($changelogbody))
return;
$conn = new PDO("mysql:host=$dbServer;dbname=$dbDatabase;port=$dbPort", $dbUser, $dbPassword); // Initialises DB connection
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
foreach($changelogbody as $changelogEntry) {
// Throw all changelogs into the DB
$stmt = $conn->prepare("INSERT INTO changelog (pr_number, author, cl_type, cl_entry) VALUES (?, ?, ?, ?)");
$stmt->bindParam(1, $prNumber, PDO::PARAM_INT);
$stmt->bindParam(2, $username, PDO::PARAM_STR);
$stmt->bindParam(3, $changelogEntry["type"], PDO::PARAM_STR);
$stmt->bindParam(4, $changelogEntry["body"], PDO::PARAM_STR);
$stmt->execute();
}
$conn = null; // Close the DB connection
}
function sendtoallservers($str) {
global $servers;
foreach ($servers as $serverid => $server) {
if (isset($server['comskey']))
$rtn = export($server['address'], $server['port'], $str.'&key='.$server['comskey']);
else
$rtn = export($server['address'], $server['port'], $str);
echo "Server Number $serverid replied: $rtn\n";
}
}
function export($addr, $port, $str) {
global $error;
// All queries must begin with a question mark (ie "?players")
if($str{0} != '?') $str = ('?' . $str);
/* --- Prepare a packet to send to the server (based on a reverse-engineered packet structure) --- */
$query = "\x00\x83" . pack('n', strlen($str) + 6) . "\x00\x00\x00\x00\x00" . $str . "\x00";
/* --- Create a socket and connect it to the server --- */
$server = socket_create(AF_INET,SOCK_STREAM,SOL_TCP) or exit("ERROR");
socket_set_option($server, SOL_SOCKET, SO_SNDTIMEO, array('sec' => 2, 'usec' => 0)); //sets connect and send timeout to 2 seconds
if(!socket_connect($server,$addr,$port)) {
$error = true;
return "ERROR";
}
/* --- Send bytes to the server. Loop until all bytes have been sent --- */
$bytestosend = strlen($query);
$bytessent = 0;
while ($bytessent < $bytestosend) {
//echo $bytessent.'<br>';
$result = socket_write($server,substr($query,$bytessent),$bytestosend-$bytessent);
//echo 'Sent '.$result.' bytes<br>';
if ($result===FALSE) die(socket_strerror(socket_last_error()));
$bytessent += $result;
}
/* --- Idle for a while until recieved bytes from game server --- */
$result = socket_read($server, 10000, PHP_BINARY_READ);
socket_close($server); // we don't need this anymore
if($result != "") {
if($result{0} == "\x00" || $result{1} == "\x83") { // make sure it's the right packet format
// Actually begin reading the output:
$sizebytes = unpack('n', $result{2} . $result{3}); // array size of the type identifier and content
$size = $sizebytes[1] - 1; // size of the string/floating-point (minus the size of the identifier byte)
if($result{4} == "\x2a") { // 4-byte big-endian floating-point
$unpackint = unpack('f', $result{5} . $result{6} . $result{7} . $result{8}); // 4 possible bytes: add them up together, unpack them as a floating-point
return $unpackint[1];
}
else if($result{4} == "\x06") { // ASCII string
$unpackstr = ""; // result string
$index = 5; // string index
while($size > 0) { // loop through the entire ASCII string
$size--;
$unpackstr .= $result{$index}; // add the string position to return string
$index++;
}
return $unpackstr;
}
}
}
//if we get to this point, something went wrong;
$error = true;
return "ERROR";
}
-4
View File
@@ -1,4 +0,0 @@
@echo off
rem Cheridan asked for this. - N3X
call python ss13_genchangelog.py ../html/changelog.html ../html/changelogs
pause
+3
View File
@@ -0,0 +1,3 @@
# Old Changelog System
This directory contains all the data for the old changelog system
+5
View File
@@ -0,0 +1,5 @@
@echo off
rem Cheridan asked for this. - N3X
rem This has been updated to use the old changelog directories as of PR #13051 -AA
call python ss13_genchangelog.py ../../html/archived_changelog/changelog.html ../../html/archived_changelog/changelogs
pause
-5
View File
@@ -1,5 +0,0 @@
#!/bin/bash
set -euo pipefail
md5sum -c - <<< "6dc1b6bf583f3bd4176b6df494caa5f1 *html/changelogs/example.yml"
python tools/ss13_genchangelog.py html/changelog.html html/changelogs