How to make a clickable link that executes a command with bukkit - minecraft

I'm trying to make a bukkit plugin and I can't seem to find any documentation on this but I've seen it done, How would I input commands into a chat message that a user could click on to execute a command on the server like "/motd" in the form of a clickable link like a URL
if (commandLabel.equalsIgnoreCase("cmd") {
player.sendMessage("Pick a command: " + </motd> + ", " + </mail> );
}
replacing "" and "" to output something like this:
Pick a command: MOTD, Mail
and clicking them would execute the command to the server as them. How would I do this?

You could do it like this:
IChatBaseComponent comp = ChatSerializer
.a("{\"text\":\"" + "Choose one: " + "\",\"extra\":[{\"text\":\"" + "MOTD" + "\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"" + "/motd" + "\"}}]}");
PacketPlayOutChat packet = new PacketPlayOutChat(comp, true);
((CraftPlayer) <player>).getHandle().playerConnection.sendPacket(packet);
This would send them a message showing:
Choose one: MOTD
and when the user clicked MOTD, it would run the command /motd as the player. Here's a little breakdown of what we're actually doing:
IChatBaseComponent comp = ChatSerializer
.a("{\"text\":\"" + "<Ignored Message> " +
"\",\"extra\":[{\"text\":\"" + "<Message that will be clicked>" +
"\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"" +
"<Command to be run when message is clicked>" + "\"}}]}");
PacketPlayOutChat packet = new PacketPlayOutChat(comp, true);
((CraftPlayer) <player>).getHandle().playerConnection.sendPacket(packet);
The above code will send the player:
<Ignored Message> <Message that will be clicked>
and when the player clicks <Message that will be clicked>
they will run the command <Command to be run when a message is clicked>, and because it does not start with the command prefix, /, it will force them to chat <Command to be run when a message is clicked>.
Unfortunately, as far as I know, you can only put one click event per message, so you would have to do something like this:
Choose one:
MOTD
Mail
So you would have to do, where the variable player is the player:
player.sendMessage("Choose one:");
IChatBaseComponent comp = ChatSerializer
.a("{\"text\":\"" +
"\",\"extra\":[{\"text\":\"" + "MOTD" +
"\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"" +
"/motd" + "\"}}]}");
PacketPlayOutChat packet = new PacketPlayOutChat(comp, true);
((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet);
IChatBaseComponent comp2 = ChatSerializer
.a("{\"text\":\"" +
"\",\"extra\":[{\"text\":\"" + "Mail" +
"\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"" +
"/mail" + "\"}}]}");
PacketPlayOutChat packet2 = new PacketPlayOutChat(comp2, true);
((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet2);
When MOTD is clicked, /motd will be run by the player, and when Mail is clicked, /mail will be run.
Just as a side note, you will need to include craftbukkit in your build path, along with bukkit to do this

Or you could simply just do this (I did my own, You can edit it)
/execute #a ~ ~ ~ tellraw #p ["",{"text":"Click this to die","color":"dark_red","bold":true,"clickEvent":{"action":"run_command","value":"/kill #p"},"hoverEvent":{"action":"show_text","value":{"text":"","extra":[{"text":"Kills you!"}]}}}]
run_command can be replaced with Open URL too.
You can replace dark red with any colour too. You can replace true with false for bold if you want, /kill #p can be replaced with a command (Or a https:// link if you do Open URL, show_text can be replaced with Show Item, Show entity, or Show Achivement. Text & Kills you can be replaced with the different thing (eg, Show entity) (Entity replaces text)
I found a website if your stuck! Good day :) http://minecraftjson.com/

Related

selenium with firefox close tab by javascript but SetTimeout() not ok

I use multithreaded way to open tab and when page finish load close tab
this is my open tab code
((JavascriptExecutor)webDriver).executeScript("window.open('"+url+"')");
When close tab,i iterate webDriver.getWindowHandles() and use function executeScript,but find some error,this is my code
this code work ok in chrome,it close all tab,but in firefox some windowHandler are closed and some not
((JavascriptExecutor) webDriver).executeScript("setTimeout(function(){window.close()},10000)");
or
((JavascriptExecutor) webDriver).executeScript("setInterval(function(){window.close()},10000)");
I try to use this code, but it's also like above code
((JavascriptExecutor) webDriver).executeScript("var script = document.createElement('script');\n" +
"script.type = 'text/javascript';\n" +
"script.innerHTML = 'setTimeout(function(){window.close()},10000);';\n" +
"script.innerHTML = 'window.close()';\n" +
"document.body.appendChild(script);");
but when i delete "script.innerHTML = 'setTimeout(function(){window.close()},10000);';\n" + only use window.close() it work close all tab, but does not meet the needs
so i think maybe setTimeout and setInterval function cause this problem in firefox
then i change code to this
((JavascriptExecutor) webDriver).executeScript("var start = null;\n" +
"\n" +
"function step(timestamp) {\n" +
" if (!start) start = timestamp;\n" +
" var progress = timestamp - start;\n" +
" if (progress < 2000) {\n" +
" window.requestAnimationFrame(step);\n" +
" } else {\n" +
" window.close();\n" +
" }\n" +
"}\n" +
"\n" +
"window.requestAnimationFrame(step);");
it's also some windowHandler are closed and some not
i don't know how can i close tab in firefox by javascript
The requirement is to close the tab directly after 10 seconds, or close the tab after the page is loaded
I'm not sure I fully understand the question but it seems you are trying to open a new tab, run some code, then close 10 seconds after it was opened?
I've tested this in firefox and it works with multiple tabs and each one closes on it's own.
((JavascriptExecutor) webDriver).executeScript(
"function openAndClose(url, timeout){" +
" var tab = window.open(url);" +
" setTimeout(function(){tab.close()},timeout);" +
"}" +
"openAndClose('https://www.google.com', 3000);");
If this is not it, could you explain your problem a little more clearly.

console log using selenium certain messages are getting truncated abruptly

I am trying to validate the browser console messages via selenium api certain messages are getting truncated abruptly and all these messages begin with some icon.
So for example expected messages is this “xyz-ENa50707a1661440e4a3070d8206797cf4.min.js?cb=1523503349:15 icon Rule "xyz" fired.” but what i am getting is "“xyz-ENa50707a1661440e4a3070d8206797cf4.min.js?cb=1523503349:15 icon".
my code is like
LogEntries logEntries = driver.manage().logs().get(LogType.BROWSER);
logEntries.getAll();
for (LogEntry entry : logEntries) {
System.out.println(new Date(entry.getTimestamp()) + " " + entry.getLevel() + " " + entry.getMessage());
}
Any suggestion.
even System.setOut(printStream); not able capture full string in message.

Scrapy can't figure out an sql query ins ajax call

I am trying to scrape data from this link https://www.flatstats.co.uk/racing-system-builder.php using scrapy.
I want to automate the ajax call using scrapy.
When I click "Full SP" Button (inspect in Firebug) the post parameter has the sql string which is "strange"
race|2|eq|Ordinary|0|~tRIDER_TYPE
What dialect is this?
My code :
import scrapy
import urllib
class FlatStat(scrapy.Spider):
name= "flatstat"
allowed_domains = ["flatstats.co.uk"]
start_urls = ["https://www.flatstats.co.uk/racing-system-builder.php"]
def parse(self, response):
query_lst = response.xpath('//table[#id="system"]//tr/td[last()]/text()').extract()
query_str = ' '.join(query_lst)
url = 'https://www.flatstats.co.uk/ajax/sb_report.php'
body_dict = {'a_e_max': '9.99',
'a_e_min': '0',
'arch_min': '0',
'exp_min': '0',
'report_type':'S',
# copied from the Post parameters by inspecting. Actually I tried everything.
'sqlFullString' : u'''Type%20(Rider)%7C%3D%7COrdinary%20(Exclude%20Amatr%2C%20App%2C%20Lady%20Races
)%7CAND%7Crace%7C2%7C0%7COrdinary%7C0%7C~tRIDER_TYPE%7C-t%7Ceq''',
#I tried copying this from the post parameters as well but no success.
#I also tried sql from the table //td text() which is "normal" sql but no success
'sqlString': query_str}
#here i tried everything FormRequest as well though there is no form.
return scrapy.Request(url, method="POST", body=urllib.urlencode(body_dict), callback=self.parse_page)
def parse_page(self, response):
with open("response.html", "w") as f:
f.write(response.body)
So questions are:
What is this sql.
Why isn't it returning me the required page. How can I run the right query?
I tried Selenium as well to click the button and let it do the stuff it self but that is another unsuccessful story. :(
It's not easy to say what the website creator is doing with the submitted sqlString. It probably means something very specific to how the data is processed by their backend.
This is an extract of the page JavaScript in-HTML code:
...
function system_report(type) {
sqlString = '', sqlFullString = '', rowcount = 0;
$('#system tr').each(function() {
if(rowcount > 0) {
var editdata = this.cells[6].innerHTML.split("|");
sqlString += editdata[0] + '|' + editdata[1] + '|' + editdata[7] + '|' + editdata[3] + '|' + editdata[4] + '|' + editdata[5] + '^';
sqlFullString += this.cells[0].innerHTML + '|' + encodeURIComponent(this.cells[1].innerHTML) + '|' + this.cells[2].innerHTML + '|' + this.cells[3].innerHTML + '|' + this.cells[6].innerHTML + '^';
}
rowcount++;
});
sqlString = sqlString.slice(0, -1)
...
Looks non trivial to reverse-engineer.
Although it's not a solution to your "sql" question above, I suggest that you try using splash (an alternative to selenium in some cases).
You can launch it with docker (the easiest way):
$ sudo docker run -p 5023:5023 -p 8050:8050 -p 8051:8051 scrapinghub/splash
With the following script:
function main(splash)
local url = splash.args.url
assert(splash:go(url))
assert(splash:wait(0.5))
-- this clicks the "Full SP" button
assert(splash:runjs("$('#b-full-report').click()"))
-- loading the report takes some time
assert(splash:wait(5))
return {
html = splash:html()
}
end
you can get the page HTML with the popup of the report.
You can integrate Splash with Scrapy using scrapyjs (a.k.a scrapy-splash)
See https://stackoverflow.com/a/35851072/ with an example how to do so with a custom script.

How do I show Error Message using Managed Custom Actions with Windows Installer

I am writing a managed custom action. I am using the DTF Framework from Windows Installer Xml to wrap the managed dll into a usable CA dll. The CA does what it is supposed to, but I am still having trouble with error handling:
Dim record As New Record(1)
' Field 0 intentionally left blank
' Field 1 contains error number
record(1) = 27533
session.Message(InstallMessage.Error, record)
The above code produces the following text shown in the MSI log:
MSI (c) (C4 ! C6) [13:15:08:749]: Product: TestMSI -- Error 27533. The case-sensitive passwords do not match.
The error number refers to the code contained in the Error table within the MSI. The Message shown above is correct.
My problem is: Why does Windows Installer NOT create a dialog notifying the user about the error?
MSI can do this, but you need to OR in some extra values for the messageType argument.
eg.
Record record = new Record();
record.FormatString = string.Format("Something has gone wrong!");
session.Message(
InstallMessage.Error | (InstallMessage) ( MessageBoxIcon.Error ) |
(InstallMessage) MessageBoxButtons.OK,
record );
See this thread from the wix-users mailing list for more details.
I have run into the same problem, according to Wix: A Developer's Guide to Windows Installer XML by Nick Ramirez, the log and message methods don't work when a custom action is called from a UI control.
If you want a dialog to show up that contains the message, you must do it yourself.
Here's some code I use to do error handling in managed custom actions that run SQL.
It shows a messagebox if the installation is operating with a full UI.
It's in c# but hopefully you'll get the idea.
private void _handleSqlException(SqlException ex)
{
StringBuilder errorMessage = new StringBuilder();
errorMessage.Append("A SQL error has occurred.");
for (int i = 0; i < ex.Errors.Count; i++)
{
errorMessage.Append("Index #" + i + "\n" +
"Message: " + ex.Errors[i].Message + "\n" +
"LineNumber: " + ex.Errors[i].LineNumber + "\n" +
"Source: " + ex.Errors[i].Source + "\n" +
"Procedure: " + ex.Errors[i].Procedure + "\n");
}
session.Log(errorMessage);
if (session["UILevel"] == "5")
{
MessageBox.Show(errorMessage);
}
}

Script to change Action Sequence records in an MSI

To solve a problem listed here I've got to change the InstallExecuteSequence .RemoveExistingProducts record in an MSI.
I want to do this as part of the build process rather than mucking around with Orca
Modifying the MSI_SetProperty.js script gives
// MSI_SetActionSequence.js <msi-file> <table> <action> <sequence>
// Performs a post-build fixup of an msi to set the specified table/action/sequence
// Constant values from Windows Installer SDK
var msiOpenDatabaseModeTransact = 1;
var msiViewModifyInsert = 1;
var msiViewModifyUpdate = 2;
var msiViewModifyAssign = 3;
var msiViewModifyReplace = 4;
var msiViewModifyDelete = 6;
if (WScript.Arguments.Length != 4)
{
WScript.StdErr.WriteLine("Usage: " + WScript.ScriptName + " file table action sequence");
WScript.Quit(1);
}
var filespec = WScript.Arguments(0);
var table = WScript.Arguments(1);
var action = WScript.Arguments(2);
var sequence = parseInt(WScript.Arguments(3));
var installer = WScript.CreateObject("WindowsInstaller.Installer");
var database = installer.OpenDatabase(filespec, msiOpenDatabaseModeTransact);
WScript.StdOut.WriteLine("Looking for action:" + action);
try
{
var sql = "SELECT Action, Sequence FROM " + table + " WHERE Action = '" + action + "'";
var view = database.OpenView(sql);
view.Execute();
var record = view.Fetch();
if (record)
{
while (record)
{
WScript.StdOut.Write("Found: " + record.StringData(0) + ", " + record.StringData(1) + ", " + record.StringData(2));
if (record.IntegerData(2) != sequence)
{
WScript.StdOut.WriteLine(" - changing to " + sequence);
record.IntegerData(2) = sequence;
view.Modify(msiViewModifyUpdate,record);
}
else
WScript.StdOut.WriteLine(" - OK");
record = view.Fetch();
}
view.Close();
database.Commit();
}
else
{
view.Close();
throw("Warning - Could not find " + table + "." + action);
}
}
catch(e)
{
WScript.StdErr.WriteLine(e);
WScript.Quit(1);
}
To call this script to perform the change to the action sequence mentioned above you would put the following in a batch file and call that from the post build event e.g. PostBuildEvent = $(ProjectDir)PostBuild.bat
cscript.exe MSI_SetActionSequence.js YOURINSTALLER.MSI InstallExecuteSequence RemoveExistingProducts 1525
Some notes to others out there. I had the "Error 1001. The specified service already exists" problem, and tried the above and it didn't seem to work. Here's what I ran into:
* Make sure the RemovePreviousVersions property on your installer project is set to True. This seems obvious--obvious, that is, if you know about it. By default it is set to False. If False, the above procedure will not solve your problem. *
I have some assemblies installed in the GAC. It appears that when I moved the RemoveExistingProducts sequence that these files were removed from the GAC, but not reinstalled. To solve this I installed all assemblies in the Application Folder. FYI, I'm using VS2010.
Also, another nit-pick. If a user selects "Repair" when attempting to reinstall the same version of a product, they will still get "The specified service already exists" error. If I get time I'll try to fix this. If someone else out there knows how to fix it, could you post?
All that said, thanks for posting this!
The solution provided by Ryan addresses part of the issue I am facing. It does perform full uninstall, followed by install.
However, I have another issue, in my case some of the programs are running in the background. Before the installer can run, the installer complains that some of the files are in use. And gives standard dialog box asking for either to close the application, or restart to complete updating.
Is there a way, eg. a custom action or a setting, to kill the processes running in the background so that the installer goes smoothly?