mirror of
https://github.com/IntQuant/noita_entangled_worlds.git
synced 2025-10-19 07:03:16 +00:00
fix telekenesis crash
This commit is contained in:
parent
1717a46b7a
commit
82256e68e8
9 changed files with 958 additions and 908 deletions
|
@ -108,13 +108,35 @@ impl EntityID {
|
||||||
|
|
||||||
pub fn kill(self) {
|
pub fn kill(self) {
|
||||||
// Shouldn't ever error.
|
// Shouldn't ever error.
|
||||||
for (i, id) in raw::physics_body_id_get_from_entity(self, None)
|
let body_id = raw::physics_body_id_get_from_entity(self, None).unwrap_or_default();
|
||||||
.unwrap_or_default()
|
if !body_id.is_empty() {
|
||||||
.iter()
|
for com in raw::entity_get_with_tag("ew_peer".into())
|
||||||
.enumerate()
|
.unwrap_or_default()
|
||||||
{
|
.iter()
|
||||||
let n = 17000.0 + (64.0 * (self.0.get() as usize + i) as f64);
|
.filter_map(|e| {
|
||||||
let _ = raw::physics_body_id_set_transform(*id, n, n, 0.0, 0.0, 0.0, 0.0);
|
e.map(|e| {
|
||||||
|
e.try_get_first_component_including_disabled::<TelekinesisComponent>(None)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
|
.flatten()
|
||||||
|
{
|
||||||
|
if body_id.contains(&com.get_body_id()) {
|
||||||
|
let _ = raw::component_set_value(*com, "mState", 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i, id) in body_id.iter().enumerate() {
|
||||||
|
let n = 17000.0;
|
||||||
|
let _ = raw::physics_body_id_set_transform(
|
||||||
|
*id,
|
||||||
|
n + 64.0 * self.0.get() as f64,
|
||||||
|
n + 64.0 * i as f64,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let _ = raw::entity_kill(self);
|
let _ = raw::entity_kill(self);
|
||||||
}
|
}
|
||||||
|
@ -526,6 +548,12 @@ impl StatusEffectDataComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TelekinesisComponent {
|
||||||
|
pub fn get_body_id(self) -> PhysicsBodyID {
|
||||||
|
raw::component_get_value_old::<PhysicsBodyID>(*self, "mBodyID").unwrap_or(PhysicsBodyID(0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn game_print(value: impl AsRef<str>) {
|
pub fn game_print(value: impl AsRef<str>) {
|
||||||
let _ = raw::game_print(value.as_ref().into());
|
let _ = raw::game_print(value.as_ref().into());
|
||||||
}
|
}
|
||||||
|
@ -560,6 +588,21 @@ pub mod raw {
|
||||||
ret.wrap_err_with(|| eyre!("Getting {field} for {component:?}"))
|
ret.wrap_err_with(|| eyre!("Getting {field} for {component:?}"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn component_get_value_old<T>(component: ComponentID, field: &str) -> eyre::Result<T>
|
||||||
|
where
|
||||||
|
T: LuaGetValue,
|
||||||
|
{
|
||||||
|
let lua = LuaState::current()?;
|
||||||
|
lua.get_global(c"ComponentGetValue");
|
||||||
|
lua.push_integer(component.0.into());
|
||||||
|
lua.push_string(field);
|
||||||
|
lua.call(2, T::size_on_stack())
|
||||||
|
.wrap_err("Failed to call ComponentGetValue")?;
|
||||||
|
let ret = T::get(lua, -1);
|
||||||
|
lua.pop_last_n(T::size_on_stack());
|
||||||
|
ret.wrap_err_with(|| eyre!("Getting {field} for {component:?}"))
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn component_object_get_value<T>(
|
pub(crate) fn component_object_get_value<T>(
|
||||||
component: ComponentID,
|
component: ComponentID,
|
||||||
object: &str,
|
object: &str,
|
||||||
|
|
|
@ -1,24 +1,22 @@
|
||||||
|
-- You're supposed to `dofile_once("path/to/load.lua")` this file.
|
||||||
-- You're supposed to `dofile_once("path/to/load.lua")` this file.
|
|
||||||
|
local orig_do_mod_appends = do_mod_appends
|
||||||
|
|
||||||
local orig_do_mod_appends = do_mod_appends
|
do_mod_appends = function(filename, ...)
|
||||||
|
do_mod_appends = orig_do_mod_appends
|
||||||
do_mod_appends = function(filename, ...)
|
do_mod_appends(filename, ...)
|
||||||
do_mod_appends = orig_do_mod_appends
|
|
||||||
do_mod_appends(filename, ...)
|
local noitapatcher_path = string.match(filename, "(.*)/load.lua")
|
||||||
|
if not noitapatcher_path then
|
||||||
local noitapatcher_path = string.match(filename, "(.*)/load.lua")
|
print("Couldn't detect NoitaPatcher path")
|
||||||
if not noitapatcher_path then
|
end
|
||||||
print("Couldn't detect NoitaPatcher path")
|
|
||||||
end
|
__nsew_path = noitapatcher_path .. "/noitapatcher/nsew/"
|
||||||
|
|
||||||
__nsew_path = noitapatcher_path .. "/noitapatcher/nsew/"
|
package.cpath = package.cpath .. ";./" .. noitapatcher_path .. "/?.dll"
|
||||||
|
package.path = package.path .. ";./" .. noitapatcher_path .. "/?.lua"
|
||||||
package.cpath = package.cpath .. ";./" .. noitapatcher_path .. "/?.dll"
|
|
||||||
package.path = package.path .. ";./" .. noitapatcher_path .. "/?.lua"
|
-- Lua's loader should now be setup properly:
|
||||||
|
-- local np = require("noitapatcher")
|
||||||
-- Lua's loader should now be setup properly:
|
-- local nsew = require("noitapatcher.nsew")
|
||||||
-- local np = require("noitapatcher")
|
end
|
||||||
-- local nsew = require("noitapatcher.nsew")
|
|
||||||
end
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
---Native library. Primarily for internal use.
|
---Native library. Primarily for internal use.
|
||||||
---@module 'noitapatcher.nsew.native_dll'
|
---@module 'noitapatcher.nsew.native_dll'
|
||||||
|
|
||||||
local ffi = require("ffi")
|
local ffi = require("ffi")
|
||||||
|
|
||||||
native_dll = {}
|
native_dll = {}
|
||||||
|
|
||||||
---The NSEW support dll loaded in with `ffi.load`.
|
---The NSEW support dll loaded in with `ffi.load`.
|
||||||
native_dll.lib = ffi.load(__nsew_path .. "nsew_native.dll")
|
native_dll.lib = ffi.load(__nsew_path .. "nsew_native.dll")
|
||||||
|
|
||||||
return native_dll
|
return native_dll
|
||||||
|
|
|
@ -1,167 +1,167 @@
|
||||||
---Rectangle utilities.
|
---Rectangle utilities.
|
||||||
---@module 'noitapatcher.nsew.rect'
|
---@module 'noitapatcher.nsew.rect'
|
||||||
|
|
||||||
---@class Rect
|
---@class Rect
|
||||||
local rect = {}
|
local rect = {}
|
||||||
|
|
||||||
local ffi = require("ffi")
|
local ffi = require("ffi")
|
||||||
local native_dll = require("noitapatcher.nsew.native_dll")
|
local native_dll = require("noitapatcher.nsew.native_dll")
|
||||||
|
|
||||||
ffi.cdef([[
|
ffi.cdef([[
|
||||||
|
|
||||||
struct nsew_rectangle {
|
struct nsew_rectangle {
|
||||||
int32_t left;
|
int32_t left;
|
||||||
int32_t top;
|
int32_t top;
|
||||||
int32_t right;
|
int32_t right;
|
||||||
int32_t bottom;
|
int32_t bottom;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct nsew_rectangle_optimiser;
|
struct nsew_rectangle_optimiser;
|
||||||
|
|
||||||
struct nsew_rectangle_optimiser* rectangle_optimiser_new();
|
struct nsew_rectangle_optimiser* rectangle_optimiser_new();
|
||||||
void rectangle_optimiser_delete(struct nsew_rectangle_optimiser* rectangle_optimiser);
|
void rectangle_optimiser_delete(struct nsew_rectangle_optimiser* rectangle_optimiser);
|
||||||
void rectangle_optimiser_reset(struct nsew_rectangle_optimiser* rectangle_optimiser);
|
void rectangle_optimiser_reset(struct nsew_rectangle_optimiser* rectangle_optimiser);
|
||||||
void rectangle_optimiser_submit(struct nsew_rectangle_optimiser* rectangle_optimiser, struct nsew_rectangle* rectangle);
|
void rectangle_optimiser_submit(struct nsew_rectangle_optimiser* rectangle_optimiser, struct nsew_rectangle* rectangle);
|
||||||
void rectangle_optimiser_scan(struct nsew_rectangle_optimiser* rectangle_optimiser);
|
void rectangle_optimiser_scan(struct nsew_rectangle_optimiser* rectangle_optimiser);
|
||||||
int32_t rectangle_optimiser_size(const struct nsew_rectangle_optimiser* rectangle_optimiser);
|
int32_t rectangle_optimiser_size(const struct nsew_rectangle_optimiser* rectangle_optimiser);
|
||||||
const struct nsew_rectangle* rectangle_optimiser_get(const struct nsew_rectangle_optimiser* rectangle_optimiser, int32_t index);
|
const struct nsew_rectangle* rectangle_optimiser_get(const struct nsew_rectangle_optimiser* rectangle_optimiser, int32_t index);
|
||||||
|
|
||||||
|
|
||||||
struct lua_nsew_rectangle_optimiser {
|
struct lua_nsew_rectangle_optimiser {
|
||||||
struct nsew_rectangle_optimiser* impl;
|
struct nsew_rectangle_optimiser* impl;
|
||||||
};
|
};
|
||||||
|
|
||||||
]])
|
]])
|
||||||
|
|
||||||
---@class Rectangle_fields
|
---@class Rectangle_fields
|
||||||
---@field top integer
|
---@field top integer
|
||||||
---@field bottom integer
|
---@field bottom integer
|
||||||
---@field right integer
|
---@field right integer
|
||||||
---@field left integer
|
---@field left integer
|
||||||
|
|
||||||
---@alias Rectangle Rectangle_mt | Rectangle_fields
|
---@alias Rectangle Rectangle_mt | Rectangle_fields
|
||||||
|
|
||||||
---@class Optimiser_fields
|
---@class Optimiser_fields
|
||||||
---@field top integer
|
---@field top integer
|
||||||
---@field bottom integer
|
---@field bottom integer
|
||||||
---@field right integer
|
---@field right integer
|
||||||
---@field left integer
|
---@field left integer
|
||||||
|
|
||||||
---@alias Optimiser Optimiser_fields | Optimiser_mt
|
---@alias Optimiser Optimiser_fields | Optimiser_mt
|
||||||
|
|
||||||
---@class Rectangle_mt
|
---@class Rectangle_mt
|
||||||
local Rectangle_mt_index = {
|
local Rectangle_mt_index = {
|
||||||
---@param r Rectangle
|
---@param r Rectangle
|
||||||
---@return integer
|
---@return integer
|
||||||
area = function(r)
|
area = function(r)
|
||||||
return (r.right - r.left) * (r.bottom - r.top)
|
return (r.right - r.left) * (r.bottom - r.top)
|
||||||
end,
|
end,
|
||||||
---@param r Rectangle
|
---@param r Rectangle
|
||||||
---@return integer
|
---@return integer
|
||||||
height = function(r)
|
height = function(r)
|
||||||
return r.bottom - r.top
|
return r.bottom - r.top
|
||||||
end,
|
end,
|
||||||
---@param r Rectangle
|
---@param r Rectangle
|
||||||
---@return integer
|
---@return integer
|
||||||
width = function(r)
|
width = function(r)
|
||||||
return r.right - r.left
|
return r.right - r.left
|
||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
local Rectangle_mt = {
|
local Rectangle_mt = {
|
||||||
__index = Rectangle_mt_index,
|
__index = Rectangle_mt_index,
|
||||||
}
|
}
|
||||||
|
|
||||||
---@type fun(left, top, right, bottom): Rectangle
|
---@type fun(left, top, right, bottom): Rectangle
|
||||||
---@diagnostic disable-next-line: assign-type-mismatch
|
---@diagnostic disable-next-line: assign-type-mismatch
|
||||||
rect.Rectangle = ffi.metatype("struct nsew_rectangle", Rectangle_mt)
|
rect.Rectangle = ffi.metatype("struct nsew_rectangle", Rectangle_mt)
|
||||||
|
|
||||||
---Given an iterator that returns rectangles, return an iterator where the
|
---Given an iterator that returns rectangles, return an iterator where the
|
||||||
---rectangle extents never exceed `size`.
|
---rectangle extents never exceed `size`.
|
||||||
---@param iterator fun(): Rectangle? returning rectangles
|
---@param iterator fun(): Rectangle? returning rectangles
|
||||||
---@param size integer maximum width and height
|
---@param size integer maximum width and height
|
||||||
---@return fun(): Rectangle? rectangles where the extents never exceed `size`
|
---@return fun(): Rectangle? rectangles where the extents never exceed `size`
|
||||||
function rect.parts(iterator, size)
|
function rect.parts(iterator, size)
|
||||||
local region
|
local region
|
||||||
local posx
|
local posx
|
||||||
local posy
|
local posy
|
||||||
return function()
|
return function()
|
||||||
if region == nil then
|
if region == nil then
|
||||||
region = iterator()
|
region = iterator()
|
||||||
if region == nil then
|
if region == nil then
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
posx = region.left
|
posx = region.left
|
||||||
posy = region.top
|
posy = region.top
|
||||||
end
|
end
|
||||||
|
|
||||||
local endx = math.min(posx + size, region.right)
|
local endx = math.min(posx + size, region.right)
|
||||||
local endy = math.min(posy + size, region.bottom)
|
local endy = math.min(posy + size, region.bottom)
|
||||||
|
|
||||||
local ret = rect.Rectangle(posx, posy, endx, endy)
|
local ret = rect.Rectangle(posx, posy, endx, endy)
|
||||||
|
|
||||||
-- Setup for next iteration: place to the right, wraparound, or
|
-- Setup for next iteration: place to the right, wraparound, or
|
||||||
-- we're done with this region.
|
-- we're done with this region.
|
||||||
if endx ~= region.right then
|
if endx ~= region.right then
|
||||||
posx = endx
|
posx = endx
|
||||||
elseif endy ~= region.bottom then
|
elseif endy ~= region.bottom then
|
||||||
posx = region.left
|
posx = region.left
|
||||||
posy = endy
|
posy = endy
|
||||||
else
|
else
|
||||||
region = nil
|
region = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
---@class Optimiser_mt
|
---@class Optimiser_mt
|
||||||
local Optimiser_mt_index = {
|
local Optimiser_mt_index = {
|
||||||
submit = function(opt, rectangle)
|
submit = function(opt, rectangle)
|
||||||
native_dll.lib.rectangle_optimiser_submit(opt.impl, rectangle)
|
native_dll.lib.rectangle_optimiser_submit(opt.impl, rectangle)
|
||||||
end,
|
end,
|
||||||
scan = function(opt)
|
scan = function(opt)
|
||||||
native_dll.lib.rectangle_optimiser_scan(opt.impl)
|
native_dll.lib.rectangle_optimiser_scan(opt.impl)
|
||||||
end,
|
end,
|
||||||
reset = function(opt)
|
reset = function(opt)
|
||||||
native_dll.lib.rectangle_optimiser_reset(opt.impl)
|
native_dll.lib.rectangle_optimiser_reset(opt.impl)
|
||||||
end,
|
end,
|
||||||
size = function(opt)
|
size = function(opt)
|
||||||
return native_dll.lib.rectangle_optimiser_size(opt.impl)
|
return native_dll.lib.rectangle_optimiser_size(opt.impl)
|
||||||
end,
|
end,
|
||||||
get = function(opt, index)
|
get = function(opt, index)
|
||||||
return native_dll.lib.rectangle_optimiser_get(opt.impl, index)
|
return native_dll.lib.rectangle_optimiser_get(opt.impl, index)
|
||||||
end,
|
end,
|
||||||
iterate = function(opt)
|
iterate = function(opt)
|
||||||
local size = native_dll.lib.rectangle_optimiser_size(opt.impl)
|
local size = native_dll.lib.rectangle_optimiser_size(opt.impl)
|
||||||
local index = 0
|
local index = 0
|
||||||
return function()
|
return function()
|
||||||
if index >= size then
|
if index >= size then
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
local ret = native_dll.lib.rectangle_optimiser_get(opt.impl, index)
|
local ret = native_dll.lib.rectangle_optimiser_get(opt.impl, index)
|
||||||
index = index + 1
|
index = index + 1
|
||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
|
|
||||||
local Optimiser_mt = {
|
local Optimiser_mt = {
|
||||||
__gc = function(opt)
|
__gc = function(opt)
|
||||||
native_dll.lib.rectangle_optimiser_delete(opt.impl)
|
native_dll.lib.rectangle_optimiser_delete(opt.impl)
|
||||||
end,
|
end,
|
||||||
__index = Optimiser_mt_index,
|
__index = Optimiser_mt_index,
|
||||||
}
|
}
|
||||||
|
|
||||||
---@type fun(unknown): Optimiser
|
---@type fun(unknown): Optimiser
|
||||||
---@diagnostic disable-next-line: assign-type-mismatch
|
---@diagnostic disable-next-line: assign-type-mismatch
|
||||||
rect.Optimiser = ffi.metatype("struct lua_nsew_rectangle_optimiser", Optimiser_mt)
|
rect.Optimiser = ffi.metatype("struct lua_nsew_rectangle_optimiser", Optimiser_mt)
|
||||||
|
|
||||||
---Create a new rectangle Optimiser
|
---Create a new rectangle Optimiser
|
||||||
---@return Optimiser optimiser
|
---@return Optimiser optimiser
|
||||||
function rect.Optimiser_new()
|
function rect.Optimiser_new()
|
||||||
return rect.Optimiser(native_dll.lib.rectangle_optimiser_new())
|
return rect.Optimiser(native_dll.lib.rectangle_optimiser_new())
|
||||||
end
|
end
|
||||||
|
|
||||||
return rect
|
return rect
|
||||||
|
|
|
@ -1,272 +1,273 @@
|
||||||
---@diagnostic disable: cast-local-type
|
---@diagnostic disable: cast-local-type
|
||||||
---World read / write functionality.
|
---World read / write functionality.
|
||||||
---@module 'noitapatcher.nsew.world'
|
---@module 'noitapatcher.nsew.world'
|
||||||
---@class World
|
---@class World
|
||||||
local world = {}
|
local world = {}
|
||||||
|
|
||||||
local ffi = require("ffi")
|
local ffi = require("ffi")
|
||||||
local world_ffi = require("noitapatcher.nsew.world_ffi")
|
local world_ffi = require("noitapatcher.nsew.world_ffi")
|
||||||
|
|
||||||
local C = ffi.C
|
local C = ffi.C
|
||||||
|
|
||||||
ffi.cdef([[
|
ffi.cdef([[
|
||||||
|
|
||||||
enum ENCODE_CONST {
|
enum ENCODE_CONST {
|
||||||
PIXEL_RUN_MAX = 4096,
|
PIXEL_RUN_MAX = 4096,
|
||||||
|
|
||||||
LIQUID_FLAG_STATIC = 1,
|
LIQUID_FLAG_STATIC = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct __attribute__ ((__packed__)) EncodedAreaHeader {
|
struct __attribute__ ((__packed__)) EncodedAreaHeader {
|
||||||
int32_t x;
|
int32_t x;
|
||||||
int32_t y;
|
int32_t y;
|
||||||
uint8_t width;
|
uint8_t width;
|
||||||
uint8_t height;
|
uint8_t height;
|
||||||
|
|
||||||
uint16_t pixel_run_count;
|
uint16_t pixel_run_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct __attribute__ ((__packed__)) PixelRun {
|
struct __attribute__ ((__packed__)) PixelRun {
|
||||||
uint16_t length;
|
uint16_t length;
|
||||||
int16_t material;
|
int16_t material;
|
||||||
uint8_t flags;
|
uint8_t flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct __attribute__ ((__packed__)) EncodedArea {
|
struct __attribute__ ((__packed__)) EncodedArea {
|
||||||
struct EncodedAreaHeader header;
|
struct EncodedAreaHeader header;
|
||||||
struct PixelRun pixel_runs[PIXEL_RUN_MAX];
|
struct PixelRun pixel_runs[PIXEL_RUN_MAX];
|
||||||
};
|
};
|
||||||
|
|
||||||
]])
|
]])
|
||||||
|
|
||||||
---@class PixelRun
|
---@class PixelRun
|
||||||
---@field flags integer
|
---@field flags integer
|
||||||
---@field material integer
|
---@field material integer
|
||||||
---@field length integer
|
---@field length integer
|
||||||
|
|
||||||
---@class EncodedAreaHeader
|
---@class EncodedAreaHeader
|
||||||
---@field x integer
|
---@field x integer
|
||||||
---@field y integer
|
---@field y integer
|
||||||
---@field width integer
|
---@field width integer
|
||||||
---@field height integer
|
---@field height integer
|
||||||
---@field pixel_run_count integer
|
---@field pixel_run_count integer
|
||||||
|
|
||||||
---@class EncodedArea
|
---@class EncodedArea
|
||||||
---@field header EncodedAreaHeader
|
---@field header EncodedAreaHeader
|
||||||
---@field pixel_runs PixelRun[] a pointer
|
---@field pixel_runs PixelRun[] a pointer
|
||||||
|
|
||||||
world.EncodedAreaHeader = ffi.typeof("struct EncodedAreaHeader")
|
world.EncodedAreaHeader = ffi.typeof("struct EncodedAreaHeader")
|
||||||
world.PixelRun = ffi.typeof("struct PixelRun")
|
world.PixelRun = ffi.typeof("struct PixelRun")
|
||||||
---@type fun(): EncodedArea
|
---@type fun(): EncodedArea
|
||||||
---@diagnostic disable-next-line: assign-type-mismatch
|
---@diagnostic disable-next-line: assign-type-mismatch
|
||||||
world.EncodedArea = ffi.typeof("struct EncodedArea")
|
world.EncodedArea = ffi.typeof("struct EncodedArea")
|
||||||
|
|
||||||
local pliquid_cell = ffi.typeof("struct CLiquidCell*")
|
local pliquid_cell = ffi.typeof("struct CLiquidCell*")
|
||||||
|
|
||||||
---Total bytes taken up by the encoded area
|
---Total bytes taken up by the encoded area
|
||||||
---@param encoded_area EncodedArea
|
---@param encoded_area EncodedArea
|
||||||
---@return integer total number of bytes that encodes the area
|
---@return integer total number of bytes that encodes the area
|
||||||
---```lua
|
---```lua
|
||||||
---local data = ffi.string(area, world.encoded_size(area))
|
---local data = ffi.string(area, world.encoded_size(area))
|
||||||
---peer:send(data)
|
---peer:send(data)
|
||||||
---```
|
---```
|
||||||
function world.encoded_size(encoded_area)
|
function world.encoded_size(encoded_area)
|
||||||
return ffi.sizeof(world.EncodedAreaHeader) + encoded_area.header.pixel_run_count * ffi.sizeof(world.PixelRun)
|
return ffi.sizeof(world.EncodedAreaHeader) + encoded_area.header.pixel_run_count * ffi.sizeof(world.PixelRun)
|
||||||
end
|
end
|
||||||
|
|
||||||
---Encode the given rectangle of the world
|
---Encode the given rectangle of the world
|
||||||
---The rectangle defined by {`start_x`, `start_y`, `end_x`, `end_y`} must not exceed 256 in width or height.
|
---The rectangle defined by {`start_x`, `start_y`, `end_x`, `end_y`} must not exceed 256 in width or height.
|
||||||
---@param chunk_map unknown
|
---@param chunk_map unknown
|
||||||
---@param start_x integer coordinate
|
---@param start_x integer coordinate
|
||||||
---@param start_y integer coordinate
|
---@param start_y integer coordinate
|
||||||
---@param end_x integer coordinate
|
---@param end_x integer coordinate
|
||||||
---@param end_y integer coordinate
|
---@param end_y integer coordinate
|
||||||
---@param encoded_area EncodedArea? memory to use, if nil this function allocates its own memory
|
---@param encoded_area EncodedArea? memory to use, if nil this function allocates its own memory
|
||||||
---@return EncodedArea? encoded_area returns an EncodedArea or nil if the area could not be encoded
|
---@return EncodedArea? encoded_area returns an EncodedArea or nil if the area could not be encoded
|
||||||
---@see decode
|
---@see decode
|
||||||
function world.encode_area(chunk_map, start_x, start_y, end_x, end_y, encoded_area)
|
function world.encode_area(chunk_map, start_x, start_y, end_x, end_y, encoded_area)
|
||||||
start_x = ffi.cast('int32_t', start_x)
|
start_x = ffi.cast("int32_t", start_x)
|
||||||
start_y = ffi.cast('int32_t', start_y)
|
start_y = ffi.cast("int32_t", start_y)
|
||||||
end_x = ffi.cast('int32_t', end_x)
|
end_x = ffi.cast("int32_t", end_x)
|
||||||
end_y = ffi.cast('int32_t', end_y)
|
end_y = ffi.cast("int32_t", end_y)
|
||||||
---@cast start_x integer
|
---@cast start_x integer
|
||||||
---@cast start_y integer
|
---@cast start_y integer
|
||||||
---@cast end_x integer
|
---@cast end_x integer
|
||||||
---@cast end_x integer
|
---@cast end_x integer
|
||||||
|
|
||||||
encoded_area = encoded_area or world.EncodedArea()
|
encoded_area = encoded_area or world.EncodedArea()
|
||||||
|
|
||||||
local width = end_x - start_x
|
local width = end_x - start_x
|
||||||
local height = end_y - start_y
|
local height = end_y - start_y
|
||||||
|
|
||||||
if width <= 0 or height <= 0 then
|
if width <= 0 or height <= 0 then
|
||||||
print("Invalid world part, negative dimension")
|
print("Invalid world part, negative dimension")
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
if width > 256 or height > 256 then
|
if width > 256 or height > 256 then
|
||||||
print("Invalid world part, dimension greater than 256")
|
print("Invalid world part, dimension greater than 256")
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
encoded_area.header.x = start_x
|
encoded_area.header.x = start_x
|
||||||
encoded_area.header.y = start_y
|
encoded_area.header.y = start_y
|
||||||
encoded_area.header.width = width - 1
|
encoded_area.header.width = width - 1
|
||||||
encoded_area.header.height = height - 1
|
encoded_area.header.height = height - 1
|
||||||
|
|
||||||
local run_count = 1
|
local run_count = 1
|
||||||
|
|
||||||
local current_run = encoded_area.pixel_runs[0]
|
local current_run = encoded_area.pixel_runs[0]
|
||||||
local run_length = 0
|
local run_length = 0
|
||||||
local current_material = 0
|
local current_material = 0
|
||||||
local current_flags = 0
|
local current_flags = 0
|
||||||
|
|
||||||
local y = start_y
|
local y = start_y
|
||||||
while y < end_y do
|
while y < end_y do
|
||||||
local x = start_x
|
local x = start_x
|
||||||
while x < end_x do
|
while x < end_x do
|
||||||
local material_number = 0
|
local material_number = 0
|
||||||
local flags = 0
|
local flags = 0
|
||||||
|
|
||||||
local ppixel = world_ffi.get_cell(chunk_map, x, y)
|
local ppixel = world_ffi.get_cell(chunk_map, x, y)
|
||||||
local pixel = ppixel[0]
|
local pixel = ppixel[0]
|
||||||
if pixel ~= nil then
|
if pixel ~= nil then
|
||||||
local cell_type = pixel.vtable.get_cell_type(pixel)
|
local cell_type = pixel.vtable.get_cell_type(pixel)
|
||||||
|
|
||||||
if cell_type ~= C.CELL_TYPE_SOLID then
|
if cell_type ~= C.CELL_TYPE_SOLID then
|
||||||
local material_ptr = pixel.vtable.get_material(pixel)
|
local material_ptr = pixel.vtable.get_material(pixel)
|
||||||
material_number = world_ffi.get_material_id(material_ptr)
|
material_number = world_ffi.get_material_id(material_ptr)
|
||||||
end
|
end
|
||||||
|
|
||||||
if cell_type == C.CELL_TYPE_LIQUID then
|
if cell_type == C.CELL_TYPE_LIQUID then
|
||||||
local liquid_cell = ffi.cast(pliquid_cell, pixel)
|
local liquid_cell = ffi.cast(pliquid_cell, pixel)
|
||||||
if liquid_cell.is_static then
|
if liquid_cell.is_static then
|
||||||
flags = bit.bor(flags, C.LIQUID_FLAG_STATIC)
|
flags = bit.bor(flags, C.LIQUID_FLAG_STATIC)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if x == start_x and y == start_y then
|
if x == start_x and y == start_y then
|
||||||
-- Initial run
|
-- Initial run
|
||||||
current_material = material_number
|
current_material = material_number
|
||||||
current_flags = flags
|
current_flags = flags
|
||||||
elseif current_material ~= material_number or current_flags ~= flags then
|
elseif current_material ~= material_number or current_flags ~= flags then
|
||||||
-- Next run
|
-- Next run
|
||||||
current_run.length = run_length - 1
|
current_run.length = run_length - 1
|
||||||
current_run.material = current_material
|
current_run.material = current_material
|
||||||
current_run.flags = current_flags
|
current_run.flags = current_flags
|
||||||
|
|
||||||
if run_count == C.PIXEL_RUN_MAX then
|
if run_count == C.PIXEL_RUN_MAX then
|
||||||
print("Area too complicated to encode")
|
print("Area too complicated to encode")
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
current_run = encoded_area.pixel_runs[run_count]
|
current_run = encoded_area.pixel_runs[run_count]
|
||||||
run_count = run_count + 1
|
run_count = run_count + 1
|
||||||
|
|
||||||
run_length = 0
|
run_length = 0
|
||||||
current_material = material_number
|
current_material = material_number
|
||||||
current_flags = flags
|
current_flags = flags
|
||||||
end
|
end
|
||||||
|
|
||||||
run_length = run_length + 1
|
run_length = run_length + 1
|
||||||
|
|
||||||
x = x + 1
|
x = x + 1
|
||||||
end
|
end
|
||||||
y = y + 1
|
y = y + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
current_run.length = run_length - 1
|
current_run.length = run_length - 1
|
||||||
current_run.material = current_material
|
current_run.material = current_material
|
||||||
current_run.flags = current_flags
|
current_run.flags = current_flags
|
||||||
|
|
||||||
encoded_area.header.pixel_run_count = run_count
|
encoded_area.header.pixel_run_count = run_count
|
||||||
|
|
||||||
return encoded_area
|
return encoded_area
|
||||||
end
|
end
|
||||||
|
|
||||||
local PixelRun_const_ptr = ffi.typeof("struct PixelRun const*")
|
local PixelRun_const_ptr = ffi.typeof("struct PixelRun const*")
|
||||||
|
|
||||||
---Load an encoded area back into the world.
|
---Load an encoded area back into the world.
|
||||||
---@param grid_world unknown
|
---@param grid_world unknown
|
||||||
---@param header EncodedAreaHeader header of the encoded area
|
---@param header EncodedAreaHeader header of the encoded area
|
||||||
---@param pixel_runs PixelRun[] or ffi array of PixelRun from the encoded area
|
---@param pixel_runs PixelRun[] or ffi array of PixelRun from the encoded area
|
||||||
---@see encode_area
|
---@see encode_area
|
||||||
function world.decode(grid_world, header, pixel_runs)
|
function world.decode(grid_world, header, pixel_runs)
|
||||||
local chunk_map = grid_world.vtable.get_chunk_map(grid_world)
|
local chunk_map = grid_world.vtable.get_chunk_map(grid_world)
|
||||||
|
|
||||||
local top_left_x = header.x
|
local top_left_x = header.x
|
||||||
local top_left_y = header.y
|
local top_left_y = header.y
|
||||||
local width = header.width + 1
|
local width = header.width + 1
|
||||||
local height = header.height + 1
|
local height = header.height + 1
|
||||||
local bottom_right_x = top_left_x + width
|
local bottom_right_x = top_left_x + width
|
||||||
local bottom_right_y = top_left_y + height
|
local bottom_right_y = top_left_y + height
|
||||||
|
|
||||||
local current_run_ix = 0
|
local current_run_ix = 0
|
||||||
local current_run = pixel_runs[current_run_ix]
|
local current_run = pixel_runs[current_run_ix]
|
||||||
local new_material = current_run.material
|
local new_material = current_run.material
|
||||||
local flags = current_run.flags
|
local flags = current_run.flags
|
||||||
local left = current_run.length + 1
|
local left = current_run.length + 1
|
||||||
|
|
||||||
local y = top_left_y
|
local y = top_left_y
|
||||||
while y < bottom_right_y do
|
while y < bottom_right_y do
|
||||||
local x = top_left_x
|
local x = top_left_x
|
||||||
while x < bottom_right_x do
|
while x < bottom_right_x do
|
||||||
if world_ffi.chunk_loaded(chunk_map, x, y) then
|
if world_ffi.chunk_loaded(chunk_map, x, y) then
|
||||||
local ppixel = world_ffi.get_cell(chunk_map, x, y)
|
local ppixel = world_ffi.get_cell(chunk_map, x, y)
|
||||||
local current_material = 0
|
local current_material = 0
|
||||||
|
|
||||||
if ppixel[0] ~= nil then
|
if ppixel[0] ~= nil then
|
||||||
local pixel = ppixel[0]
|
local pixel = ppixel[0]
|
||||||
current_material = world_ffi.get_material_id(pixel.vtable.get_material(pixel))
|
current_material = world_ffi.get_material_id(pixel.vtable.get_material(pixel))
|
||||||
|
|
||||||
if new_material ~= current_material then
|
if new_material ~= current_material then
|
||||||
world_ffi.remove_cell(grid_world, pixel, x, y, false)
|
world_ffi.remove_cell(grid_world, pixel, x, y, false)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if current_material ~= new_material and new_material ~= 0 then
|
if current_material ~= new_material and new_material ~= 0 then
|
||||||
local pixel = world_ffi.construct_cell(grid_world, x, y, world_ffi.get_material_ptr(new_material), nil)
|
local pixel =
|
||||||
if pixel == nil then
|
world_ffi.construct_cell(grid_world, x, y, world_ffi.get_material_ptr(new_material), nil)
|
||||||
-- TODO: This can happen when the material texture has a
|
if pixel == nil then
|
||||||
-- transparent pixel at the given coordinate. There's
|
-- TODO: This can happen when the material texture has a
|
||||||
-- probably a better way to deal with this, but for now
|
-- transparent pixel at the given coordinate. There's
|
||||||
-- we skip positions like this.
|
-- probably a better way to deal with this, but for now
|
||||||
goto next_pixel
|
-- we skip positions like this.
|
||||||
end
|
goto next_pixel
|
||||||
local cell_type = pixel.vtable.get_cell_type(pixel)
|
end
|
||||||
|
local cell_type = pixel.vtable.get_cell_type(pixel)
|
||||||
if cell_type == C.CELL_TYPE_LIQUID then
|
|
||||||
local liquid_cell = ffi.cast(pliquid_cell, pixel)
|
if cell_type == C.CELL_TYPE_LIQUID then
|
||||||
liquid_cell.is_static = bit.band(flags, C.CELL_TYPE_LIQUID) == C.LIQUID_FLAG_STATIC
|
local liquid_cell = ffi.cast(pliquid_cell, pixel)
|
||||||
end
|
liquid_cell.is_static = bit.band(flags, C.CELL_TYPE_LIQUID) == C.LIQUID_FLAG_STATIC
|
||||||
|
end
|
||||||
ppixel[0] = pixel
|
|
||||||
end
|
ppixel[0] = pixel
|
||||||
end
|
end
|
||||||
|
end
|
||||||
::next_pixel::
|
|
||||||
|
::next_pixel::
|
||||||
left = left - 1
|
|
||||||
if left <= 0 then
|
left = left - 1
|
||||||
current_run_ix = current_run_ix + 1
|
if left <= 0 then
|
||||||
if current_run_ix >= header.pixel_run_count then
|
current_run_ix = current_run_ix + 1
|
||||||
-- No more runs, done
|
if current_run_ix >= header.pixel_run_count then
|
||||||
assert(x == bottom_right_x - 1)
|
-- No more runs, done
|
||||||
assert(y == bottom_right_y - 1)
|
assert(x == bottom_right_x - 1)
|
||||||
return
|
assert(y == bottom_right_y - 1)
|
||||||
end
|
return
|
||||||
|
end
|
||||||
current_run = pixel_runs[current_run_ix]
|
|
||||||
new_material = current_run.material
|
current_run = pixel_runs[current_run_ix]
|
||||||
flags = current_run.flags
|
new_material = current_run.material
|
||||||
left = current_run.length + 1
|
flags = current_run.flags
|
||||||
end
|
left = current_run.length + 1
|
||||||
|
end
|
||||||
x = x + 1
|
|
||||||
end
|
x = x + 1
|
||||||
y = y + 1
|
end
|
||||||
end
|
y = y + 1
|
||||||
end
|
end
|
||||||
|
end
|
||||||
return world
|
|
||||||
|
return world
|
||||||
|
|
|
@ -1,425 +1,425 @@
|
||||||
---@diagnostic disable: assign-type-mismatch
|
---@diagnostic disable: assign-type-mismatch
|
||||||
---Noita world functionality exposed.
|
---Noita world functionality exposed.
|
||||||
---@module 'noitapatcher.nsew.world_ffi'
|
---@module 'noitapatcher.nsew.world_ffi'
|
||||||
|
|
||||||
---@class WorldFFI
|
---@class WorldFFI
|
||||||
local world_ffi = {}
|
local world_ffi = {}
|
||||||
|
|
||||||
local ffi = require("ffi")
|
local ffi = require("ffi")
|
||||||
|
|
||||||
local np = require("noitapatcher")
|
local np = require("noitapatcher")
|
||||||
local world_info = np.GetWorldInfo()
|
local world_info = np.GetWorldInfo()
|
||||||
|
|
||||||
if not world_info then
|
if not world_info then
|
||||||
error("Couldn't get world info from NoitaPatcher.")
|
error("Couldn't get world info from NoitaPatcher.")
|
||||||
end
|
end
|
||||||
|
|
||||||
local gg_ptr = world_info.game_global
|
local gg_ptr = world_info.game_global
|
||||||
|
|
||||||
ffi.cdef([[
|
ffi.cdef([[
|
||||||
|
|
||||||
typedef void* __thiscall placeholder_memfn(void*);
|
typedef void* __thiscall placeholder_memfn(void*);
|
||||||
|
|
||||||
struct Position {
|
struct Position {
|
||||||
int x;
|
int x;
|
||||||
int y;
|
int y;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Colour {
|
struct Colour {
|
||||||
uint8_t r;
|
uint8_t r;
|
||||||
uint8_t g;
|
uint8_t g;
|
||||||
uint8_t b;
|
uint8_t b;
|
||||||
uint8_t a;
|
uint8_t a;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AABB {
|
struct AABB {
|
||||||
struct Position top_left;
|
struct Position top_left;
|
||||||
struct Position bottom_right;
|
struct Position bottom_right;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct std_string { /* VC++ std::string */
|
struct std_string { /* VC++ std::string */
|
||||||
char *buffer;
|
char *buffer;
|
||||||
char sso_buffer[12];
|
char sso_buffer[12];
|
||||||
size_t size;
|
size_t size;
|
||||||
size_t capacity;
|
size_t capacity;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum cell_type {
|
typedef enum cell_type {
|
||||||
none=0,
|
none=0,
|
||||||
liquid=1,
|
liquid=1,
|
||||||
gas=2,
|
gas=2,
|
||||||
solid=3,
|
solid=3,
|
||||||
fire=4,
|
fire=4,
|
||||||
invalid=4294967295
|
invalid=4294967295
|
||||||
} cell_type;
|
} cell_type;
|
||||||
|
|
||||||
struct CellData {
|
struct CellData {
|
||||||
struct std_string name;
|
struct std_string name;
|
||||||
struct std_string ui_name;
|
struct std_string ui_name;
|
||||||
int material_type;
|
int material_type;
|
||||||
int id_2;
|
int id_2;
|
||||||
enum cell_type cell_type;
|
enum cell_type cell_type;
|
||||||
int platform_type;
|
int platform_type;
|
||||||
unsigned int wang_color;
|
unsigned int wang_color;
|
||||||
int gfx_glow;
|
int gfx_glow;
|
||||||
unsigned int gfx_glow_color;
|
unsigned int gfx_glow_color;
|
||||||
char unknown1[24];
|
char unknown1[24];
|
||||||
unsigned int default_primary_colour;
|
unsigned int default_primary_colour;
|
||||||
char unknown2[36];
|
char unknown2[36];
|
||||||
bool cell_holes_in_texture;
|
bool cell_holes_in_texture;
|
||||||
bool stainable;
|
bool stainable;
|
||||||
bool burnable;
|
bool burnable;
|
||||||
bool on_fire;
|
bool on_fire;
|
||||||
int fire_hp;
|
int fire_hp;
|
||||||
int autoignition_temperature;
|
int autoignition_temperature;
|
||||||
int _100_minus_autoignition_temp;
|
int _100_minus_autoignition_temp;
|
||||||
int temperature_of_fire;
|
int temperature_of_fire;
|
||||||
int generates_smoke;
|
int generates_smoke;
|
||||||
int generates_flames;
|
int generates_flames;
|
||||||
bool requires_oxygen;
|
bool requires_oxygen;
|
||||||
char padding1[3];
|
char padding1[3];
|
||||||
struct std_string on_fire_convert_to_material;
|
struct std_string on_fire_convert_to_material;
|
||||||
int on_fire_convert_to_material_id;
|
int on_fire_convert_to_material_id;
|
||||||
struct std_string on_fire_flame_material;
|
struct std_string on_fire_flame_material;
|
||||||
int on_fire_flame_material_id;
|
int on_fire_flame_material_id;
|
||||||
struct std_string on_fire_smoke_material;
|
struct std_string on_fire_smoke_material;
|
||||||
int on_fire_smoke_material_id;
|
int on_fire_smoke_material_id;
|
||||||
struct ConfigExplosion *explosion_config;
|
struct ConfigExplosion *explosion_config;
|
||||||
int durability;
|
int durability;
|
||||||
int crackability;
|
int crackability;
|
||||||
bool electrical_conductivity;
|
bool electrical_conductivity;
|
||||||
bool slippery;
|
bool slippery;
|
||||||
char padding2[2];
|
char padding2[2];
|
||||||
float stickyness;
|
float stickyness;
|
||||||
struct std_string cold_freezes_to_material;
|
struct std_string cold_freezes_to_material;
|
||||||
struct std_string warmth_melts_to_material;
|
struct std_string warmth_melts_to_material;
|
||||||
int warmth_melts_to_material_id;
|
int warmth_melts_to_material_id;
|
||||||
int cold_freezes_to_material_id;
|
int cold_freezes_to_material_id;
|
||||||
int16_t cold_freezes_chance_rev;
|
int16_t cold_freezes_chance_rev;
|
||||||
int16_t warmth_melts_chance_rev;
|
int16_t warmth_melts_chance_rev;
|
||||||
bool cold_freezes_to_dont_do_reverse_reaction;
|
bool cold_freezes_to_dont_do_reverse_reaction;
|
||||||
char padding3[3];
|
char padding3[3];
|
||||||
int lifetime;
|
int lifetime;
|
||||||
int hp;
|
int hp;
|
||||||
float density;
|
float density;
|
||||||
bool liquid_sand;
|
bool liquid_sand;
|
||||||
bool liquid_slime;
|
bool liquid_slime;
|
||||||
bool liquid_static;
|
bool liquid_static;
|
||||||
bool liquid_stains_self;
|
bool liquid_stains_self;
|
||||||
int liquid_sticks_to_ceiling;
|
int liquid_sticks_to_ceiling;
|
||||||
float liquid_gravity;
|
float liquid_gravity;
|
||||||
int liquid_viscosity;
|
int liquid_viscosity;
|
||||||
int liquid_stains;
|
int liquid_stains;
|
||||||
unsigned int liquid_stains_custom_color;
|
unsigned int liquid_stains_custom_color;
|
||||||
float liquid_sprite_stain_shaken_drop_chance;
|
float liquid_sprite_stain_shaken_drop_chance;
|
||||||
float liquid_sprite_stain_ignited_drop_chance;
|
float liquid_sprite_stain_ignited_drop_chance;
|
||||||
int8_t liquid_sprite_stains_check_offset;
|
int8_t liquid_sprite_stains_check_offset;
|
||||||
char padding4[3];
|
char padding4[3];
|
||||||
float liquid_sprite_stains_status_threshold;
|
float liquid_sprite_stains_status_threshold;
|
||||||
float liquid_damping;
|
float liquid_damping;
|
||||||
float liquid_flow_speed;
|
float liquid_flow_speed;
|
||||||
bool liquid_sand_never_box2d;
|
bool liquid_sand_never_box2d;
|
||||||
char unknown7[3];
|
char unknown7[3];
|
||||||
int8_t gas_speed;
|
int8_t gas_speed;
|
||||||
int8_t gas_upwards_speed;
|
int8_t gas_upwards_speed;
|
||||||
int8_t gas_horizontal_speed;
|
int8_t gas_horizontal_speed;
|
||||||
int8_t gas_downwards_speed;
|
int8_t gas_downwards_speed;
|
||||||
float solid_friction;
|
float solid_friction;
|
||||||
float solid_restitution;
|
float solid_restitution;
|
||||||
float solid_gravity_scale;
|
float solid_gravity_scale;
|
||||||
int solid_static_type;
|
int solid_static_type;
|
||||||
float solid_on_collision_splash_power;
|
float solid_on_collision_splash_power;
|
||||||
bool solid_on_collision_explode;
|
bool solid_on_collision_explode;
|
||||||
bool solid_on_sleep_convert;
|
bool solid_on_sleep_convert;
|
||||||
bool solid_on_collision_convert;
|
bool solid_on_collision_convert;
|
||||||
bool solid_on_break_explode;
|
bool solid_on_break_explode;
|
||||||
bool solid_go_through_sand;
|
bool solid_go_through_sand;
|
||||||
bool solid_collide_with_self;
|
bool solid_collide_with_self;
|
||||||
char padding5[2];
|
char padding5[2];
|
||||||
struct std_string solid_on_collision_material;
|
struct std_string solid_on_collision_material;
|
||||||
int solid_on_collision_material_id;
|
int solid_on_collision_material_id;
|
||||||
struct std_string solid_break_to_type;
|
struct std_string solid_break_to_type;
|
||||||
int solid_break_to_type_id;
|
int solid_break_to_type_id;
|
||||||
struct std_string convert_to_box2d_material;
|
struct std_string convert_to_box2d_material;
|
||||||
int convert_to_box2d_material_id;
|
int convert_to_box2d_material_id;
|
||||||
int vegetation_full_lifetime_growth;
|
int vegetation_full_lifetime_growth;
|
||||||
struct std_string vegetation_sprite;
|
struct std_string vegetation_sprite;
|
||||||
bool vegetation_random_flip_x_scale;
|
bool vegetation_random_flip_x_scale;
|
||||||
char padding6[3];
|
char padding6[3];
|
||||||
char unknown11[12];
|
char unknown11[12];
|
||||||
float wang_noise_percent;
|
float wang_noise_percent;
|
||||||
float wang_curvature;
|
float wang_curvature;
|
||||||
int wang_noise_type;
|
int wang_noise_type;
|
||||||
char unknown12[12];
|
char unknown12[12];
|
||||||
bool danger_fire;
|
bool danger_fire;
|
||||||
bool danger_radioactive;
|
bool danger_radioactive;
|
||||||
bool danger_poison;
|
bool danger_poison;
|
||||||
bool danger_water;
|
bool danger_water;
|
||||||
char unknown13[24];
|
char unknown13[24];
|
||||||
bool always_ignites_damagemodel;
|
bool always_ignites_damagemodel;
|
||||||
bool ignore_self_reaction_warning;
|
bool ignore_self_reaction_warning;
|
||||||
char padding7[2];
|
char padding7[2];
|
||||||
char unknown14[12];
|
char unknown14[12];
|
||||||
float audio_size_multiplier;
|
float audio_size_multiplier;
|
||||||
bool audio_is_soft;
|
bool audio_is_soft;
|
||||||
char padding8[3];
|
char padding8[3];
|
||||||
char unknown15[8];
|
char unknown15[8];
|
||||||
bool show_in_creative_mode;
|
bool show_in_creative_mode;
|
||||||
bool is_just_particle_fx;
|
bool is_just_particle_fx;
|
||||||
char padding9[2];
|
char padding9[2];
|
||||||
// struct grid_CosmeticParticleConfig *ParticleEffect;
|
// struct grid_CosmeticParticleConfig *ParticleEffect;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum CellType {
|
enum CellType {
|
||||||
CELL_TYPE_NONE = 0,
|
CELL_TYPE_NONE = 0,
|
||||||
CELL_TYPE_LIQUID = 1,
|
CELL_TYPE_LIQUID = 1,
|
||||||
CELL_TYPE_GAS = 2,
|
CELL_TYPE_GAS = 2,
|
||||||
CELL_TYPE_SOLID = 3,
|
CELL_TYPE_SOLID = 3,
|
||||||
CELL_TYPE_FIRE = 4,
|
CELL_TYPE_FIRE = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Cell_vtable {
|
struct Cell_vtable {
|
||||||
void (__thiscall *destroy)(struct Cell*, char dealloc);
|
void (__thiscall *destroy)(struct Cell*, char dealloc);
|
||||||
enum CellType (__thiscall *get_cell_type)(struct Cell*);
|
enum CellType (__thiscall *get_cell_type)(struct Cell*);
|
||||||
void* field2_0x8;
|
void* field2_0x8;
|
||||||
void* field3_0xc;
|
void* field3_0xc;
|
||||||
void* field4_0x10;
|
void* field4_0x10;
|
||||||
struct Colour (__thiscall *get_colour)(struct Cell*);
|
struct Colour (__thiscall *get_colour)(struct Cell*);
|
||||||
void* field6_0x18;
|
void* field6_0x18;
|
||||||
void (__thiscall *set_colour)(struct Cell*, struct Colour);
|
void (__thiscall *set_colour)(struct Cell*, struct Colour);
|
||||||
void* field8_0x20;
|
void* field8_0x20;
|
||||||
void* field9_0x24;
|
void* field9_0x24;
|
||||||
void* field10_0x28;
|
void* field10_0x28;
|
||||||
void* field11_0x2c;
|
void* field11_0x2c;
|
||||||
struct CellData* (__thiscall *get_material)(void *);
|
struct CellData* (__thiscall *get_material)(void *);
|
||||||
void* field13_0x34;
|
void* field13_0x34;
|
||||||
void* field14_0x38;
|
void* field14_0x38;
|
||||||
void* field15_0x3c;
|
void* field15_0x3c;
|
||||||
void* field16_0x40;
|
void* field16_0x40;
|
||||||
void* field17_0x44;
|
void* field17_0x44;
|
||||||
void* field18_0x48;
|
void* field18_0x48;
|
||||||
void* field19_0x4c;
|
void* field19_0x4c;
|
||||||
struct Position * (__thiscall *get_position)(void *, struct Position *);
|
struct Position * (__thiscall *get_position)(void *, struct Position *);
|
||||||
void* field21_0x54;
|
void* field21_0x54;
|
||||||
void* field22_0x58;
|
void* field22_0x58;
|
||||||
void* field23_0x5c;
|
void* field23_0x5c;
|
||||||
void* field24_0x60;
|
void* field24_0x60;
|
||||||
void* field25_0x64;
|
void* field25_0x64;
|
||||||
void* field26_0x68;
|
void* field26_0x68;
|
||||||
void* field27_0x6c;
|
void* field27_0x6c;
|
||||||
void* field28_0x70;
|
void* field28_0x70;
|
||||||
bool (__thiscall *is_burning)(struct Cell*);
|
bool (__thiscall *is_burning)(struct Cell*);
|
||||||
void* field30_0x78;
|
void* field30_0x78;
|
||||||
void* field31_0x7c;
|
void* field31_0x7c;
|
||||||
void* field32_0x80;
|
void* field32_0x80;
|
||||||
void (__thiscall *stop_burning)(struct Cell*);
|
void (__thiscall *stop_burning)(struct Cell*);
|
||||||
void* field34_0x88;
|
void* field34_0x88;
|
||||||
void* field35_0x8c;
|
void* field35_0x8c;
|
||||||
void* field36_0x90;
|
void* field36_0x90;
|
||||||
void* field37_0x94;
|
void* field37_0x94;
|
||||||
void* field38_0x98;
|
void* field38_0x98;
|
||||||
void (__thiscall *remove)(struct Cell*);
|
void (__thiscall *remove)(struct Cell*);
|
||||||
void* field40_0xa0;
|
void* field40_0xa0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// In the Noita code this would be the ICellBurnable class
|
// In the Noita code this would be the ICellBurnable class
|
||||||
struct Cell {
|
struct Cell {
|
||||||
struct Cell_vtable* vtable;
|
struct Cell_vtable* vtable;
|
||||||
|
|
||||||
int hp;
|
int hp;
|
||||||
char unknown1[8];
|
char unknown1[8];
|
||||||
bool is_burning;
|
bool is_burning;
|
||||||
char unknown2[3];
|
char unknown2[3];
|
||||||
uintptr_t material_ptr;
|
uintptr_t material_ptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CLiquidCell {
|
struct CLiquidCell {
|
||||||
struct Cell cell;
|
struct Cell cell;
|
||||||
int x;
|
int x;
|
||||||
int y;
|
int y;
|
||||||
char unknown1;
|
char unknown1;
|
||||||
char unknown2;
|
char unknown2;
|
||||||
bool is_static;
|
bool is_static;
|
||||||
char unknown3;
|
char unknown3;
|
||||||
int unknown4[3];
|
int unknown4[3];
|
||||||
struct Colour colour;
|
struct Colour colour;
|
||||||
unsigned not_colour;
|
unsigned not_colour;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct Cell (*cell_array)[0x40000];
|
typedef struct Cell (*cell_array)[0x40000];
|
||||||
|
|
||||||
struct ChunkMap {
|
struct ChunkMap {
|
||||||
int unknown[2];
|
int unknown[2];
|
||||||
cell_array* (*cells)[0x40000];
|
cell_array* (*cells)[0x40000];
|
||||||
int unknown2[8];
|
int unknown2[8];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GridWorld_vtable {
|
struct GridWorld_vtable {
|
||||||
placeholder_memfn* unknown[3];
|
placeholder_memfn* unknown[3];
|
||||||
struct ChunkMap* (__thiscall *get_chunk_map)(struct GridWorld* this);
|
struct ChunkMap* (__thiscall *get_chunk_map)(struct GridWorld* this);
|
||||||
placeholder_memfn* unknown2[30];
|
placeholder_memfn* unknown2[30];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GridWorld {
|
struct GridWorld {
|
||||||
struct GridWorld_vtable* vtable;
|
struct GridWorld_vtable* vtable;
|
||||||
int unknown[318];
|
int unknown[318];
|
||||||
int world_update_count;
|
int world_update_count;
|
||||||
struct ChunkMap chunk_map;
|
struct ChunkMap chunk_map;
|
||||||
int unknown2[41];
|
int unknown2[41];
|
||||||
struct GridWorldThreadImpl* mThreadImpl;
|
struct GridWorldThreadImpl* mThreadImpl;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GridWorldThreaded_vtable;
|
struct GridWorldThreaded_vtable;
|
||||||
|
|
||||||
struct GridWorldThreaded {
|
struct GridWorldThreaded {
|
||||||
struct GridWorldThreaded_vtable* vtable;
|
struct GridWorldThreaded_vtable* vtable;
|
||||||
int unknown[287];
|
int unknown[287];
|
||||||
struct AABB update_region;
|
struct AABB update_region;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct vec_pGridWorldThreaded {
|
struct vec_pGridWorldThreaded {
|
||||||
struct GridWorldThreaded** begin;
|
struct GridWorldThreaded** begin;
|
||||||
struct GridWorldThreaded** end_;
|
struct GridWorldThreaded** end_;
|
||||||
struct GridWorldThreaded** capacity_end;
|
struct GridWorldThreaded** capacity_end;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WorldUpdateParams {
|
struct WorldUpdateParams {
|
||||||
struct AABB update_region;
|
struct AABB update_region;
|
||||||
int unknown;
|
int unknown;
|
||||||
struct GridWorldThreaded* grid_world_threaded;
|
struct GridWorldThreaded* grid_world_threaded;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct vec_WorldUpdateParams {
|
struct vec_WorldUpdateParams {
|
||||||
struct WorldUpdateParams* begin;
|
struct WorldUpdateParams* begin;
|
||||||
struct WorldUpdateParams* end_;
|
struct WorldUpdateParams* end_;
|
||||||
struct WorldUpdateParams* capacity_end;
|
struct WorldUpdateParams* capacity_end;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GridWorldThreadImpl {
|
struct GridWorldThreadImpl {
|
||||||
int chunk_update_count;
|
int chunk_update_count;
|
||||||
struct vec_pGridWorldThreaded updated_grid_worlds;
|
struct vec_pGridWorldThreaded updated_grid_worlds;
|
||||||
|
|
||||||
int world_update_params_count;
|
int world_update_params_count;
|
||||||
struct vec_WorldUpdateParams world_update_params;
|
struct vec_WorldUpdateParams world_update_params;
|
||||||
|
|
||||||
int grid_with_area_count;
|
int grid_with_area_count;
|
||||||
struct vec_pGridWorldThreaded with_area_grid_worlds;
|
struct vec_pGridWorldThreaded with_area_grid_worlds;
|
||||||
|
|
||||||
int another_count;
|
int another_count;
|
||||||
int another_vec[3];
|
int another_vec[3];
|
||||||
|
|
||||||
int some_kind_of_ptr;
|
int some_kind_of_ptr;
|
||||||
int some_kind_of_counter;
|
int some_kind_of_counter;
|
||||||
|
|
||||||
int last_vec[3];
|
int last_vec[3];
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct Cell** __thiscall get_cell_f(struct ChunkMap*, int x, int y);
|
typedef struct Cell** __thiscall get_cell_f(struct ChunkMap*, int x, int y);
|
||||||
typedef bool __thiscall chunk_loaded_f(struct ChunkMap*, int x, int y);
|
typedef bool __thiscall chunk_loaded_f(struct ChunkMap*, int x, int y);
|
||||||
|
|
||||||
typedef void __thiscall remove_cell_f(struct GridWorld*, void* cell, int x, int y, bool);
|
typedef void __thiscall remove_cell_f(struct GridWorld*, void* cell, int x, int y, bool);
|
||||||
typedef struct Cell* __thiscall construct_cell_f(struct GridWorld*, int x, int y, void* material_ptr, void* memory);
|
typedef struct Cell* __thiscall construct_cell_f(struct GridWorld*, int x, int y, void* material_ptr, void* memory);
|
||||||
|
|
||||||
]])
|
]])
|
||||||
|
|
||||||
--local function check_celldata_field(f, o)
|
--local function check_celldata_field(f, o)
|
||||||
-- local offset = ffi.offsetof("struct CellData", f)
|
-- local offset = ffi.offsetof("struct CellData", f)
|
||||||
-- assert(offset == o, "Expected field " .. f .. " to be at offset " .. o)
|
-- assert(offset == o, "Expected field " .. f .. " to be at offset " .. o)
|
||||||
--end
|
--end
|
||||||
--
|
--
|
||||||
--check_celldata_field("wang_color", 0x40)
|
--check_celldata_field("wang_color", 0x40)
|
||||||
--check_celldata_field("generates_flames", 0xa4)
|
--check_celldata_field("generates_flames", 0xa4)
|
||||||
--check_celldata_field("durability", 0x104)
|
--check_celldata_field("durability", 0x104)
|
||||||
--check_celldata_field("cold_freezes_to_material", 0x114)
|
--check_celldata_field("cold_freezes_to_material", 0x114)
|
||||||
--check_celldata_field("liquid_sand", 0x160)
|
--check_celldata_field("liquid_sand", 0x160)
|
||||||
--check_celldata_field("liquid_sprite_stain_ignited_drop_chance", 0x17c)
|
--check_celldata_field("liquid_sprite_stain_ignited_drop_chance", 0x17c)
|
||||||
--check_celldata_field("gas_horizontal_speed", 0x196)
|
--check_celldata_field("gas_horizontal_speed", 0x196)
|
||||||
--check_celldata_field("solid_on_sleep_convert", 0x1ad)
|
--check_celldata_field("solid_on_sleep_convert", 0x1ad)
|
||||||
--check_celldata_field("solid_break_to_type", 0x1d0)
|
--check_celldata_field("solid_break_to_type", 0x1d0)
|
||||||
--check_celldata_field("vegetation_sprite", 0x20c)
|
--check_celldata_field("vegetation_sprite", 0x20c)
|
||||||
--check_celldata_field("wang_noise_type", 0x23c)
|
--check_celldata_field("wang_noise_type", 0x23c)
|
||||||
--check_celldata_field("ignore_self_reaction_warning", 0x269)
|
--check_celldata_field("ignore_self_reaction_warning", 0x269)
|
||||||
--check_celldata_field("is_just_particle_fx", 0x289)
|
--check_celldata_field("is_just_particle_fx", 0x289)
|
||||||
|
|
||||||
---@class ChunkMap pointer type
|
---@class ChunkMap pointer type
|
||||||
---@class GridWorld pointer type
|
---@class GridWorld pointer type
|
||||||
---@class CellData pointer type
|
---@class CellData pointer type
|
||||||
---@class Cell pointer type
|
---@class Cell pointer type
|
||||||
|
|
||||||
---Access a pixel in the world.
|
---Access a pixel in the world.
|
||||||
---You can write a cell created from world_ffi.construct_cell to this pointer to add a cell into the world.
|
---You can write a cell created from world_ffi.construct_cell to this pointer to add a cell into the world.
|
||||||
---If there's already a cell at this position, make sure to call world_ffi.remove_cell first.
|
---If there's already a cell at this position, make sure to call world_ffi.remove_cell first.
|
||||||
---@type fun(chunk_map: ChunkMap, x: integer, y: integer): Cell
|
---@type fun(chunk_map: ChunkMap, x: integer, y: integer): Cell
|
||||||
world_ffi.get_cell = ffi.cast("get_cell_f*", world_info.get_cell)
|
world_ffi.get_cell = ffi.cast("get_cell_f*", world_info.get_cell)
|
||||||
|
|
||||||
---Remove a cell from the world. bool return has unknown meaning.
|
---Remove a cell from the world. bool return has unknown meaning.
|
||||||
---@type fun(grid_world: GridWorld, cell: Cell, x: integer, y: integer): boolean
|
---@type fun(grid_world: GridWorld, cell: Cell, x: integer, y: integer): boolean
|
||||||
world_ffi.remove_cell = ffi.cast("remove_cell_f*", world_info.remove_cell)
|
world_ffi.remove_cell = ffi.cast("remove_cell_f*", world_info.remove_cell)
|
||||||
|
|
||||||
---Create a new cell. If memory is null pointer it will allocate its own memory.
|
---Create a new cell. If memory is null pointer it will allocate its own memory.
|
||||||
---@type fun(grid_world: GridWorld, x: integer, y: integer, material: CellData, memory: ffi.cdata*)
|
---@type fun(grid_world: GridWorld, x: integer, y: integer, material: CellData, memory: ffi.cdata*)
|
||||||
world_ffi.construct_cell = ffi.cast("construct_cell_f*", world_info.construct_cell)
|
world_ffi.construct_cell = ffi.cast("construct_cell_f*", world_info.construct_cell)
|
||||||
|
|
||||||
---Check if a chunk is loaded. x and y are world coordinates.
|
---Check if a chunk is loaded. x and y are world coordinates.
|
||||||
---```lua
|
---```lua
|
||||||
---if world_ffi.chunk_loaded(chunk_map, x, y) then
|
---if world_ffi.chunk_loaded(chunk_map, x, y) then
|
||||||
--- local cell = world_ffi.get_cell(chunk_map, x, y)
|
--- local cell = world_ffi.get_cell(chunk_map, x, y)
|
||||||
--- ..
|
--- ..
|
||||||
---```
|
---```
|
||||||
---@type fun(chunk_map: ChunkMap, x: integer, y: integer): boolean
|
---@type fun(chunk_map: ChunkMap, x: integer, y: integer): boolean
|
||||||
world_ffi.chunk_loaded = ffi.cast("chunk_loaded_f*", world_info.chunk_loaded)
|
world_ffi.chunk_loaded = ffi.cast("chunk_loaded_f*", world_info.chunk_loaded)
|
||||||
|
|
||||||
world_ffi.Position = ffi.typeof("struct Position")
|
world_ffi.Position = ffi.typeof("struct Position")
|
||||||
world_ffi.Colour = ffi.typeof("struct Colour")
|
world_ffi.Colour = ffi.typeof("struct Colour")
|
||||||
world_ffi.AABB = ffi.typeof("struct AABB")
|
world_ffi.AABB = ffi.typeof("struct AABB")
|
||||||
world_ffi.CellType = ffi.typeof("enum CellType")
|
world_ffi.CellType = ffi.typeof("enum CellType")
|
||||||
world_ffi.Cell = ffi.typeof("struct Cell")
|
world_ffi.Cell = ffi.typeof("struct Cell")
|
||||||
world_ffi.CLiquidCell = ffi.typeof("struct CLiquidCell")
|
world_ffi.CLiquidCell = ffi.typeof("struct CLiquidCell")
|
||||||
world_ffi.ChunkMap = ffi.typeof("struct ChunkMap")
|
world_ffi.ChunkMap = ffi.typeof("struct ChunkMap")
|
||||||
world_ffi.GridWorld = ffi.typeof("struct GridWorld")
|
world_ffi.GridWorld = ffi.typeof("struct GridWorld")
|
||||||
world_ffi.GridWorldThreaded = ffi.typeof("struct GridWorldThreaded")
|
world_ffi.GridWorldThreaded = ffi.typeof("struct GridWorldThreaded")
|
||||||
world_ffi.WorldUpdateParams = ffi.typeof("struct WorldUpdateParams")
|
world_ffi.WorldUpdateParams = ffi.typeof("struct WorldUpdateParams")
|
||||||
world_ffi.GridWorldThreadImpl = ffi.typeof("struct GridWorldThreadImpl")
|
world_ffi.GridWorldThreadImpl = ffi.typeof("struct GridWorldThreadImpl")
|
||||||
|
|
||||||
---Get the grid world.
|
---Get the grid world.
|
||||||
---@return GridWorld
|
---@return GridWorld
|
||||||
function world_ffi.get_grid_world()
|
function world_ffi.get_grid_world()
|
||||||
local game_global = ffi.cast("void*", gg_ptr)
|
local game_global = ffi.cast("void*", gg_ptr)
|
||||||
local world_data = ffi.cast("void**", ffi.cast("char*", game_global) + 0xc)[0]
|
local world_data = ffi.cast("void**", ffi.cast("char*", game_global) + 0xc)[0]
|
||||||
local grid_world = ffi.cast("struct GridWorld**", ffi.cast("char*", world_data) + 0x44)[0]
|
local grid_world = ffi.cast("struct GridWorld**", ffi.cast("char*", world_data) + 0x44)[0]
|
||||||
return grid_world
|
return grid_world
|
||||||
end
|
end
|
||||||
|
|
||||||
local celldata_size = 0x290
|
local celldata_size = 0x290
|
||||||
local CellData_ptr = ffi.typeof("struct CellData*")
|
local CellData_ptr = ffi.typeof("struct CellData*")
|
||||||
|
|
||||||
---Turn a standard material id into a material pointer.
|
---Turn a standard material id into a material pointer.
|
||||||
---@param id integer material id that is used in the standard Noita functions
|
---@param id integer material id that is used in the standard Noita functions
|
||||||
---@return CellData material to internal material data (aka cell data).
|
---@return CellData material to internal material data (aka cell data).
|
||||||
---```lua
|
---```lua
|
||||||
---local gold_ptr = world_ffi.get_material_ptr(CellFactory_GetType("gold"))
|
---local gold_ptr = world_ffi.get_material_ptr(CellFactory_GetType("gold"))
|
||||||
---```
|
---```
|
||||||
function world_ffi.get_material_ptr(id)
|
function world_ffi.get_material_ptr(id)
|
||||||
local game_global = ffi.cast("char*", gg_ptr)
|
local game_global = ffi.cast("char*", gg_ptr)
|
||||||
local cell_factory = ffi.cast('char**', (game_global + 0x18))[0]
|
local cell_factory = ffi.cast("char**", (game_global + 0x18))[0]
|
||||||
local begin = ffi.cast('char**', cell_factory + 0x18)[0]
|
local begin = ffi.cast("char**", cell_factory + 0x18)[0]
|
||||||
local ptr = begin + celldata_size * id
|
local ptr = begin + celldata_size * id
|
||||||
return ffi.cast(CellData_ptr, ptr) --[[@as CellData]]
|
return ffi.cast(CellData_ptr, ptr) --[[@as CellData]]
|
||||||
end
|
end
|
||||||
|
|
||||||
---Turn a material pointer into a standard material id.
|
---Turn a material pointer into a standard material id.
|
||||||
---@param material CellData to a material (aka cell data)
|
---@param material CellData to a material (aka cell data)
|
||||||
---@return integer material id that is accepted by standard Noita functions such as `CellFactory_GetUIName` and `ConvertMaterialOnAreaInstantly`.
|
---@return integer material id that is accepted by standard Noita functions such as `CellFactory_GetUIName` and `ConvertMaterialOnAreaInstantly`.
|
||||||
---```lua
|
---```lua
|
||||||
---local mat_id = world_ffi.get_material_id(cell.vtable.get_material(cell))
|
---local mat_id = world_ffi.get_material_id(cell.vtable.get_material(cell))
|
||||||
---```
|
---```
|
||||||
---See: `world_ffi.get_material_ptr`
|
---See: `world_ffi.get_material_ptr`
|
||||||
function world_ffi.get_material_id(material)
|
function world_ffi.get_material_id(material)
|
||||||
local game_global = ffi.cast("char*", gg_ptr)
|
local game_global = ffi.cast("char*", gg_ptr)
|
||||||
local cell_factory = ffi.cast('char**', (game_global + 0x18))[0]
|
local cell_factory = ffi.cast("char**", (game_global + 0x18))[0]
|
||||||
local begin = ffi.cast('char**', cell_factory + 0x18)[0]
|
local begin = ffi.cast("char**", cell_factory + 0x18)[0]
|
||||||
local offset = ffi.cast('char*', material) - begin
|
local offset = ffi.cast("char*", material) - begin
|
||||||
return offset / celldata_size
|
return offset / celldata_size
|
||||||
end
|
end
|
||||||
|
|
||||||
return world_ffi
|
return world_ffi
|
||||||
|
|
|
@ -911,4 +911,4 @@ function rpc.replicate_projectile(seri_ent, position_x, position_y, target_x, ta
|
||||||
GameShootProjectile(source_ent, position_x, position_y, target_x, target_y, ent)
|
GameShootProjectile(source_ent, position_x, position_y, target_x, target_y, ent)
|
||||||
end
|
end
|
||||||
|
|
||||||
return enemy_sync
|
return enemy_sync
|
||||||
|
|
|
@ -862,4 +862,4 @@ ctx.cap.item_sync = {
|
||||||
|
|
||||||
item_sync.rpc = rpc
|
item_sync.rpc = rpc
|
||||||
|
|
||||||
return item_sync
|
return item_sync
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
local rpc = net.new_rpc_namespace()
|
local rpc = net.new_rpc_namespace()
|
||||||
local tele = {}
|
local tele = {}
|
||||||
local who_has_tele = {}
|
local who_has_tele = {}
|
||||||
|
local is_holding
|
||||||
|
|
||||||
rpc.opts_reliable()
|
rpc.opts_reliable()
|
||||||
function rpc.end_tele()
|
function rpc.end_tele()
|
||||||
|
@ -29,6 +30,12 @@ function rpc.send_tele(body_gid, n, extent, aimangle, bodyangle, distance, mindi
|
||||||
if not table.contains(who_has_tele, ctx.rpc_peer_id) then
|
if not table.contains(who_has_tele, ctx.rpc_peer_id) then
|
||||||
table.insert(who_has_tele, ctx.rpc_peer_id)
|
table.insert(who_has_tele, ctx.rpc_peer_id)
|
||||||
ComponentSetValue2(com, "mState", 1)
|
ComponentSetValue2(com, "mState", 1)
|
||||||
|
if is_holding == ent then
|
||||||
|
local mycom = EntityGetFirstComponent(ctx.my_player.entity, "TelekinesisComponent")
|
||||||
|
if mycom ~= nil then
|
||||||
|
ComponentSetValue2(mycom, "mState", 0)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
ComponentSetValue(com, "mBodyID", body_id)
|
ComponentSetValue(com, "mBodyID", body_id)
|
||||||
ComponentSetValue2(com, "mStartBodyMaxExtent", extent)
|
ComponentSetValue2(com, "mStartBodyMaxExtent", extent)
|
||||||
|
@ -92,6 +99,7 @@ function tele.on_world_update()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if gid ~= nil then
|
if gid ~= nil then
|
||||||
|
is_holding = ent
|
||||||
has_tele = true
|
has_tele = true
|
||||||
rpc.send_tele(
|
rpc.send_tele(
|
||||||
ComponentGetValue2(gid, "value_string"),
|
ComponentGetValue2(gid, "value_string"),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue