(https://i.ibb.co/9VdssZV/colscreen.png) (https://ibb.co/b2Gzzb2)
https://i.imgur.com/fDo4Gnh.png (https://i.imgur.com/fDo4Gnh.png)
This is one of my old ideas that I finally found time to code. This script is just small example how functions for relative position and finding an angle (in 3d) (https://forum.vc-mp.org/index.php?topic=9368.0) can be used. Remote collision screenshot can be helpful to detect map mods (and with little edit - vehicle collisions mods/cheats)
server.nut
colscreen_i <- 0;
function onScriptLoad(){
::SetBackfaceCullingDisabled(true);
::SetMaxPlayers(12);
::SetUseClasses(true);
::SetServerName("Collision screenshot script");
::SetGameModeName("snippet");
::SetFriendlyFire(false);
::SetShowOnRadar(true);
::SetShowOnlyTeamMarkers(false);
::SetSpawnPlayerPos(::Vector(191.924, -468.823, 17.547));
::SetSpawnCameraPos(::Vector(194.041, -467.79, 17.547));
::SetSpawnCameraLook(::Vector(191.924, -468.823, 17.547));
::SetSyncFrameLimiter(false);
::SetFrameLimiter(false);
::SetTaxiBoostJump(true);
::SetDriveOnWater(false);
::SetFastSwitch(false);
::SetJumpSwitch(true);
::SetWallglitch(true);
::SetDrivebyEnabled(true);
::SetPerfectHandling(false);
::SetFlyingCars(false);
::SetDeathMessages(false);
::SetJoinMessages(false);
::SetWeather(4);
::SetHour(12);
::SetMinute(0);
::SetTimeRate(0);
::SetGravity(0.008);
::SetGamespeed(1.0);
if("SetFallTimer" in ::getroottable()){
::SetFallTimer(500);// rel006 feature
}
::SetWaterLevel(6.0);
::SetShootInAir(false);
::SetShowNametags(true);
::SetStuntBike(false);
::SetPassword("");
::SetVehiclesForcedRespawnHeight(19999);
::SetMaxHeight(300);
::AddClass(161, ::RGB(0, 200, 180), 0, ::Vector(191.924, -468.823, 17.547), -57.2958, 0, 0, 0, 0, 0, 0);
::SetWastedSettings(1500, 1500, 0.1, 0.1, ::RGB(0,0,0), 1000, 500);
::SetKillDelay(100);
}
function onLoginAttempt(playerName, password, ipAddress){
return true;
}
function onPlayerJoin(player){
player.Name = player.Name + player.ID;
}
function onPlayerRequestClass(player, classID, team, skin){
return true;
}
function onPlayerRequestSpawn(player){
return true;
}
function onPlayerCommand(player, cmd, text){
if(cmd == "colscreen"){
if(!text){return ::MessagePlayer("Error - command syntax: /colscreen <player ID> <depth>", player);}
local text_arr = split(text, " ");
if(text_arr.len() != 2){return ::MessagePlayer("Error - command syntax: /colscreen <player ID> <depth>", player);}
local depth = text_arr[1].tointeger();
if((depth < 10)||(depth > 1000)){
return ::MessagePlayer("use depth from 10 to 1000", player);
}
if(text_arr[0]){
local target = ::FindPlayer(text_arr[0].tointeger());
if(target){
::colscreen_i++;
local s = ::Stream();
s.StartWrite();
s.WriteByte(102);
s.WriteByte(1);
s.WriteInt(::colscreen_i); // uniq id of screenshot
s.WriteByte(target.ID);
s.WriteInt(depth);
s.SendStream(player); // recipient
::MessagePlayer("Starting process of collision screenshot", player);
} else {
return ::MessagePlayer("Error - target player not found", player);
}
}
} else if((cmd == "colscreenstop")||(cmd == "stopcolscreen")){
if(!text){return ::MessagePlayer("Error - command syntax: /colscreenstop <player ID>", player);}
local target = ::FindPlayer(text.tointeger());
if(target){
::colscreen_i++;
local s = ::Stream();
s.StartWrite();
s.WriteByte(102);
s.WriteByte(5);
s.SendStream(target);
local s = ::Stream();
s.StartWrite();
s.WriteByte(102);
s.WriteByte(6);
s.SendStream(player);
::MessagePlayer("Process of collision screenshot is aborted", player);
} else {
return ::MessagePlayer("Error - target player not found", player);
}
}
}
function onClientScriptData(player){
local netcode = ::Stream.ReadByte();
if(netcode == 102){
local colscreen_netcode = ::Stream.ReadByte();
if(colscreen_netcode == 2){
local colscreen_i = ::Stream.ReadInt();
local target_id = ::Stream.ReadByte();
local depth = ::Stream.ReadInt();
local target = ::FindPlayer(target_id);
if(target){
local x1 = ::Stream.ReadFloat();
local y1 = ::Stream.ReadFloat();
local z1 = ::Stream.ReadFloat();
local x2 = ::Stream.ReadFloat();
local y2 = ::Stream.ReadFloat();
local z2 = ::Stream.ReadFloat();
local s = ::Stream();
s.StartWrite();
s.WriteByte(102);
s.WriteByte(3);
s.WriteInt(colscreen_i);
s.WriteByte(player.ID); // recipient
s.WriteInt(depth);
s.WriteFloat(x1);
s.WriteFloat(y1);
s.WriteFloat(z1);
s.WriteFloat(x2);
s.WriteFloat(y2);
s.WriteFloat(z2);
s.SendStream(target);
} else {
return ::MessagePlayer("Error - target player not online anymore", player);
}
} else if(colscreen_netcode == 4){
local colscreen_i = ::Stream.ReadInt();
local recipient_id = ::Stream.ReadByte();
local y = ::Stream.ReadInt();
local l = ::Stream.ReadInt();
local row = [];
for(local i = 0; i < l; i++){
row.push(::Stream.ReadByte());
}
local recipient = ::FindPlayer(recipient_id);
if(recipient){
local s = ::Stream();
s.StartWrite();
s.WriteByte(102);
s.WriteByte(4);
s.WriteInt(colscreen_i);
s.WriteInt(y);
s.WriteInt(l);
for(local i = 0; i < l; i++){
s.WriteByte(row[i]);
}
s.SendStream(recipient);
}
}
}
}
client (main.nut)
colscreen <- {
"last_update" : {},
"screenshot" : {},
"last_call" : ::Script.GetTicks(),
"recording" : false,
"colscreen_i" : 0,
"colscreen_i_recipient" : 0,
"row_result" : [],
"recipient_id" : 0,
"depth" : 0,
"x" : 0,
"y" : 0,
"x1" : 0,
"y1" : 0,
"z1" : 0,
"x2" : 0,
"y2" : 0,
"z2" : 0,
"angle" : 0,
"vangle" : 0,
"fov_per_pixel" : ::Vector(0.005, 0.007, 0), // its optimal for default screenshot_size
"screenshot_size" : ::VectorScreen(252, 142), // resolution of screen, don't use big values to avoid waste of time
"screenshot_sizeh" : false,
"rays_per_frame" : 1000, // you can limit it for low-end PC; wont be used more than screenshot_size.X
"start" : function(colscreen_i, recipient_id, depth, x1, y1, z1, x2, y2, z2){
::colscreen.colscreen_i = colscreen_i;
::colscreen.recipient_id = recipient_id;
::colscreen.depth = depth;
::colscreen.x1 = x1;
::colscreen.y1 = y1;
::colscreen.z1 = z1;
::colscreen.x2 = x2;
::colscreen.y2 = y2;
::colscreen.z2 = z2;
::colscreen.vangle = ::colscreen.get_vangle(x1, y1, z1, x2, y2, z2);
::colscreen.angle = ::colscreen.get_angle(x1, y1, x2, y2);
::colscreen.screenshot_sizeh = ::VectorScreen(::colscreen.screenshot_size.X * 0.5, ::colscreen.screenshot_size.Y * 0.5);
::colscreen.x = -::colscreen.screenshot_sizeh.X;
::colscreen.y = -::colscreen.screenshot_sizeh.Y;
::colscreen.row_result = [];
::colscreen.recording = true;
},
"normalize_angle" : function (a){
return ::atan2(::sin(a), ::cos(a));
},
"get_vangle" : function(x1, y1, z1, x2, y2, z2){
return ::atan2(z2 - z1, ::colscreen.dist_2d(x2,y2,x1,y1));
},
"get_angle" : function(x, y, x2, y2){
return ::atan2(y2 - y, x2 - x);
},
"rel_pos3d" : function(dist, pos_x, pos_y, pos_z, y_angle, z_angle){
local rX = dist * ::cos(y_angle) * ::cos(z_angle);
local rY = dist * ::cos(y_angle) * ::sin(z_angle);
local rZ = dist * ::sin(y_angle);
return ::Vector(pos_x + rX, pos_y + rY, pos_z + rZ);
},
"dist_3d" : function (x, y, z, x2, y2, z2){
return ::sqrt((x - x2)*(x - x2) + (y - y2)*(y - y2) + (z - z2)*(z - z2));
},
"dist_2d" : function (x, y, x2, y2){
return ::sqrt((x - x2)*(x - x2) + (y - y2)*(y - y2));
},
"proc" : function(){
if(true == ::colscreen.recording){
if(::colscreen.rays_per_frame < 1){
return false;
}
for(local i = 0; i < ::colscreen.rays_per_frame; i++){
local rel_pos3d = ::colscreen.rel_pos3d(depth, x1, y1, z1, ::colscreen.normalize_angle(::colscreen.vangle + (-1 * (::colscreen.y * ::colscreen.fov_per_pixel.Y))), ::colscreen.normalize_angle(::colscreen.angle + ( (::colscreen.x * ::colscreen.fov_per_pixel.X))));
local rt = ::RayTrace(::Vector(x1, y1, z1), rel_pos3d, RAY_BUILDING | RAY_OBJECT);
local depth_color = 255;
if(rt.Collided){
local dist = ::colscreen.dist_3d(x1, y1, z1, rt.Position.X, rt.Position.Y, rt.Position.Z);
depth_color = ((255 / depth.tofloat()) * dist).tointeger();
if(depth_color > 255){
depth_color = 255;
}
}
::colscreen.row_result.push(depth_color);
::colscreen.x++;
if(::colscreen.x >= ::colscreen.screenshot_sizeh.X){
local s = Stream();
s.WriteByte(102);
s.WriteByte(4);
s.WriteInt(::colscreen.colscreen_i);
s.WriteByte(::colscreen.recipient_id);
s.WriteInt(::colscreen.y);
local l = ::colscreen.row_result.len();
s.WriteInt(l);
for(local i = 0; i < l; i++){
s.WriteByte(::colscreen.row_result[i]);
}
::Server.SendData(s);
::colscreen.row_result = [];
::colscreen.x = -::colscreen.screenshot_sizeh.X;
::colscreen.y++;
if(::colscreen.y >= ::colscreen.screenshot_sizeh.Y){
::colscreen.recording = false;
}
return true;
}
}
}
},
"on_server_data" : function(stream){
local colscreen_netcode = stream.ReadByte();
if(colscreen_netcode == 1){
::colscreen.colscreen_i_recipient = stream.ReadInt();
local target_id = stream.ReadByte();
local depth = stream.ReadInt();
local screen_size = ::GUI.GetScreenSize();
local camera_pos_from = ::GUI.ScreenPosToWorld(::Vector(screen_size.X * 0.5, screen_size.Y * 0.5, -1));
local camera_pos_to = ::GUI.ScreenPosToWorld(::Vector(screen_size.X * 0.5, screen_size.Y * 0.5, 1));
local s = Stream();
s.WriteByte(102);
s.WriteByte(2);
s.WriteInt(::colscreen.colscreen_i_recipient);
s.WriteByte(target_id);
s.WriteInt(depth);
s.WriteFloat(camera_pos_from.X);
s.WriteFloat(camera_pos_from.Y);
s.WriteFloat(camera_pos_from.Z);
s.WriteFloat(camera_pos_to.X);
s.WriteFloat(camera_pos_to.Y);
s.WriteFloat(camera_pos_to.Z);
::Server.SendData(s);
} else if(colscreen_netcode == 3){
local colscreen_i = stream.ReadInt();
local recipient_id = stream.ReadByte();
local depth = stream.ReadInt();
local x1 = stream.ReadFloat();
local y1 = stream.ReadFloat();
local z1 = stream.ReadFloat();
local x2 = stream.ReadFloat();
local y2 = stream.ReadFloat();
local z2 = stream.ReadFloat();
::colscreen.start(colscreen_i, recipient_id, depth, x1, y1, z1, x2, y2, z2);
} else if(colscreen_netcode == 4){
local colscreen_i = stream.ReadInt();
if(colscreen_i == ::colscreen.colscreen_i_recipient){
local y = stream.ReadInt();
local l = stream.ReadInt();
local screen_size = ::GUI.GetScreenSize();
local screenshot_pos = ::VectorScreen((screen_size.X * 0.5), (screen_size.Y * 0.5));
for(local i = 0; i < l; i++){
local x = (::colscreen.screenshot_size.X * 0.5).tointeger() - i;
local pixel = stream.ReadByte();
local c = ::GUICanvas();
c.Size = ::VectorScreen(1, 1);
c.Position = ::VectorScreen(screenshot_pos.X + x, screenshot_pos.Y + y);
c.Colour = ::Colour(pixel, pixel, pixel, 255);
::colscreen.screenshot.rawset(x +"."+ y, c);
}
}
} else if(colscreen_netcode == 5){
::colscreen.recording = false;
::colscreen.row_result = [];
} else if(colscreen_netcode == 6){
::colscreen.screenshot = {};
}
}
}
function Server::ServerData(stream){
local netcode = stream.ReadByte();
if(netcode == 102){
::colscreen.on_server_data(stream);
}
}
function Script::ScriptProcess(){
::colscreen.proc();
}
Thats clever. thanks for sharing
Woah! This is big!
what exactly does this do? Why is there a picture on the man's head.
Quote from: habi2 on Aug 29, 2024, 04:08 AMwhat exactly does this do? Why is there a picture on the man's head.
this takes camera position from admin (guy who typed command), then send this position to target player, on side of target player: script send raytrace from camera position to world, and send back relative distance (0-255, based on <depth>) row by row back to admin to draw picture of raytrace image
ingame printer 😎😅
Quote from: vitovc on Aug 29, 2024, 06:45 AMthis takes camera position from admin (guy who typed command), then send this position to target player, on side of target player: script send raytrace from camera position to world, and send back relative distance (0-255, based on <depth>) row by row back to admin to draw picture of raytrace image
So that picture above tommy's head is a depth-row-by-row raytrace result you made.
God, now i understand.
Good work.
This feature seems to be able to test if the player has made changes to the map, such as deleting a building, etc., should be able to use this feature to see, I will try to modify your code for real-time monitoring of the player's screen, thank you for making and sharing this very cool feature.
Quote from: PSL on Oct 30, 2024, 06:13 AMI will try to modify your code for real-time monitoring of the player's screen
Raytrace function is using CPU too much, real-time is possible only for very low-resolution and low recoding frames per second.