mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-10-29 12:57:46 +00:00
Merge branch 'mc-1.20.x' into mc-1.21.x
This commit is contained in:
@@ -4,7 +4,6 @@
|
||||
|
||||
package dan200.computercraft.core;
|
||||
|
||||
import dan200.computercraft.api.lua.ILuaAPIFactory;
|
||||
import dan200.computercraft.core.asm.GenericMethod;
|
||||
import dan200.computercraft.core.asm.LuaMethodSupplier;
|
||||
import dan200.computercraft.core.asm.PeripheralMethodSupplier;
|
||||
@@ -35,21 +34,19 @@ public final class ComputerContext {
|
||||
private final ComputerScheduler computerScheduler;
|
||||
private final MainThreadScheduler mainThreadScheduler;
|
||||
private final ILuaMachine.Factory luaFactory;
|
||||
private final List<ILuaAPIFactory> apiFactories;
|
||||
private final MethodSupplier<LuaMethod> luaMethods;
|
||||
private final MethodSupplier<PeripheralMethod> peripheralMethods;
|
||||
|
||||
ComputerContext(
|
||||
private ComputerContext(
|
||||
GlobalEnvironment globalEnvironment, ComputerScheduler computerScheduler,
|
||||
MainThreadScheduler mainThreadScheduler, ILuaMachine.Factory luaFactory,
|
||||
List<ILuaAPIFactory> apiFactories, MethodSupplier<LuaMethod> luaMethods,
|
||||
MethodSupplier<LuaMethod> luaMethods,
|
||||
MethodSupplier<PeripheralMethod> peripheralMethods
|
||||
) {
|
||||
this.globalEnvironment = globalEnvironment;
|
||||
this.computerScheduler = computerScheduler;
|
||||
this.mainThreadScheduler = mainThreadScheduler;
|
||||
this.luaFactory = luaFactory;
|
||||
this.apiFactories = apiFactories;
|
||||
this.luaMethods = luaMethods;
|
||||
this.peripheralMethods = peripheralMethods;
|
||||
}
|
||||
@@ -91,15 +88,6 @@ public final class ComputerContext {
|
||||
return luaFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Additional APIs to inject into each computer.
|
||||
*
|
||||
* @return All available API factories.
|
||||
*/
|
||||
public List<ILuaAPIFactory> apiFactories() {
|
||||
return apiFactories;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link MethodSupplier} used to find methods on Lua values.
|
||||
*
|
||||
@@ -166,7 +154,6 @@ public final class ComputerContext {
|
||||
private @Nullable ComputerScheduler computerScheduler = null;
|
||||
private @Nullable MainThreadScheduler mainThreadScheduler;
|
||||
private @Nullable ILuaMachine.Factory luaFactory;
|
||||
private @Nullable List<ILuaAPIFactory> apiFactories;
|
||||
private @Nullable List<GenericMethod> genericMethods;
|
||||
|
||||
Builder(GlobalEnvironment environment) {
|
||||
@@ -227,20 +214,6 @@ public final class ComputerContext {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the additional {@linkplain ILuaAPIFactory APIs} to add to each computer.
|
||||
*
|
||||
* @param apis A list of API factories.
|
||||
* @return {@code this}, for chaining
|
||||
* @see ComputerContext#apiFactories()
|
||||
*/
|
||||
public Builder apiFactories(Collection<ILuaAPIFactory> apis) {
|
||||
Objects.requireNonNull(apis);
|
||||
if (apiFactories != null) throw new IllegalStateException("Main-thread scheduler already specified");
|
||||
apiFactories = List.copyOf(apis);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the set of {@link GenericMethod}s used by the {@linkplain MethodSupplier method suppliers}.
|
||||
*
|
||||
@@ -267,7 +240,6 @@ public final class ComputerContext {
|
||||
computerScheduler == null ? new ComputerThread(1) : computerScheduler,
|
||||
mainThreadScheduler == null ? new NoWorkMainThreadScheduler() : mainThreadScheduler,
|
||||
luaFactory == null ? CobaltLuaMachine::new : luaFactory,
|
||||
apiFactories == null ? List.of() : apiFactories,
|
||||
LuaMethodSupplier.create(genericMethods == null ? List.of() : genericMethods),
|
||||
PeripheralMethodSupplier.create(genericMethods == null ? List.of() : genericMethods)
|
||||
);
|
||||
|
||||
@@ -21,7 +21,7 @@ public abstract class ComputerAccess implements IComputerAccess {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ComputerAccess.class);
|
||||
|
||||
private final IAPIEnvironment environment;
|
||||
private final Set<String> mounts = new HashSet<>();
|
||||
private final Set<String> mounts = new HashSet<>(0);
|
||||
|
||||
protected ComputerAccess(IAPIEnvironment environment) {
|
||||
this.environment = environment;
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.core.computer;
|
||||
|
||||
import dan200.computercraft.api.lua.ILuaAPI;
|
||||
|
||||
/**
|
||||
* Hooks for managing the lifecycle of an API. This allows adding additional logic to an API's {@link ILuaAPI#startup()}
|
||||
* and {@link ILuaAPI#shutdown()} methods.
|
||||
*
|
||||
* @see ILuaAPI
|
||||
* @see Computer#addApi(ILuaAPI, ApiLifecycle)
|
||||
*/
|
||||
public interface ApiLifecycle {
|
||||
/**
|
||||
* Called before the API's {@link ILuaAPI#startup()} method, may be used to set up resources.
|
||||
*/
|
||||
default void startup() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after the API's {@link ILuaAPI#shutdown()} method, may be used to tear down resources.
|
||||
*/
|
||||
default void shutdown() {
|
||||
}
|
||||
}
|
||||
@@ -9,18 +9,14 @@ import dan200.computercraft.api.lua.ILuaAPI;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* A wrapper for {@link ILuaAPI}s which optionally manages the lifecycle of a {@link ComputerSystem}.
|
||||
* A wrapper for {@link ILuaAPI}s which provides an optional shutdown hook to clean up resources.
|
||||
*
|
||||
* @param api The original API.
|
||||
* @param lifecycle The optional lifecycle hooks for this API.
|
||||
*/
|
||||
final class ApiWrapper {
|
||||
private final ILuaAPI api;
|
||||
private final @Nullable ComputerSystem system;
|
||||
|
||||
ApiWrapper(ILuaAPI api, @Nullable ComputerSystem system) {
|
||||
this.api = api;
|
||||
this.system = system;
|
||||
}
|
||||
|
||||
record ApiWrapper(ILuaAPI api, @Nullable ApiLifecycle lifecycle) {
|
||||
public void startup() {
|
||||
if (lifecycle != null) lifecycle.startup();
|
||||
api.startup();
|
||||
}
|
||||
|
||||
@@ -30,7 +26,7 @@ final class ApiWrapper {
|
||||
|
||||
public void shutdown() {
|
||||
api.shutdown();
|
||||
if (system != null) system.unmountAll();
|
||||
if (lifecycle != null) lifecycle.shutdown();
|
||||
}
|
||||
|
||||
public ILuaAPI api() {
|
||||
|
||||
@@ -184,6 +184,10 @@ public class Computer {
|
||||
executor.addApi(api);
|
||||
}
|
||||
|
||||
public void addApi(ILuaAPI api, ApiLifecycle lifecycleHooks) {
|
||||
executor.addApi(api, lifecycleHooks);
|
||||
}
|
||||
|
||||
long getUniqueTaskId() {
|
||||
return lastTaskId.incrementAndGet();
|
||||
}
|
||||
|
||||
@@ -162,13 +162,6 @@ final class ComputerExecutor implements ComputerScheduler.Worker {
|
||||
addApi(new PeripheralAPI(environment, context.peripheralMethods()));
|
||||
addApi(new OSAPI(environment));
|
||||
if (CoreConfig.httpEnabled) addApi(new HTTPAPI(environment));
|
||||
|
||||
// Load in the externally registered APIs.
|
||||
for (var factory : context.apiFactories()) {
|
||||
var system = new ComputerSystem(environment);
|
||||
var api = factory.create(system);
|
||||
if (api != null) apis.add(new ApiWrapper(api, system));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -190,6 +183,10 @@ final class ComputerExecutor implements ComputerScheduler.Worker {
|
||||
apis.add(new ApiWrapper(api, null));
|
||||
}
|
||||
|
||||
void addApi(ILuaAPI api, ApiLifecycle lifecycleHooks) {
|
||||
apis.add(new ApiWrapper(api, lifecycleHooks));
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule this computer to be started if not already on.
|
||||
*/
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2019 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.core.computer;
|
||||
|
||||
import dan200.computercraft.api.lua.IComputerSystem;
|
||||
import dan200.computercraft.api.lua.ILuaAPIFactory;
|
||||
import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.core.apis.ComputerAccess;
|
||||
import dan200.computercraft.core.apis.IAPIEnvironment;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Implementation of {@link IComputerAccess}/{@link IComputerSystem} for usage by externally registered APIs.
|
||||
*
|
||||
* @see ILuaAPIFactory
|
||||
* @see ApiWrapper
|
||||
*/
|
||||
public class ComputerSystem extends ComputerAccess implements IComputerSystem {
|
||||
private final IAPIEnvironment environment;
|
||||
|
||||
ComputerSystem(IAPIEnvironment environment) {
|
||||
super(environment);
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAttachmentName() {
|
||||
return "computer";
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getLabel() {
|
||||
return environment.getLabel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, IPeripheral> getAvailablePeripherals() {
|
||||
// TODO: Should this return peripherals on the current computer?
|
||||
return Map.of();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public IPeripheral getAvailablePeripheral(String name) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -7,9 +7,13 @@
|
||||
-- @module textutils
|
||||
-- @since 1.2
|
||||
|
||||
local expect = dofile("rom/modules/main/cc/expect.lua")
|
||||
local pgk_env = setmetatable({}, { __index = _ENV })
|
||||
pgk_env.require = dofile("rom/modules/main/cc/require.lua").make(pgk_env, "rom/modules/main")
|
||||
local require = pgk_env.require
|
||||
|
||||
local expect = require("cc.expect")
|
||||
local expect, field = expect.expect, expect.field
|
||||
local wrap = dofile("rom/modules/main/cc/strings.lua").wrap
|
||||
local wrap = require("cc.strings").wrap
|
||||
|
||||
--- Slowly writes string text at current cursor position,
|
||||
-- character-by-character.
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
# New features in CC: Tweaked 1.112.0
|
||||
|
||||
* Report a custom error when using `!` instead of `not`.
|
||||
* Update several translations (zyxkad, MineKID-LP).
|
||||
* Add `cc.strings.split` function.
|
||||
|
||||
Several bug fixes:
|
||||
* Fix `drive.getAudioTitle` returning `nil` when no disk is inserted.
|
||||
* Preserve item data when upgrading pocket computers.
|
||||
* Add missing bounds check to `cc.strings.wrap` (Lupus950).
|
||||
* Fix dyed turtles rendering transparent.
|
||||
* Fix dupe bug when crafting with turtles.
|
||||
|
||||
# New features in CC: Tweaked 1.111.1
|
||||
|
||||
* Add support for data-driven turtle upgrades.
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
New features in CC: Tweaked 1.111.1
|
||||
New features in CC: Tweaked 1.112.0
|
||||
|
||||
* Add support for data-driven turtle upgrades.
|
||||
* Report a custom error when using `!` instead of `not`.
|
||||
* Update several translations (zyxkad, MineKID-LP).
|
||||
* Add `cc.strings.split` function.
|
||||
|
||||
Several bug fixes:
|
||||
* Fix monitors not rendering on NeoForge.
|
||||
* Fix turtle labels not rendering.
|
||||
* Fix compatibility with newer versions of NeoForge.
|
||||
* Fix heights of turtle flags.
|
||||
* Fix `drive.getAudioTitle` returning `nil` when no disk is inserted.
|
||||
* Preserve item data when upgrading pocket computers.
|
||||
* Add missing bounds check to `cc.strings.wrap` (Lupus950).
|
||||
* Fix dyed turtles rendering transparent.
|
||||
* Fix dupe bug when crafting with turtles.
|
||||
|
||||
Type "help changelog" to see the full version history.
|
||||
|
||||
@@ -118,8 +118,8 @@ end
|
||||
--- Expect a number to be within a specific range.
|
||||
--
|
||||
-- @tparam number num The value to check.
|
||||
-- @tparam number min The minimum value, if nil then `-math.huge` is used.
|
||||
-- @tparam number max The maximum value, if nil then `math.huge` is used.
|
||||
-- @tparam[opt=-math.huge] number min The minimum value.
|
||||
-- @tparam[opt=math.huge] number max The maximum value.
|
||||
-- @return The given `value`.
|
||||
-- @throws If the value is outside of the allowed range.
|
||||
-- @since 1.96.0
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
-- @since 1.95.0
|
||||
-- @see textutils For additional string related utilities.
|
||||
|
||||
local expect = (require and require("cc.expect") or dofile("rom/modules/main/cc/expect.lua")).expect
|
||||
local expect = require("cc.expect")
|
||||
local expect, range = expect.expect, expect.range
|
||||
|
||||
--[[- Wraps a block of text, so that each line fits within the given width.
|
||||
|
||||
@@ -32,7 +33,7 @@ local function wrap(text, width)
|
||||
expect(1, text, "string")
|
||||
expect(2, width, "number", "nil")
|
||||
width = width or term.getSize()
|
||||
|
||||
range(width, 1)
|
||||
|
||||
local lines, lines_n, current_line = {}, 0, ""
|
||||
local function push_line()
|
||||
@@ -109,7 +110,63 @@ local function ensure_width(line, width)
|
||||
return line
|
||||
end
|
||||
|
||||
--[[- Split a string into parts, each separated by a deliminator.
|
||||
|
||||
For instance, splitting the string `"a b c"` with the deliminator `" "`, would
|
||||
return a table with three strings: `"a"`, `"b"`, and `"c"`.
|
||||
|
||||
By default, the deliminator is given as a [Lua pattern][pattern]. Passing `true`
|
||||
to the `plain` argument will cause the deliminator to be treated as a litteral
|
||||
string.
|
||||
|
||||
[pattern]: https://www.lua.org/manual/5.3/manual.html#6.4.1
|
||||
|
||||
@tparam string str The string to split.
|
||||
@tparam string deliminator The pattern to split this string on.
|
||||
@tparam[opt=false] boolean plain Treat the deliminator as a plain string, rather than a pattern.
|
||||
@tparam[opt] number limit The maximum number of elements in the returned list.
|
||||
@treturn { string... } The list of split strings.
|
||||
|
||||
@usage Split a string into words.
|
||||
|
||||
require "cc.strings".split("This is a sentence.", "%s+")
|
||||
|
||||
@usage Split a string by "-" into at most 3 elements.
|
||||
|
||||
require "cc.strings".split("a-separated-string-of-sorts", "-", true, 3)
|
||||
|
||||
@see table.concat To join strings together.
|
||||
|
||||
@since 1.112.0
|
||||
]]
|
||||
local function split(str, deliminator, plain, limit)
|
||||
expect(1, str, "string")
|
||||
expect(2, deliminator, "string")
|
||||
expect(3, plain, "boolean", "nil")
|
||||
expect(4, limit, "number", "nil")
|
||||
|
||||
local out, out_n, pos = {}, 0, 1
|
||||
while not limit or out_n < limit - 1 do
|
||||
local start, finish = str:find(deliminator, pos, plain)
|
||||
if not start then break end
|
||||
|
||||
out_n = out_n + 1
|
||||
out[out_n] = str:sub(pos, start - 1)
|
||||
|
||||
-- Require us to advance by at least one character.
|
||||
if finish < start then error("separator is empty", 2) end
|
||||
|
||||
pos = finish + 1
|
||||
end
|
||||
|
||||
if pos == 1 then return { str } end
|
||||
|
||||
out[out_n + 1] = str:sub(pos)
|
||||
return out
|
||||
end
|
||||
|
||||
return {
|
||||
wrap = wrap,
|
||||
ensure_width = ensure_width,
|
||||
split = split,
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
--
|
||||
-- SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
describe("cc.pretty", function()
|
||||
describe("cc.strings", function()
|
||||
local str = require("cc.strings")
|
||||
|
||||
describe("wrap", function()
|
||||
@@ -11,6 +11,8 @@ describe("cc.pretty", function()
|
||||
str.wrap("test string is long", 11)
|
||||
expect.error(str.wrap, nil):eq("bad argument #1 (string expected, got nil)")
|
||||
expect.error(str.wrap, "", false):eq("bad argument #2 (number expected, got boolean)")
|
||||
|
||||
expect.error(str.wrap, "", 0):eq("number outside of range (expected 0 to be within 1 and inf)")
|
||||
end)
|
||||
|
||||
it("wraps lines", function()
|
||||
@@ -42,4 +44,33 @@ describe("cc.pretty", function()
|
||||
expect(str.ensure_width("test string is long", 15)):eq("test string is ")
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("split", function()
|
||||
it("splits with empty segments", function()
|
||||
expect(str.split("", "%-")):same { "" }
|
||||
expect(str.split("-", "%-")):same { "", "" }
|
||||
expect(str.split("---", "%-")):same { "", "", "", "" }
|
||||
expect(str.split("-a", "%-")):same { "", "a" }
|
||||
expect(str.split("a-", "%-")):same { "a", "" }
|
||||
end)
|
||||
|
||||
it("cannot split with an empty separator", function()
|
||||
expect.error(str.split, "abc", ""):eq("separator is empty")
|
||||
end)
|
||||
|
||||
it("splits on patterns", function()
|
||||
expect(str.split("a.bcd ef", "%W+")):same { "a", "bcd", "ef" }
|
||||
end)
|
||||
|
||||
it("splits on literal strings", function()
|
||||
expect(str.split("a-bcd-ef", "-", true)):same { "a", "bcd", "ef" }
|
||||
end)
|
||||
|
||||
it("accepts a limit", function()
|
||||
expect(str.split("foo-bar-baz-qux-quyux", "-", true, 3)):same { "foo", "bar", "baz-qux-quyux" }
|
||||
expect(str.split("foo-bar-baz", "-", true, 5)):same { "foo", "bar", "baz" }
|
||||
expect(str.split("foo-bar-baz", "-", true, 1)):same { "foo-bar-baz" }
|
||||
expect(str.split("foo-bar-baz", "-", true, 1)):same { "foo-bar-baz" }
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
|
||||
Reference in New Issue
Block a user