mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-18 03:36:47 -04:00
Merge branch 'master-MC1.9.4' of github.com:MightyPirates/OpenComputers into master-MC1.10
This commit is contained in:
commit
5cab00af2d
31
src/main/java/li/cil/oc/api/event/SignChangeEvent.java
Normal file
31
src/main/java/li/cil/oc/api/event/SignChangeEvent.java
Normal file
@ -0,0 +1,31 @@
|
||||
package li.cil.oc.api.event;
|
||||
|
||||
import net.minecraft.tileentity.TileEntitySign;
|
||||
import net.minecraftforge.fml.common.eventhandler.Cancelable;
|
||||
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||
|
||||
/**
|
||||
* A bit more specific sign change event that holds information about new text of the sign. Used in the sign upgrade.
|
||||
*/
|
||||
public abstract class SignChangeEvent extends Event {
|
||||
public final TileEntitySign sign;
|
||||
public final String[] lines;
|
||||
|
||||
private SignChangeEvent(TileEntitySign sign, String[] lines) {
|
||||
this.sign = sign;
|
||||
this.lines = lines;
|
||||
}
|
||||
|
||||
@Cancelable
|
||||
public static class Pre extends SignChangeEvent {
|
||||
public Pre(TileEntitySign sign, String[] lines) {
|
||||
super(sign, lines);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Post extends SignChangeEvent {
|
||||
public Post(TileEntitySign sign, String[] lines) {
|
||||
super(sign, lines);
|
||||
}
|
||||
}
|
||||
}
|
@ -1511,9 +1511,11 @@ opencomputers {
|
||||
# Enable debug card functionality. This may also be of use for custom
|
||||
# maps, so it is enabled by default. If you run a server where people
|
||||
# may cheat in items but should not have op/admin-like rights, you may
|
||||
# want to set this to false. This will *not* remove the card, it will
|
||||
# just make all functions it provides error out.
|
||||
enableDebugCard: true
|
||||
# want to set this to false or `deny`. Set this to `whitelist` if you
|
||||
# want to enable whitelisting of debug card users (managed by command
|
||||
# /oc_debugWhitelist). This will *not* remove the card, it will just
|
||||
# make all functions it provides error out.
|
||||
debugCardAccess: allow
|
||||
|
||||
# Whether to always register the LuaJ architecture - even if the native
|
||||
# library is available. In that case it is possible to switch between
|
||||
|
@ -66,9 +66,15 @@ function bit32.replace(n, v, field, width)
|
||||
end
|
||||
|
||||
function bit32.lrotate(x, disp)
|
||||
if disp == 0 then return x
|
||||
elseif disp < 0 then return bit32.rrotate(x, -disp)
|
||||
else return trim((x << disp) | (x >> (32 - disp))) end
|
||||
if disp == 0 then
|
||||
return x
|
||||
elseif disp < 0 then
|
||||
return bit32.rrotate(x, -disp)
|
||||
else
|
||||
disp = disp & 31
|
||||
x = trim(x)
|
||||
return trim((x << disp) | (x >> (32 - disp)))
|
||||
end
|
||||
end
|
||||
|
||||
function bit32.lshift(x, disp)
|
||||
@ -76,9 +82,15 @@ function bit32.lshift(x, disp)
|
||||
end
|
||||
|
||||
function bit32.rrotate(x, disp)
|
||||
if disp == 0 then return x
|
||||
elseif disp < 0 then return bit32.lrotate(x, -disp)
|
||||
else return trim((x >> disp) | (x << (32 - disp))) end
|
||||
if disp == 0 then
|
||||
return x
|
||||
elseif disp < 0 then
|
||||
return bit32.lrotate(x, -disp)
|
||||
else
|
||||
disp = disp & 31
|
||||
x = trim(x)
|
||||
return trim((x >> disp) | (x << (32 - disp)))
|
||||
end
|
||||
end
|
||||
|
||||
function bit32.rshift(x, disp)
|
||||
|
@ -3,19 +3,26 @@ package li.cil.oc
|
||||
import java.io._
|
||||
import java.net.Inet4Address
|
||||
import java.net.InetAddress
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.security.SecureRandom
|
||||
import java.util.UUID
|
||||
|
||||
import com.google.common.net.InetAddresses
|
||||
import com.mojang.authlib.GameProfile
|
||||
import com.typesafe.config._
|
||||
import li.cil.oc.Settings.DebugCardAccess
|
||||
import li.cil.oc.common.Tier
|
||||
import li.cil.oc.integration.Mods
|
||||
import li.cil.oc.server.component.DebugCard
|
||||
import li.cil.oc.server.component.DebugCard.AccessContext
|
||||
import org.apache.commons.codec.binary.Hex
|
||||
import net.minecraftforge.fml.common.Loader
|
||||
import net.minecraftforge.fml.common.versioning.DefaultArtifactVersion
|
||||
import net.minecraftforge.fml.common.versioning.VersionRange
|
||||
import org.apache.commons.lang3.StringEscapeUtils
|
||||
|
||||
import scala.collection.convert.WrapAsScala._
|
||||
import scala.collection.mutable
|
||||
import scala.io.Codec
|
||||
import scala.io.Source
|
||||
import scala.util.matching.Regex
|
||||
@ -415,7 +422,21 @@ class Settings(val config: Config) {
|
||||
val nativeInTmpDir = config.getBoolean("debug.nativeInTmpDir")
|
||||
val periodicallyForceLightUpdate = config.getBoolean("debug.periodicallyForceLightUpdate")
|
||||
val insertIdsInConverters = config.getBoolean("debug.insertIdsInConverters")
|
||||
val enableDebugCard = config.getBoolean("debug.enableDebugCard")
|
||||
|
||||
val debugCardAccess = config.getValue("debug.debugCardAccess").unwrapped() match {
|
||||
case "true" | "allow" | java.lang.Boolean.TRUE => DebugCardAccess.Allowed
|
||||
case "false" | "deny" | java.lang.Boolean.FALSE => DebugCardAccess.Forbidden
|
||||
case "whitelist" =>
|
||||
val wlFile = new File(Loader.instance.getConfigDir + File.separator + "opencomputers" + File.separator +
|
||||
"debug_card_whitelist.txt")
|
||||
|
||||
DebugCardAccess.Whitelist(wlFile)
|
||||
|
||||
case _ => // Fallback to most secure configuration
|
||||
OpenComputers.log.warn("Unknown debug card access type, falling back to `deny`. Allowed values: `allow`, `deny`, `whitelist`.")
|
||||
DebugCardAccess.Forbidden
|
||||
}
|
||||
|
||||
val registerLuaJArchitecture = config.getBoolean("debug.registerLuaJArchitecture")
|
||||
val disableLocaleChanging = config.getBoolean("debug.disableLocaleChanging")
|
||||
}
|
||||
@ -549,4 +570,95 @@ object Settings {
|
||||
def apply(inetAddress: InetAddress, host: String) = validator(inetAddress, host)
|
||||
}
|
||||
|
||||
sealed trait DebugCardAccess {
|
||||
def checkAccess(ctx: Option[DebugCard.AccessContext]): Option[String]
|
||||
}
|
||||
|
||||
object DebugCardAccess {
|
||||
case object Forbidden extends DebugCardAccess {
|
||||
override def checkAccess(ctx: Option[AccessContext]): Option[String] =
|
||||
Some("debug card is disabled")
|
||||
}
|
||||
|
||||
case object Allowed extends DebugCardAccess {
|
||||
override def checkAccess(ctx: Option[AccessContext]): Option[String] = None
|
||||
}
|
||||
|
||||
case class Whitelist(noncesFile: File) extends DebugCardAccess {
|
||||
private val values = mutable.Map.empty[String, String]
|
||||
private val rng = SecureRandom.getInstance("SHA1PRNG")
|
||||
|
||||
load()
|
||||
|
||||
def save(): Unit = {
|
||||
val noncesDir = noncesFile.getParentFile
|
||||
if (!noncesDir.exists() && !noncesDir.mkdirs())
|
||||
throw new IOException(s"Cannot create nonces directory: ${noncesDir.getCanonicalPath}")
|
||||
|
||||
val writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(noncesFile), StandardCharsets.UTF_8), false)
|
||||
try {
|
||||
for ((p, n) <- values)
|
||||
writer.println(s"$p $n")
|
||||
} finally writer.close()
|
||||
}
|
||||
|
||||
def load(): Unit = {
|
||||
values.clear()
|
||||
|
||||
if (!noncesFile.exists())
|
||||
return
|
||||
|
||||
val reader = new BufferedReader(new InputStreamReader(new FileInputStream(noncesFile), StandardCharsets.UTF_8))
|
||||
Iterator.continually(reader.readLine())
|
||||
.takeWhile(_ != null)
|
||||
.map(_.split(" ", 2))
|
||||
.flatMap {
|
||||
case Array(p, n) => Seq(p -> n)
|
||||
case _ => Nil
|
||||
}.foreach(values += _)
|
||||
}
|
||||
|
||||
private def generateNonce(): String = {
|
||||
val buf = new Array[Byte](16)
|
||||
rng.nextBytes(buf)
|
||||
new String(Hex.encodeHex(buf, true))
|
||||
}
|
||||
|
||||
def nonce(player: String) = values.get(player.toLowerCase)
|
||||
|
||||
def isWhitelisted(player: String) = values.contains(player.toLowerCase)
|
||||
|
||||
def whitelist: collection.Set[String] = values.keySet
|
||||
|
||||
def add(player: String): Unit = {
|
||||
if (!values.contains(player.toLowerCase)) {
|
||||
values.put(player.toLowerCase, generateNonce())
|
||||
save()
|
||||
}
|
||||
}
|
||||
|
||||
def remove(player: String): Unit = {
|
||||
if (values.remove(player.toLowerCase).isDefined)
|
||||
save()
|
||||
}
|
||||
|
||||
def invalidate(player: String): Unit = {
|
||||
if (values.contains(player.toLowerCase)) {
|
||||
values.put(player.toLowerCase, generateNonce())
|
||||
save()
|
||||
}
|
||||
}
|
||||
|
||||
def checkAccess(ctxOpt: Option[DebugCard.AccessContext]): Option[String] = ctxOpt match {
|
||||
case Some(ctx) => values.get(ctx.player) match {
|
||||
case Some(x) =>
|
||||
if (x == ctx.nonce) None
|
||||
else Some("debug card is invalidated, please re-bind it to yourself")
|
||||
case None => Some("you are not whitelisted to use debug card")
|
||||
}
|
||||
|
||||
case None => Some("debug card is whitelisted, Shift+Click with it to bind card to yourself")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -474,7 +474,9 @@ class Drone(val world: World) extends Entity(world) with MachineHost with intern
|
||||
override def processInitialInteract(player: EntityPlayer, stack: ItemStack, hand: EnumHand): Boolean = {
|
||||
if (player.isSneaking) {
|
||||
if (Wrench.isWrench(player.getHeldItemMainhand)) {
|
||||
kill()
|
||||
if(!world.isRemote) {
|
||||
kill()
|
||||
}
|
||||
}
|
||||
else if (!world.isRemote && !machine.isRunning) {
|
||||
preparePowerUp()
|
||||
|
@ -2,26 +2,44 @@ package li.cil.oc.common.item
|
||||
|
||||
import java.util
|
||||
|
||||
import li.cil.oc.Settings
|
||||
import li.cil.oc.Settings.DebugCardAccess
|
||||
import li.cil.oc.common.item.data.DebugCardData
|
||||
import li.cil.oc.server.component.{DebugCard => CDebugCard}
|
||||
import net.minecraft.entity.player.EntityPlayer
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.util.ActionResult
|
||||
import net.minecraft.util.EnumActionResult
|
||||
import net.minecraft.util.EnumHand
|
||||
import net.minecraft.util.text.TextComponentString
|
||||
import net.minecraft.world.World
|
||||
|
||||
class DebugCard(val parent: Delegator) extends traits.Delegate {
|
||||
override protected def tooltipExtended(stack: ItemStack, tooltip: util.List[String]): Unit = {
|
||||
super.tooltipExtended(stack, tooltip)
|
||||
val data = new DebugCardData(stack)
|
||||
data.player.foreach(name => tooltip.add(s"§8$name§r"))
|
||||
data.access.foreach(access => tooltip.add(s"§8${access.player}§r"))
|
||||
}
|
||||
|
||||
override def onItemRightClick(stack: ItemStack, world: World, player: EntityPlayer): ActionResult[ItemStack] = {
|
||||
if (player.isSneaking) {
|
||||
val data = new DebugCardData(stack)
|
||||
if (data.player.contains(player.getName)) data.player = None
|
||||
else data.player = Option(player.getName)
|
||||
val name = player.getName
|
||||
|
||||
if (data.access.exists(_.player == name)) data.access = None
|
||||
else data.access =
|
||||
Some(CDebugCard.AccessContext(name, Settings.get.debugCardAccess match {
|
||||
case wl: DebugCardAccess.Whitelist => wl.nonce(name) match {
|
||||
case Some(n) => n
|
||||
case None =>
|
||||
player.addChatComponentMessage(new TextComponentString("§cYou are not whitelisted to use debug card"))
|
||||
player.swingArm(EnumHand.MAIN_HAND)
|
||||
return new ActionResult[ItemStack](EnumActionResult.FAIL, stack)
|
||||
}
|
||||
|
||||
case _ => ""
|
||||
}))
|
||||
|
||||
data.save(stack)
|
||||
player.swingArm(EnumHand.MAIN_HAND)
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package li.cil.oc.common.item.data
|
||||
|
||||
import li.cil.oc.server.component.DebugCard.AccessContext
|
||||
import li.cil.oc.Constants
|
||||
import li.cil.oc.Settings
|
||||
import net.minecraft.item.ItemStack
|
||||
@ -11,22 +12,18 @@ class DebugCardData extends ItemData(Constants.ItemName.DebugCard) {
|
||||
load(stack)
|
||||
}
|
||||
|
||||
var player: Option[String] = None
|
||||
var access: Option[AccessContext] = None
|
||||
|
||||
private final val DataTag = Settings.namespace + "data"
|
||||
private final val PlayerTag = Settings.namespace + "player"
|
||||
|
||||
override def load(nbt: NBTTagCompound) {
|
||||
val tag = dataTag(nbt)
|
||||
if (tag.hasKey(PlayerTag)) {
|
||||
player = Option(tag.getString(PlayerTag))
|
||||
}
|
||||
override def load(nbt: NBTTagCompound): Unit = {
|
||||
access = AccessContext.load(dataTag(nbt))
|
||||
}
|
||||
|
||||
override def save(nbt: NBTTagCompound) {
|
||||
override def save(nbt: NBTTagCompound): Unit = {
|
||||
val tag = dataTag(nbt)
|
||||
tag.removeTag(PlayerTag)
|
||||
player.foreach(tag.setString(PlayerTag, _))
|
||||
AccessContext.remove(tag)
|
||||
access.foreach(_.save(tag))
|
||||
}
|
||||
|
||||
private def dataTag(nbt: NBTTagCompound) = {
|
||||
|
@ -9,5 +9,6 @@ object CommandHandler {
|
||||
e.registerServerCommand(NonDisassemblyAgreementCommand)
|
||||
e.registerServerCommand(WirelessRenderingCommand)
|
||||
e.registerServerCommand(SpawnComputerCommand)
|
||||
e.registerServerCommand(DebugWhitelistCommand)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,54 @@
|
||||
package li.cil.oc.server.command
|
||||
|
||||
import li.cil.oc.Settings
|
||||
import li.cil.oc.Settings.DebugCardAccess
|
||||
import li.cil.oc.common.command.SimpleCommand
|
||||
import net.minecraft.command.{ICommandSender, WrongUsageException}
|
||||
import net.minecraft.server.MinecraftServer
|
||||
import net.minecraft.util.text.TextComponentString
|
||||
|
||||
object DebugWhitelistCommand extends SimpleCommand("oc_debugWhitelist") {
|
||||
// Required OP levels:
|
||||
// to revoke your cards - 0
|
||||
// to do other whitelist manipulation - 2
|
||||
|
||||
override def getRequiredPermissionLevel = 0
|
||||
private def isOp(sender: ICommandSender) = getOpLevel(sender) >= 2
|
||||
|
||||
override def getCommandUsage(sender: ICommandSender): String =
|
||||
if (isOp(sender)) name + " [revoke|add|remove] <player> OR " + name + " [revoke|list]"
|
||||
else name + " revoke"
|
||||
|
||||
override def execute(server: MinecraftServer, sender: ICommandSender, args: Array[String]): Unit = {
|
||||
val wl = Settings.get.debugCardAccess match {
|
||||
case w: DebugCardAccess.Whitelist => w
|
||||
case _ => throw new WrongUsageException("§cDebug card whitelisting is not enabled.")
|
||||
}
|
||||
|
||||
def revokeUser(player: String): Unit = {
|
||||
if (wl.isWhitelisted(player)) {
|
||||
wl.invalidate(player)
|
||||
sender.addChatMessage(new TextComponentString("§aAll your debug cards were invalidated."))
|
||||
} else sender.addChatMessage(new TextComponentString("§cYou are not whitelisted to use debug card."))
|
||||
}
|
||||
|
||||
args match {
|
||||
case Array("revoke") => revokeUser(sender.getName)
|
||||
case Array("revoke", player) if isOp(sender) => revokeUser(player)
|
||||
case Array("list") if isOp(sender) =>
|
||||
val players = wl.whitelist
|
||||
if (players.nonEmpty)
|
||||
sender.addChatMessage(new TextComponentString("§aCurrently whitelisted players: §e" + players.mkString(", ")))
|
||||
else
|
||||
sender.addChatMessage(new TextComponentString("§cThere is no currently whitelisted players."))
|
||||
case Array("add", player) if isOp(sender) =>
|
||||
wl.add(player)
|
||||
sender.addChatMessage(new TextComponentString("§aPlayer was added to whitelist."))
|
||||
case Array("remove", player) if isOp(sender) =>
|
||||
wl.remove(player)
|
||||
sender.addChatMessage(new TextComponentString("§aPlayer was removed from whitelist"))
|
||||
case _ =>
|
||||
sender.addChatMessage(new TextComponentString("§e" + getCommandUsage(sender)))
|
||||
}
|
||||
}
|
||||
}
|
31
src/main/scala/li/cil/oc/server/command/package.scala
Normal file
31
src/main/scala/li/cil/oc/server/command/package.scala
Normal file
@ -0,0 +1,31 @@
|
||||
package li.cil.oc.server
|
||||
|
||||
import net.minecraft.command.ICommandSender
|
||||
import net.minecraft.entity.player.EntityPlayerMP
|
||||
import net.minecraft.server.MinecraftServer
|
||||
import net.minecraft.util.text.ITextComponent
|
||||
import net.minecraft.util.text.TextComponentString
|
||||
import net.minecraftforge.fml.server.FMLServerHandler
|
||||
|
||||
import scala.language.implicitConversions
|
||||
|
||||
package object command {
|
||||
implicit def string2text(s: String): ITextComponent = new TextComponentString(s)
|
||||
|
||||
def getOpLevel(sender: ICommandSender): Int = {
|
||||
// Shitty minecraft server logic & shitty minecraft server code.
|
||||
val srv = FMLServerHandler.instance().getServer
|
||||
if (srv.isSinglePlayer && srv.worldServers.head.getWorldInfo.areCommandsAllowed &&
|
||||
srv.getServerOwner.equalsIgnoreCase(sender.getName) /* || srv.commandsAllowedForAll */ )
|
||||
return 4
|
||||
|
||||
sender match {
|
||||
case _: MinecraftServer => 4
|
||||
case p: EntityPlayerMP =>
|
||||
|
||||
val e = srv.getPlayerList.getOppedPlayers.getEntry(p.getGameProfile)
|
||||
if (e == null) 0 else e.getPermissionLevel
|
||||
case _ => 0
|
||||
}
|
||||
}
|
||||
}
|
@ -14,7 +14,7 @@ import li.cil.oc.api.network.SidedEnvironment
|
||||
import li.cil.oc.api.network.Visibility
|
||||
import li.cil.oc.api.prefab
|
||||
import li.cil.oc.api.prefab.AbstractValue
|
||||
import li.cil.oc.server.component.DebugCard.CommandSender
|
||||
import li.cil.oc.server.component.DebugCard.{AccessContext, CommandSender}
|
||||
import li.cil.oc.util.BlockPosition
|
||||
import li.cil.oc.util.ExtendedArguments._
|
||||
import li.cil.oc.util.ExtendedNBT._
|
||||
@ -63,7 +63,9 @@ class DebugCard(host: EnvironmentHost) extends prefab.ManagedEnvironment {
|
||||
private var remoteNodePosition: Option[(Int, Int, Int)] = None
|
||||
|
||||
// Player this card is bound to (if any) to use for permissions.
|
||||
var player: Option[String] = None
|
||||
implicit var access: Option[AccessContext] = None
|
||||
|
||||
def player = access.map(_.player)
|
||||
|
||||
private lazy val CommandSender = {
|
||||
def defaultFakePlayer = FakePlayerFactory.get(host.world.asInstanceOf[WorldServer], Settings.get.fakePlayerProfile)
|
||||
@ -75,67 +77,67 @@ class DebugCard(host: EnvironmentHost) extends prefab.ManagedEnvironment {
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
import li.cil.oc.server.component.DebugCard.checkEnabled
|
||||
import li.cil.oc.server.component.DebugCard.checkAccess
|
||||
|
||||
@Callback(doc = """function(value:number):number -- Changes the component network's energy buffer by the specified delta.""")
|
||||
def changeBuffer(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
result(node.changeBuffer(args.checkDouble(0)))
|
||||
}
|
||||
|
||||
@Callback(doc = """function():number -- Get the container's X position in the world.""")
|
||||
def getX(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
result(host.xPosition)
|
||||
}
|
||||
|
||||
@Callback(doc = """function():number -- Get the container's Y position in the world.""")
|
||||
def getY(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
result(host.yPosition)
|
||||
}
|
||||
|
||||
@Callback(doc = """function():number -- Get the container's Z position in the world.""")
|
||||
def getZ(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
result(host.zPosition)
|
||||
}
|
||||
|
||||
@Callback(doc = """function([id:number]):userdata -- Get the world object for the specified dimension ID, or the container's.""")
|
||||
def getWorld(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
if (args.count() > 0) result(new DebugCard.WorldValue(DimensionManager.getWorld(args.checkInteger(0))))
|
||||
else result(new DebugCard.WorldValue(host.world))
|
||||
}
|
||||
|
||||
@Callback(doc = """function():table -- Get a list of all world IDs, loaded and unloaded.""")
|
||||
def getWorlds(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
result(DimensionManager.getStaticDimensionIDs)
|
||||
}
|
||||
|
||||
@Callback(doc = """function(name:string):userdata -- Get the entity of a player.""")
|
||||
def getPlayer(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
result(new DebugCard.PlayerValue(args.checkString(0)))
|
||||
}
|
||||
|
||||
@Callback(doc = """function():table -- Get a list of currently logged-in players.""")
|
||||
def getPlayers(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
result(FMLCommonHandler.instance.getMinecraftServerInstance.getAllUsernames)
|
||||
}
|
||||
|
||||
@Callback(doc = """function(name:string):boolean -- Get whether a mod or API is loaded.""")
|
||||
def isModLoaded(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
val name = args.checkString(0)
|
||||
result(Loader.isModLoaded(name) || ModAPIManager.INSTANCE.hasAPI(name))
|
||||
}
|
||||
|
||||
@Callback(doc = """function(command:string):number -- Runs an arbitrary command using a fake player.""")
|
||||
def runCommand(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
val commands =
|
||||
if (args.isTable(0)) collectionAsScalaIterable(args.checkTable(0).values())
|
||||
else Iterable(args.checkString(0))
|
||||
@ -152,7 +154,7 @@ class DebugCard(host: EnvironmentHost) extends prefab.ManagedEnvironment {
|
||||
|
||||
@Callback(doc = """function(x:number, y:number, z:number):boolean -- Connect the debug card to the block at the specified coordinates.""")
|
||||
def connectToBlock(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
val x = args.checkInteger(0)
|
||||
val y = args.checkInteger(1)
|
||||
val z = args.checkInteger(2)
|
||||
@ -180,7 +182,7 @@ class DebugCard(host: EnvironmentHost) extends prefab.ManagedEnvironment {
|
||||
|
||||
@Callback(doc = """function():userdata -- Test method for user-data and general value conversion.""")
|
||||
def test(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
|
||||
val v1 = mutable.Map("a" -> true, "b" -> "test")
|
||||
val v2 = Map(10 -> "zxc", false -> v1)
|
||||
@ -218,42 +220,63 @@ class DebugCard(host: EnvironmentHost) extends prefab.ManagedEnvironment {
|
||||
|
||||
override def load(nbt: NBTTagCompound): Unit = {
|
||||
super.load(nbt)
|
||||
access = AccessContext.load(nbt)
|
||||
if (nbt.hasKey(Settings.namespace + "remoteX")) {
|
||||
val x = nbt.getInteger(Settings.namespace + "remoteX")
|
||||
val y = nbt.getInteger(Settings.namespace + "remoteY")
|
||||
val z = nbt.getInteger(Settings.namespace + "remoteZ")
|
||||
remoteNodePosition = Some((x, y, z))
|
||||
}
|
||||
if (nbt.hasKey(Settings.namespace + "player")) {
|
||||
player = Option(nbt.getString(Settings.namespace + "player"))
|
||||
}
|
||||
}
|
||||
|
||||
override def save(nbt: NBTTagCompound): Unit = {
|
||||
super.save(nbt)
|
||||
access.foreach(_.save(nbt))
|
||||
remoteNodePosition.foreach {
|
||||
case (x, y, z) =>
|
||||
nbt.setInteger(Settings.namespace + "remoteX", x)
|
||||
nbt.setInteger(Settings.namespace + "remoteY", y)
|
||||
nbt.setInteger(Settings.namespace + "remoteZ", z)
|
||||
}
|
||||
player.foreach(nbt.setString(Settings.namespace + "player", _))
|
||||
}
|
||||
}
|
||||
|
||||
object DebugCard {
|
||||
def checkAccess()(implicit ctx: Option[AccessContext]) =
|
||||
for (msg <- Settings.get.debugCardAccess.checkAccess(ctx))
|
||||
throw new Exception(msg)
|
||||
|
||||
import li.cil.oc.util.ResultWrapper.result
|
||||
object AccessContext {
|
||||
def remove(nbt: NBTTagCompound): Unit = {
|
||||
nbt.removeTag(Settings.namespace + "player")
|
||||
nbt.removeTag(Settings.namespace + "accessNonce")
|
||||
}
|
||||
|
||||
def checkEnabled() = if (!Settings.get.enableDebugCard) throw new Exception("debug card functionality is disabled")
|
||||
def load(nbt: NBTTagCompound): Option[AccessContext] = {
|
||||
if (nbt.hasKey(Settings.namespace + "player"))
|
||||
Some(AccessContext(
|
||||
nbt.getString(Settings.namespace + "player"),
|
||||
nbt.getString(Settings.namespace + "accessNonce")
|
||||
))
|
||||
else
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
class PlayerValue(var name: String) extends prefab.AbstractValue {
|
||||
def this() = this("") // For loading.
|
||||
case class AccessContext(player: String, nonce: String) {
|
||||
def save(nbt: NBTTagCompound): Unit = {
|
||||
nbt.setString(Settings.namespace + "player", player)
|
||||
nbt.setString(Settings.namespace + "accessNonce", nonce)
|
||||
}
|
||||
}
|
||||
|
||||
class PlayerValue(var name: String)(implicit var ctx: Option[AccessContext]) extends prefab.AbstractValue {
|
||||
def this() = this("")(None) // For loading.
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
def withPlayer(f: (EntityPlayerMP) => Array[AnyRef]) = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
FMLCommonHandler.instance.getMinecraftServerInstance.getPlayerList.getPlayerByUsername(name) match {
|
||||
case player: EntityPlayerMP => f(player)
|
||||
case _ => result(Unit, "player is offline")
|
||||
@ -309,93 +332,95 @@ object DebugCard {
|
||||
|
||||
override def load(nbt: NBTTagCompound) {
|
||||
super.load(nbt)
|
||||
ctx = AccessContext.load(nbt)
|
||||
name = nbt.getString(NameTag)
|
||||
}
|
||||
|
||||
override def save(nbt: NBTTagCompound) {
|
||||
super.save(nbt)
|
||||
ctx.foreach(_.save(nbt))
|
||||
nbt.setString(NameTag, name)
|
||||
}
|
||||
}
|
||||
|
||||
class WorldValue(var world: World) extends prefab.AbstractValue {
|
||||
def this() = this(null) // For loading.
|
||||
class WorldValue(var world: World)(implicit var ctx: Option[AccessContext]) extends prefab.AbstractValue {
|
||||
def this() = this(null)(None) // For loading.
|
||||
|
||||
// ----------------------------------------------------------------------- //
|
||||
|
||||
@Callback(doc = """function():number -- Gets the numeric id of the current dimension.""")
|
||||
def getDimensionId(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
result(world.provider.getDimension)
|
||||
}
|
||||
|
||||
@Callback(doc = """function():string -- Gets the name of the current dimension.""")
|
||||
def getDimensionName(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
result(world.provider.getDimensionType.getName)
|
||||
}
|
||||
|
||||
@Callback(doc = """function():number -- Gets the seed of the world.""")
|
||||
def getSeed(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
result(world.getSeed)
|
||||
}
|
||||
|
||||
@Callback(doc = """function():boolean -- Returns whether it is currently raining.""")
|
||||
def isRaining(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
result(world.isRaining)
|
||||
}
|
||||
|
||||
@Callback(doc = """function(value:boolean) -- Sets whether it is currently raining.""")
|
||||
def setRaining(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
world.getWorldInfo.setRaining(args.checkBoolean(0))
|
||||
null
|
||||
}
|
||||
|
||||
@Callback(doc = """function():boolean -- Returns whether it is currently thundering.""")
|
||||
def isThundering(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
result(world.isThundering)
|
||||
}
|
||||
|
||||
@Callback(doc = """function(value:boolean) -- Sets whether it is currently thundering.""")
|
||||
def setThundering(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
world.getWorldInfo.setThundering(args.checkBoolean(0))
|
||||
null
|
||||
}
|
||||
|
||||
@Callback(doc = """function():number -- Get the current world time.""")
|
||||
def getTime(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
result(world.getWorldTime)
|
||||
}
|
||||
|
||||
@Callback(doc = """function(value:number) -- Set the current world time.""")
|
||||
def setTime(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
world.setWorldTime(args.checkDouble(0).toLong)
|
||||
null
|
||||
}
|
||||
|
||||
@Callback(doc = """function():number, number, number -- Get the current spawn point coordinates.""")
|
||||
def getSpawnPoint(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
result(world.getWorldInfo.getSpawnX, world.getWorldInfo.getSpawnY, world.getWorldInfo.getSpawnZ)
|
||||
}
|
||||
|
||||
@Callback(doc = """function(x:number, y:number, z:number) -- Set the spawn point coordinates.""")
|
||||
def setSpawnPoint(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
world.getWorldInfo.setSpawn(new BlockPos(args.checkInteger(0), args.checkInteger(1), args.checkInteger(2)))
|
||||
null
|
||||
}
|
||||
|
||||
@Callback(doc = """function(x:number, y:number, z:number, sound:string, range:number) -- Play a sound at the specified coordinates.""")
|
||||
def playSoundAt(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
val (x, y, z) = (args.checkInteger(0), args.checkInteger(1), args.checkInteger(2))
|
||||
val sound = args.checkString(3)
|
||||
val range = args.checkInteger(4)
|
||||
@ -407,25 +432,25 @@ object DebugCard {
|
||||
|
||||
@Callback(doc = """function(x:number, y:number, z:number):number -- Get the ID of the block at the specified coordinates.""")
|
||||
def getBlockId(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
result(Block.getIdFromBlock(world.getBlockState(new BlockPos(args.checkInteger(0), args.checkInteger(1), args.checkInteger(2))).getBlock))
|
||||
}
|
||||
|
||||
@Callback(doc = """function(x:number, y:number, z:number):number -- Get the metadata of the block at the specified coordinates.""")
|
||||
def getMetadata(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
result(world.getBlockState(new BlockPos(args.checkInteger(0), args.checkInteger(1), args.checkInteger(2))))
|
||||
}
|
||||
|
||||
@Callback(doc = """function(x:number, y:number, z:number):number -- Check whether the block at the specified coordinates is loaded.""")
|
||||
def isLoaded(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
result(world.isBlockLoaded(new BlockPos(args.checkInteger(0), args.checkInteger(1), args.checkInteger(2))))
|
||||
}
|
||||
|
||||
@Callback(doc = """function(x:number, y:number, z:number):number -- Check whether the block at the specified coordinates has a tile entity.""")
|
||||
def hasTileEntity(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
val blockPos = new BlockPos(args.checkInteger(0), args.checkInteger(1), args.checkInteger(2))
|
||||
val state = world.getBlockState(blockPos)
|
||||
result(state.getBlock.hasTileEntity(state))
|
||||
@ -433,7 +458,7 @@ object DebugCard {
|
||||
|
||||
@Callback(doc = """function(x:number, y:number, z:number):table -- Get the NBT of the block at the specified coordinates.""")
|
||||
def getTileNBT(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
val blockPos = new BlockPos(args.checkInteger(0), args.checkInteger(1), args.checkInteger(2))
|
||||
world.getTileEntity(blockPos) match {
|
||||
case tileEntity: TileEntity => result(toNbt((nbt) => tileEntity.writeToNBT(nbt): Unit).toTypedMap)
|
||||
@ -443,7 +468,7 @@ object DebugCard {
|
||||
|
||||
@Callback(doc = """function(x:number, y:number, z:number, nbt:table):boolean -- Set the NBT of the block at the specified coordinates.""")
|
||||
def setTileNBT(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
val blockPos = new BlockPos(args.checkInteger(0), args.checkInteger(1), args.checkInteger(2))
|
||||
world.getTileEntity(blockPos) match {
|
||||
case tileEntity: TileEntity =>
|
||||
@ -461,25 +486,25 @@ object DebugCard {
|
||||
|
||||
@Callback(doc = """function(x:number, y:number, z:number):number -- Get the light opacity of the block at the specified coordinates.""")
|
||||
def getLightOpacity(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
result(world.getBlockLightOpacity(new BlockPos(args.checkInteger(0), args.checkInteger(1), args.checkInteger(2))))
|
||||
}
|
||||
|
||||
@Callback(doc = """function(x:number, y:number, z:number):number -- Get the light value (emission) of the block at the specified coordinates.""")
|
||||
def getLightValue(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
result(world.getLight(new BlockPos(args.checkInteger(0), args.checkInteger(1), args.checkInteger(2)), false))
|
||||
}
|
||||
|
||||
@Callback(doc = """function(x:number, y:number, z:number):number -- Get whether the block at the specified coordinates is directly under the sky.""")
|
||||
def canSeeSky(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
result(world.canBlockSeeSky(new BlockPos(args.checkInteger(0), args.checkInteger(1), args.checkInteger(2))))
|
||||
}
|
||||
|
||||
@Callback(doc = """function(x:number, y:number, z:number, id:number or string, meta:number):number -- Set the block at the specified coordinates.""")
|
||||
def setBlock(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
val block = if (args.isInteger(3)) Block.getBlockById(args.checkInteger(3)) else Block.getBlockFromName(args.checkString(3))
|
||||
val metadata = args.checkInteger(4)
|
||||
result(world.setBlockState(new BlockPos(args.checkInteger(0), args.checkInteger(1), args.checkInteger(2)), block.getStateFromMeta(metadata)))
|
||||
@ -487,7 +512,7 @@ object DebugCard {
|
||||
|
||||
@Callback(doc = """function(x1:number, y1:number, z1:number, x2:number, y2:number, z2:number, id:number or string, meta:number):number -- Set all blocks in the area defined by the two corner points (x1, y1, z1) and (x2, y2, z2).""")
|
||||
def setBlocks(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
val (xMin, yMin, zMin) = (args.checkInteger(0), args.checkInteger(1), args.checkInteger(2))
|
||||
val (xMax, yMax, zMax) = (args.checkInteger(3), args.checkInteger(4), args.checkInteger(5))
|
||||
val block = if (args.isInteger(6)) Block.getBlockById(args.checkInteger(6)) else Block.getBlockFromName(args.checkString(6))
|
||||
@ -506,7 +531,7 @@ object DebugCard {
|
||||
|
||||
@Callback(doc = """function(id:string, count:number, damage:number, nbt:string, x:number, y:number, z:number, side:number):boolean - Insert an item stack into the inventory at the specified location. NBT tag is expected in JSON format.""")
|
||||
def insertItem(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
val item = Item.REGISTRY.getObject(new ResourceLocation(args.checkString(0)))
|
||||
if (item == null) {
|
||||
throw new IllegalArgumentException("invalid item id")
|
||||
@ -528,7 +553,7 @@ object DebugCard {
|
||||
|
||||
@Callback(doc = """function(x:number, y:number, z:number, slot:number[, count:number]):number - Reduce the size of an item stack in the inventory at the specified location.""")
|
||||
def removeItem(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
val position = BlockPosition(args.checkDouble(0), args.checkDouble(1), args.checkDouble(2), world)
|
||||
InventoryUtils.inventoryAt(position) match {
|
||||
case Some(inventory) =>
|
||||
@ -543,7 +568,7 @@ object DebugCard {
|
||||
|
||||
@Callback(doc = """function(id:string, amount:number, x:number, y:number, z:number, side:number):boolean - Insert some fluid into the tank at the specified location.""")
|
||||
def insertFluid(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
val fluid = FluidRegistry.getFluid(args.checkString(0))
|
||||
if (fluid == null) {
|
||||
throw new IllegalArgumentException("invalid fluid id")
|
||||
@ -559,7 +584,7 @@ object DebugCard {
|
||||
|
||||
@Callback(doc = """function(amount:number, x:number, y:number, z:number, side:number):boolean - Remove some fluid from a tank at the specified location.""")
|
||||
def removeFluid(context: Context, args: Arguments): Array[AnyRef] = {
|
||||
checkEnabled()
|
||||
checkAccess()
|
||||
val amount = args.checkInteger(0)
|
||||
val position = BlockPosition(args.checkDouble(1), args.checkDouble(2), args.checkDouble(3), world)
|
||||
val side = args.checkSideAny(4)
|
||||
@ -575,11 +600,13 @@ object DebugCard {
|
||||
|
||||
override def load(nbt: NBTTagCompound) {
|
||||
super.load(nbt)
|
||||
ctx = AccessContext.load(nbt)
|
||||
world = DimensionManager.getWorld(nbt.getInteger(DimensionTag))
|
||||
}
|
||||
|
||||
override def save(nbt: NBTTagCompound) {
|
||||
super.save(nbt)
|
||||
ctx.foreach(_.save(nbt))
|
||||
nbt.setInteger(DimensionTag, world.provider.getDimension)
|
||||
}
|
||||
}
|
||||
|
@ -3,11 +3,12 @@ package li.cil.oc.server.component
|
||||
import java.util
|
||||
|
||||
import li.cil.oc.Constants
|
||||
import li.cil.oc.api.driver.DeviceInfo.DeviceAttribute
|
||||
import li.cil.oc.api.driver.DeviceInfo.DeviceClass
|
||||
import li.cil.oc.Settings
|
||||
import li.cil.oc.api
|
||||
import li.cil.oc.api.driver.DeviceInfo
|
||||
import li.cil.oc.api.driver.DeviceInfo.DeviceAttribute
|
||||
import li.cil.oc.api.driver.DeviceInfo.DeviceClass
|
||||
import li.cil.oc.api.event.SignChangeEvent
|
||||
import li.cil.oc.api.internal
|
||||
import li.cil.oc.api.network.EnvironmentHost
|
||||
import li.cil.oc.api.network.Message
|
||||
@ -54,13 +55,19 @@ abstract class UpgradeSign extends prefab.ManagedEnvironment with DeviceInfo {
|
||||
case robot: internal.Robot => robot.player
|
||||
case _ => FakePlayerFactory.get(host.world.asInstanceOf[WorldServer], Settings.get.fakePlayerProfile)
|
||||
}
|
||||
if (!canChangeSign(player, sign)) {
|
||||
|
||||
val lines = text.lines.padTo(4, "").map(line => if (line.length > 15) line.substring(0, 15) else line).toArray
|
||||
|
||||
if (!canChangeSign(player, sign, lines)) {
|
||||
return result(Unit, "not allowed")
|
||||
}
|
||||
|
||||
text.lines.padTo(4, "").map(line => if (line.length > 15) line.substring(0, 15) else line).map(new TextComponentString(_)).copyToArray(sign.signText)
|
||||
lines.map(line => new TextComponentString(line)).copyToArray(sign.signText)
|
||||
host.world.notifyBlockUpdate(sign.getPos)
|
||||
result(sign.signText.map(_.getUnformattedText).mkString("\n"))
|
||||
|
||||
MinecraftForge.EVENT_BUS.post(new SignChangeEvent.Post(sign, lines))
|
||||
|
||||
result(sign.signText.mkString("\n"))
|
||||
case _ => result(Unit, "no sign")
|
||||
}
|
||||
}
|
||||
@ -76,13 +83,19 @@ abstract class UpgradeSign extends prefab.ManagedEnvironment with DeviceInfo {
|
||||
}
|
||||
}
|
||||
|
||||
private def canChangeSign(player: EntityPlayer, tileEntity: TileEntitySign): Boolean = {
|
||||
private def canChangeSign(player: EntityPlayer, tileEntity: TileEntitySign, lines: Array[String]): Boolean = {
|
||||
if (!host.world.isBlockModifiable(player, tileEntity.getPos)) {
|
||||
return false
|
||||
}
|
||||
val event = new BlockEvent.BreakEvent(host.world, tileEntity.getPos, tileEntity.getWorld.getBlockState(tileEntity.getPos), player)
|
||||
MinecraftForge.EVENT_BUS.post(event)
|
||||
!(event.isCanceled || event.getResult == Event.Result.DENY)
|
||||
if (event.isCanceled || event.getResult == Event.Result.DENY) {
|
||||
return false
|
||||
}
|
||||
|
||||
val signEvent = new SignChangeEvent.Pre(tileEntity, lines)
|
||||
MinecraftForge.EVENT_BUS.post(signEvent)
|
||||
!(signEvent.isCanceled || signEvent.getResult == Event.Result.DENY)
|
||||
}
|
||||
|
||||
override def onMessage(message: Message): Unit = {
|
||||
|
Loading…
x
Reference in New Issue
Block a user