Gun no longer runs on separate thread. Fixes #449.

This commit is contained in:
UnknownShadow200 2017-06-13 17:41:31 +10:00
parent 4b2eb16806
commit 163638e8b5
3 changed files with 148 additions and 135 deletions

View File

@ -19,8 +19,9 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using MCGalaxy.Maths; using MCGalaxy.Maths;
using MCGalaxy.Tasks;
namespace MCGalaxy.Commands.Fun { namespace MCGalaxy.Commands.Fun {
public sealed class CmdGun : WeaponCmd { public sealed class CmdGun : WeaponCmd {
public override string name { get { return "gun"; } } public override string name { get { return "gun"; } }
protected override string Weapon { get { return "Gun"; } } protected override string Weapon { get { return "Gun"; } }
@ -29,70 +30,80 @@ namespace MCGalaxy.Commands.Fun {
p.RevertBlock(x, y, z); p.RevertBlock(x, y, z);
if (!CommandParser.IsBlockAllowed(p, "place", block)) return; if (!CommandParser.IsBlockAllowed(p, "place", block)) return;
Thread gunThread = new Thread(() => DoShoot(p, block)); WeaponArgs args = new WeaponArgs();
gunThread.Name = "MCG_Gun"; args.player = p;
gunThread.Start(); args.block = block;
args.weaponType = (WeaponType)p.blockchangeObject;
args.start = MakePos(p);
args.dir = DirUtils.GetFlatDirVector(p.Rot.RotY, p.Rot.HeadX);
args.pos = args.PosAt(3);
args.iterations = 4;
SchedulerTask task = new SchedulerTask(GunCallback, args, TimeSpan.Zero, true);
p.CriticalTasks.Add(task);
} }
void DoShoot(Player p, ExtBlock block) { static void GunCallback(SchedulerTask task) {
CatchPos bp = (CatchPos)p.blockchangeObject; WeaponArgs args = (WeaponArgs)task.State;
Vec3F32 dir = DirUtils.GetFlatDirVector(p.Rot.RotY, p.Rot.HeadX); if (args.moving) {
args.moving = MoveGun(args);
// Laser gun persists for a short while
if (!args.moving && args.weaponType == WeaponType.Laser)
task.Delay = TimeSpan.FromMilliseconds(400);
return;
}
double bigDiag = Math.Sqrt(Math.Sqrt(p.level.Width * p.level.Width + p.level.Length * p.level.Length) args.TeleportSourcePlayer();
+ p.level.Height * p.level.Height + p.level.Width * p.level.Width); if (args.weaponType == WeaponType.Laser) {
foreach (Vec3U16 pos in args.previous) {
args.player.level.Blockchange(pos.X, pos.Y, pos.Z, ExtBlock.Air, true);
}
args.previous.Clear();
} else if (args.previous.Count > 0) {
Vec3U16 pos = args.previous[0];
args.previous.RemoveAt(0);
args.player.level.Blockchange(pos.X, pos.Y, pos.Z, ExtBlock.Air, true);
}
task.Repeating = args.previous.Count > 0;
}
static bool MoveGun(WeaponArgs args) {
while (true) {
args.pos = args.PosAt(args.iterations);
args.iterations++;
Vec3U16 pos = args.pos;
List<Vec3U16> previous = new List<Vec3U16>(); ExtBlock cur = args.player.level.GetBlock(pos.X, pos.Y, pos.Z);
List<Vec3U16> allBlocks = new List<Vec3U16>(); if (cur.IsInvalid) return false;
Vec3U16 pos; if (cur.BlockID != Block.air && !args.allBlocks.Contains(pos) && HandlesHitBlock(args.player, cur, args.weaponType, pos, true))
return false;
Vec3S32 start = p.Pos.BlockCoords;
pos.X = (ushort)Math.Round(start.X + dir.X * 3);
pos.Y = (ushort)Math.Round(start.Y + dir.Y * 3);
pos.Z = (ushort)Math.Round(start.Z + dir.Z * 3);
for (double t = 4; bigDiag > t; t++) { args.player.level.Blockchange(pos.X, pos.Y, pos.Z, args.block);
pos.X = (ushort)Math.Round(start.X + (double)(dir.X * t)); args.previous.Add(pos);
pos.Y = (ushort)Math.Round(start.Y + (double)(dir.Y * t)); args.allBlocks.Add(pos);
pos.Z = (ushort)Math.Round(start.Z + (double)(dir.Z * t)); if (HitsPlayer(args, pos)) return false;
ExtBlock cur = p.level.GetBlock(pos.X, pos.Y, pos.Z); if (args.iterations > 12 && args.weaponType != WeaponType.Laser) {
if (cur.BlockID != Block.air && !allBlocks.Contains(pos) && HandlesHitBlock(p, cur, bp.ending, pos, true)) pos = args.previous[0];
break; args.previous.RemoveAt(0);
args.player.level.Blockchange(pos.X, pos.Y, pos.Z, ExtBlock.Air, true);
p.level.Blockchange(pos.X, pos.Y, pos.Z, block);
previous.Add(pos);
allBlocks.Add(pos);
if (HandlesPlayers(p, bp, pos)) break;
if (t > 12 && bp.ending != EndType.Laser) {
pos = previous[0];
p.level.Blockchange(pos.X, pos.Y, pos.Z, ExtBlock.Air, true);
previous.RemoveAt(0);
} }
if (bp.ending != EndType.Laser) Thread.Sleep(20); if (args.weaponType != WeaponType.Laser) return true;
}
if (bp.ending == EndType.Teleport) {
int index = previous.Count - 3;
if (index >= 0 && index < previous.Count)
DoTeleport(p, previous[index]);
}
if (bp.ending == EndType.Laser) Thread.Sleep(400);
foreach (Vec3U16 pos1 in previous) {
p.level.Blockchange(pos1.X, pos1.Y, pos1.Z, ExtBlock.Air, true);
if (bp.ending != EndType.Laser) Thread.Sleep(20);
} }
} }
bool HandlesPlayers(Player p, CatchPos bp, Vec3U16 pos) { static Vec3U16 MakePos(Player p) { return (Vec3U16)p.Pos.BlockCoords; }
Player pl = GetPlayer(p, pos, true);
static bool HitsPlayer(WeaponArgs args, Vec3U16 pos) {
Player pl = GetPlayer(args.player, pos, true);
if (pl == null) return false; if (pl == null) return false;
ExtBlock stone = (ExtBlock)Block.stone; ExtBlock stone = (ExtBlock)Block.stone;
if (p.level.physics >= 3 && bp.ending >= EndType.Explode) { Player p = args.player;
if (p.level.physics >= 3 && args.weaponType >= WeaponType.Explode) {
pl.HandleDeath(stone, " was blown up by " + p.ColoredName, true); pl.HandleDeath(stone, " was blown up by " + p.ColoredName, true);
} else { } else {
pl.HandleDeath(stone, " was shot by " + p.ColoredName); pl.HandleDeath(stone, " was shot by " + p.ColoredName);

View File

@ -35,127 +35,102 @@ namespace MCGalaxy.Commands.Fun {
p.RevertBlock(x, y, z); p.RevertBlock(x, y, z);
if (!CommandParser.IsBlockAllowed(p, "place", block)) return; if (!CommandParser.IsBlockAllowed(p, "place", block)) return;
MissileArgs args = new MissileArgs(); WeaponArgs args = new WeaponArgs();
args.player = p; args.player = p;
args.block = block; args.block = block;
CatchPos bp = (CatchPos)p.blockchangeObject; args.weaponType = (WeaponType)p.blockchangeObject;
args.ending = bp.ending;
args.pos = MakePos(p); args.pos = MakePos(p);
SchedulerTask task = new SchedulerTask(MissileCallback, args, SchedulerTask task = new SchedulerTask(MissileCallback, args,
TimeSpan.FromMilliseconds(100), true); TimeSpan.FromMilliseconds(100), true);
p.CriticalTasks.Add(task); p.CriticalTasks.Add(task);
} }
class MissileArgs {
public Player player;
public ExtBlock block;
public EndType ending;
public Vec3U16 pos;
public bool Moving = true;
public List<Vec3U16> previous = new List<Vec3U16>();
public List<Vec3U16> allBlocks = new List<Vec3U16>();
public List<Vec3S32> buffer = new List<Vec3S32>();
public int iterations;
}
static void MissileCallback(SchedulerTask task) { static void MissileCallback(SchedulerTask task) {
MissileArgs args = (MissileArgs)task.State; WeaponArgs args = (WeaponArgs)task.State;
Player p = args.player; if (args.moving) { PerformMove(args); return; }
if (args.Moving) { PerformMove(args); return; }
if (args.ending == EndType.Teleport) {
args.ending = EndType.Normal;
int index = args.previous.Count - 3;
if (index >= 0 && index < args.previous.Count)
DoTeleport(p, args.previous[index]);
}
args.TeleportSourcePlayer();
if (args.previous.Count > 0) { if (args.previous.Count > 0) {
Vec3U16 pos = args.previous[0]; Vec3U16 pos = args.previous[0];
args.previous.RemoveAt(0); args.previous.RemoveAt(0);
p.level.Blockchange(pos.X, pos.Y, pos.Z, ExtBlock.Air, true); args.player.level.Blockchange(pos.X, pos.Y, pos.Z, ExtBlock.Air, true);
} }
task.Repeating = args.previous.Count > 0; task.Repeating = args.previous.Count > 0;
} }
static void PerformMove(MissileArgs args) { static void PerformMove(WeaponArgs args) {
while (true) { while (true) {
args.iterations++; args.iterations++;
Vec3U16 target = MissileTarget(args); Vec3U16 target = MissileTarget(args);
FindNext(target, ref args.pos, args.buffer); FindNext(target, ref args.pos, args.buffer);
if (args.iterations <= 3) continue; if (args.iterations <= 3) continue;
args.Moving = MoveMissile(args, args.pos, target); args.moving = MoveMissile(args, args.pos, target);
return; return;
} }
} }
static Vec3U16 MissileTarget(MissileArgs args) { static Vec3U16 MissileTarget(WeaponArgs args) {
Player p = args.player; Player p = args.player;
Vec3U16 start = MakePos(p); args.start = MakePos(p);
Vec3F32 dir = DirUtils.GetFlatDirVector(p.Rot.RotY, p.Rot.HeadX); args.dir = DirUtils.GetFlatDirVector(p.Rot.RotY, p.Rot.HeadX);
Vec3U16 target;
int i; int i;
for (i = 1; ; i++) { for (i = 1; ; i++) {
target.X = (ushort)Math.Round(start.X + (double)(dir.X * i)); Vec3U16 target = args.PosAt(i);
target.Y = (ushort)Math.Round(start.Y + (double)(dir.Y * i));
target.Z = (ushort)Math.Round(start.Z + (double)(dir.Z * i));
ExtBlock block = p.level.GetBlock(target.X, target.Y, target.Z); ExtBlock block = p.level.GetBlock(target.X, target.Y, target.Z);
if (block.BlockID == Block.Invalid) break; if (block.BlockID == Block.Invalid) break;
if (block.BlockID != Block.air && !args.allBlocks.Contains(target) && HandlesHitBlock(p, block, args.ending, target, false)) if (block.BlockID != Block.air && !args.allBlocks.Contains(target) && HandlesHitBlock(p, block, args.weaponType, target, false))
break; break;
Player hit = GetPlayer(p, target, true); Player hit = GetPlayer(p, target, true);
if (hit != null) return MakePos(hit); if (hit != null) return MakePos(hit);
} }
return args.PosAt(i - 1);
target.X = (ushort)Math.Round(start.X + (double)(dir.X * (i - 1)));
target.Y = (ushort)Math.Round(start.Y + (double)(dir.Y * (i - 1)));
target.Z = (ushort)Math.Round(start.Z + (double)(dir.Z * (i - 1)));
return target;
} }
static bool MoveMissile(MissileArgs args, Vec3U16 pos, Vec3U16 target) { static bool MoveMissile(WeaponArgs args, Vec3U16 pos, Vec3U16 target) {
Player p = args.player; Player p = args.player;
ExtBlock block = p.level.GetBlock(pos.X, pos.Y, pos.Z); ExtBlock block = p.level.GetBlock(pos.X, pos.Y, pos.Z);
if (block.BlockID != Block.air && !args.allBlocks.Contains(pos) && HandlesHitBlock(p, block, args.ending, pos, true)) if (block.BlockID != Block.air && !args.allBlocks.Contains(pos) && HandlesHitBlock(p, block, args.weaponType, pos, true))
return false; return false;
p.level.Blockchange(pos.X, pos.Y, pos.Z, args.block); p.level.Blockchange(pos.X, pos.Y, pos.Z, args.block);
args.previous.Add(pos); args.previous.Add(pos);
args.allBlocks.Add(pos); args.allBlocks.Add(pos);
if (HitsPlayer(args, pos)) return false;
Player hitP = GetPlayer(p, pos, true); if (pos == target && p.level.physics >= 3 && args.weaponType >= WeaponType.Explode) {
if (hitP != null) {
if (p.level.physics >= 3 && args.ending >= EndType.Explode) {
hitP.HandleDeath((ExtBlock)Block.stone, " was blown up by " + p.ColoredName, true);
} else {
hitP.HandleDeath((ExtBlock)Block.stone, " was hit a missile from " + p.ColoredName);
}
return false;
}
if (pos == target && p.level.physics >= 3 && args.ending >= EndType.Explode) {
p.level.MakeExplosion(target.X, target.Y, target.Z, 2); p.level.MakeExplosion(target.X, target.Y, target.Z, 2);
return false; return false;
} }
if (args.previous.Count > 12) { if (args.previous.Count > 12) {
p.level.Blockchange(args.previous[0].X, args.previous[0].Y, args.previous[0].Z, ExtBlock.Air, true); pos = args.previous[0];
p.level.Blockchange(pos.X, pos.Y, pos.Z, ExtBlock.Air, true);
args.previous.RemoveAt(0); args.previous.RemoveAt(0);
} }
return true; return true;
}
static bool HitsPlayer(WeaponArgs args, Vec3U16 pos) {
Player pl = GetPlayer(args.player, pos, true);
if (pl == null) return false;
ExtBlock stone = (ExtBlock)Block.stone;
Player p = args.player;
if (p.level.physics >= 3 && args.weaponType >= WeaponType.Explode) {
pl.HandleDeath(stone, " was blown up by " + p.ColoredName, true);
} else {
pl.HandleDeath(stone, " was hit by a missile from " + p.ColoredName);
}
return true;
} }
static Vec3U16 MakePos(Player p) { static Vec3U16 MakePos(Player p) { return (Vec3U16)p.Pos.BlockCoords; }
return (Vec3U16)p.Pos.BlockCoords;
}
static void FindNext(Vec3U16 lookedAt, ref Vec3U16 pos, List<Vec3S32> buffer) { static void FindNext(Vec3U16 lookedAt, ref Vec3U16 pos, List<Vec3S32> buffer) {
LineDrawOp.DrawLine(pos.X, pos.Y, pos.Z, 2, lookedAt.X, lookedAt.Y, lookedAt.Z, buffer); LineDrawOp.DrawLine(pos.X, pos.Y, pos.Z, 2, lookedAt.X, lookedAt.Y, lookedAt.Z, buffer);

View File

@ -44,10 +44,10 @@ namespace MCGalaxy.Commands.Fun {
return; return;
} }
CatchPos cpos = default(CatchPos); WeaponType weaponType = GetWeaponType(p, message);
cpos.ending = GetEnd(p, message); if (weaponType == WeaponType.Invalid) return;
if (cpos.ending == EndType.Invalid) return;
p.blockchangeObject = cpos; p.blockchangeObject = weaponType;
p.ClearBlockchange(); p.ClearBlockchange();
p.Blockchange += PlacedMark; p.Blockchange += PlacedMark;
@ -61,15 +61,15 @@ namespace MCGalaxy.Commands.Fun {
p.CriticalTasks.Add(task); p.CriticalTasks.Add(task);
} }
EndType GetEnd(Player p, string mode) { WeaponType GetWeaponType(Player p, string mode) {
if (mode == "") return EndType.Normal; if (mode == "") return WeaponType.Normal;
if (mode.CaselessEq("destroy")) return EndType.Destroy; if (mode.CaselessEq("destroy")) return WeaponType.Destroy;
if (mode.CaselessEq("tp") || mode.CaselessEq("teleport")) return EndType.Teleport; if (mode.CaselessEq("tp") || mode.CaselessEq("teleport")) return WeaponType.Teleport;
if (mode.CaselessEq("explode")) return EndType.Explode; if (mode.CaselessEq("explode")) return WeaponType.Explode;
if (mode.CaselessEq("laser")) return EndType.Laser; if (mode.CaselessEq("laser")) return WeaponType.Laser;
Help(p); Help(p);
return EndType.Invalid; return WeaponType.Invalid;
} }
class AimState { class AimState {
@ -137,6 +137,42 @@ namespace MCGalaxy.Commands.Fun {
protected abstract void PlacedMark(Player p, ushort x, ushort y, ushort z, ExtBlock block); protected abstract void PlacedMark(Player p, ushort x, ushort y, ushort z, ExtBlock block);
protected class WeaponArgs {
public Player player;
public ExtBlock block;
public WeaponType weaponType;
public Vec3U16 pos, start;
public Vec3F32 dir;
public bool moving = true;
public List<Vec3U16> previous = new List<Vec3U16>();
public List<Vec3U16> allBlocks = new List<Vec3U16>();
public List<Vec3S32> buffer = new List<Vec3S32>();
public int iterations;
public Vec3U16 PosAt(int i) {
Vec3U16 target;
target.X = (ushort)Math.Round(start.X + (double)(dir.X * i));
target.Y = (ushort)Math.Round(start.Y + (double)(dir.Y * i));
target.Z = (ushort)Math.Round(start.Z + (double)(dir.Z * i));
return target;
}
public void TeleportSourcePlayer() {
if (weaponType != WeaponType.Teleport) return;
weaponType = WeaponType.Normal;
int index = previous.Count - 3;
if (index >= 0 && index < previous.Count) {
Vec3U16 coords = previous[index];
Position pos = new Position(coords.X * 32, coords.Y * 32 + 32, coords.Z * 32);
player.SendPos(Entities.SelfID, pos, player.Rot);
}
}
}
protected static Player GetPlayer(Player p, Vec3U16 pos, bool skipSelf) { protected static Player GetPlayer(Player p, Vec3U16 pos, bool skipSelf) {
Player[] players = PlayerInfo.Online.Items; Player[] players = PlayerInfo.Online.Items;
foreach (Player pl in players) { foreach (Player pl in players) {
@ -153,18 +189,10 @@ namespace MCGalaxy.Commands.Fun {
return null; return null;
} }
protected static void DoTeleport(Player p, Vec3U16 coords) { protected static bool HandlesHitBlock(Player p, ExtBlock block, WeaponType ending, Vec3U16 pos, bool doExplode) {
try { if (p.level.physics < 2 || ending == WeaponType.Teleport || ending == WeaponType.Normal) return true;
Position pos = new Position(coords.X * 32, coords.Y * 32 + 32, coords.Z * 32);
p.SendPos(Entities.SelfID, pos, p.Rot);
} catch {
}
}
protected static bool HandlesHitBlock(Player p, ExtBlock block, EndType ending, Vec3U16 pos, bool doExplode) {
if (p.level.physics < 2 || ending == EndType.Teleport || ending == EndType.Normal) return true;
if (ending == EndType.Destroy) { if (ending == WeaponType.Destroy) {
bool fireKills = block.BlockID != Block.air && p.level.BlockProps[block.Index].LavaKills; bool fireKills = block.BlockID != Block.air && p.level.BlockProps[block.Index].LavaKills;
if ((!fireKills && !Block.NeedRestart(block.BlockID)) && block.BlockID != Block.glass) { if ((!fireKills && !Block.NeedRestart(block.BlockID)) && block.BlockID != Block.glass) {
return true; return true;
@ -180,7 +208,6 @@ namespace MCGalaxy.Commands.Fun {
return false; return false;
} }
protected struct CatchPos { public EndType ending; } protected enum WeaponType { Invalid, Normal, Destroy, Teleport, Explode, Laser };
protected enum EndType { Invalid, Normal, Destroy, Teleport, Explode, Laser };
} }
} }