progress on custom entities

This commit is contained in:
ZXMushroom63 2025-01-25 17:26:41 +08:00
parent c8664c7a5b
commit 9555af5b1a
4 changed files with 91 additions and 11 deletions

View File

@ -1,8 +1,10 @@
## ModAPI.keygen
ModAPI.keygen contains the API for getting item and block IDs from a string. It looks at the registries for items and blocks to derive the IDs, so IDs will not be automatically reserved until a block/item is actually registered. Ideally, you'd want to call a keygen method just before registering your block.
ModAPI.keygen contains the API for getting numerical item, block and entity IDs from a string. It looks at registries to derive the IDs, so IDs will not be automatically reserved until a block/item is actually registered into the game. Ideally, you'd want to call a keygen method just before registering your block.
Methods:
- `ModAPI.keygen.item(itemId: String) : number`
- Example usage is: `var id = ModAPI.keygen.item("my_example_item");`
- `ModAPI.keygen.block(blockId: String) : number`
- Example usage is: `var id = ModAPI.keygen.block("my_example_block");`
- Example usage is: `var id = ModAPI.keygen.block("my_example_block");`
- `ModAPI.keygen.entity(entityId: String) : number`
- Example usage is: `var id = ModAPI.keygen.entity("my_example_entity");`

View File

@ -16,9 +16,10 @@ Methods:
- This method is used to find a class by its id.
- For example, to get the `Minecraft` class, you can use `ModAPI.reflect.getClassById("Minecraft")`
- This runs slower than `getClassById` because it has to filter through all classes. Make sure to cache the result rather than calling it over and over again.
- `ModAPI.reflect.getSuper(rClass: ReflectClass, filter: Function) : Function`
- `ModAPI.reflect.getSuper(rClass: ReflectClass, filter: Function?) : Function`
- Gets a super function from a reflect class. This is used to extend built in classes, like `Block`.
- For an example, see lines [29](https://github.com/eaglerforge/EaglerForgeInjector/blob/6e8598c180f96a65c0c101be72e6d0fa53195404/examplemods/unlucky_blocks.js#L29) and [33](https://github.com/eaglerforge/EaglerForgeInjector/blob/6e8598c180f96a65c0c101be72e6d0fa53195404/examplemods/unlucky_blocks.js#L33) in unlucky_blocks.js
- For an example, see lines [29](https://github.com/eaglerforge/EaglerForgeInjector/blob/6e8598c180f96a65c0c101be72e6d0fa53195404/examplemods/unlucky_blocks.js#L29) and [33](https://github.com/eaglerforge/EaglerForgeInjector/blob/6e8598c180f96a65c0c101be72e6d0fa53195404/examplemods/unlucky_blocks.js#L33) in `unlucky_blocks.js`
- When called without a filter function, the filter defaults to `(fn)=>fn.length === 1`
- `ModAPI.reflect.prototypeStack(rClass: ReflectClass, target: Class/ConstructorFunction) : void`
- Copies methods from a reflect class and it's parents onto a target native JavaScript class. This allows TeaVM to use these objects normally, without you having to manually reimplement every method. In other words, this is the equivalent of extending a class.
- [Example usage](https://github.com/eaglerforge/EaglerForgeInjector/blob/6e8598c180f96a65c0c101be72e6d0fa53195404/examplemods/unlucky_blocks.js#L37)

View File

@ -5,12 +5,87 @@
ModAPI.meta.credits("By ZXMushroom64");
function registerEntity() {
// Utils
const ResourceLocation = ModAPI.reflect.getClassByName("ResourceLocation").constructors.find(x=>x.length===1);
const GlStateManager = Object.fromEntries(Object.values(ModAPI.reflect.getClassByName("GlStateManager").staticMethods).map(x=>[x.methodNameShort, x.method]));
// START CUSTOM ENTITY
var entityClass = ModAPI.reflect.getClassById("net.minecraft.entity.Entity");
var entitySuper = ModAPI.reflect.getSuper(entityClass, (x) => x.length === 2);
var nme_EntityCube = function nme_EntityCube($worldIn) {
entitySuper(this, $worldIn);
this.$setCreativeTab(creativeMiscTab);
this.$preventEntitySpawning = 1;
this.$setSize(1, 1);
}
ModAPI.reflect.prototypeStack(entityClass, nme_EntityCube);
nme_EntityCube.prototype.$canTriggerWalking = function () { return 0 };
nme_EntityCube.prototype.$canBePushed = function () { return 0 };
nme_EntityCube.prototype.$getCollisionBox = function () { return this.$getEntityBoundingBox() };
nme_EntityCube.prototype.$getCollisionBoundingBox = function () { return this.$getEntityBoundingBox() };
// END CUSTOM ENTITY
// START CUSTOM MODEL
var ModelRenderer = ModAPI.reflect.getClassById("net.minecraft.client.model.ModelRenderer").constructors.find(x => x.length === 1);
var modelBaseClass = ModAPI.reflect.getClassById("net.minecraft.client.model.ModelBase");
var modelBaseSuper = ModAPI.reflect.getSuper(entityClass); //while super isn't used when extending this class, java implies the call.
var nmcm_ModelCube = function nmcm_ModelCube() {
modelBaseSuper(this);
this.$textureWidth = 64;
this.$textureHeight = 64;
this.$cubeRenderer = ModelRenderer(this).$setTextureOffset(0, 0);
this.$cubeRenderer.$addBox0(0, 0, 0, 1, 1, 1);
this.$cubeRenderer.$setRotationPoint(0, 0, 0);
}
ModAPI.reflect.prototypeStack(modelBaseClass, nmcm_ModelCube);
nmcm_ModelCube.prototype.$render = function ($entity, useless1, useless2, partialTicks, useless3, useless4, f) {
this.$cubeRenderer.$render(f);
}
// END CUSTOM MODEL
// START CUSTOM RENDERER
var renderClass = ModAPI.reflect.getClassById("net.minecraft.client.renderer.entity.Render");
var renderSuper = ModAPI.reflect.getSuper(entityClass, (x)=>x.length === 2);
const cubeTextures = ResourceLocation(ModAPI.util.str("textures/entity/cube.png"));
var nmcre_RenderCube = function nmcre_RenderCube(renderManager) {
renderSuper(this, renderManager);
this.$modelCube = new nmcm_ModelCube();
this.$shadowSize = 0.5;
}
ModAPI.reflect.prototypeStack(renderClass, nmcre_RenderCube);
nmcre_RenderCube.prototype.$getEntityTexture = function (entity) {
return cubeTextures;
}
const parentDoRender = nmcre_RenderCube.prototype.$doRender;
nmcre_RenderCube.prototype.$doRender = function (entity, x, y, z, yaw, pitch) {
GlStateManager.pushMatrix();
GlStateManager.translate(x, y + 0.25, z);
GlStateManager.rotate(180 - yaw, 0, 1, 0);
this.$bindEntityTexture(entity);
this.$modelCube.$render(entity, 0, 0, -0.1, 0, 0, 0.0625);
GlStateManager.popMatrix();
parentDoRender.apply(this, [entity, x, y, z, yaw, pitch]);
}
ModAPI.reflect.getClassById("net.minecraft.entity.EntityList").staticMethods.addMapping0(
ModAPI.util.asClass(nme_EntityCube),
{
$createEntity: nme_EntityCube
},
ModAPI.util.str("Cube"),
ModAPI.keygen.entity("cube"),
0x000000, //egg base
0x00FF00 //egg spots
);
ModAPI.mc.renderManager.entityRenderMap.put(ModAPI.util.asClass(nme_EntityCube), new nmcre_RenderCube(ModAPI.mc.renderManager.getRef()));
return {
EntityCube: null,
ModelCube: null,
RenderCube: null
EntityCube: nme_EntityCube,
ModelCube: nmcm_ModelCube,
RenderCube: nmcre_RenderCube,
cubeTexture: cubeTextures
}
}
@ -18,7 +93,9 @@
var data = registerEntity();
ModAPI.addEventListener("lib:asyncsink", async () => {
//ModAPI.mc.renderManager.entityRenderMap.put(ModAPI.util.asClass(wellGetThere), new data.RenderCube(ModAPI.mc.renderManager.getRef()))
AsyncSink.L10N.set("entity.Cube.name", "Cube (TM)");
AsyncSink.setFile("resourcepacks/AsyncSinkLib/assets/minecraft/textures/entity/cube.png", await (await fetch(
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAAAQBJREFUeF7l0BFzAmAAgOGvKxgMgiAYDIJgEARBEASDQTAIgiAYBEEQBN0NBkEQBEEQBIMgCAZBEAwGgyAIgiAIgiConxE88PJ790RCCNdYCOGeRe/4j4SYDvCgAzzqAHEdIKEDJHWAJx3gWQdI6QBpHeBFB8joAFkdIKcD5HWAgg5Q1AFedYA3HaCkA7zrAGUdoKIDVHWAmg7woQPUdYCGDtDUAVo6QFsH6OgAnzrAlw7Q1QF6OkBfBxjoAEMdYKQDjHWAiQ7wrQNMdYCZDjDXAX50gIUOsNQBVjrArw7wpwP86wBrHWCjA2x1gJ0OsNcBDjrAUQc46QBnHeBiA9wALSueIjTE4PwAAAAASUVORK5CYII="
)).arrayBuffer());
});
})();

View File

@ -166,7 +166,7 @@ globalThis.modapi_postinit = "(" + (() => {
return name;
}
ModAPI.util.asClass = ModAPI.util.asClass = ModAPI.hooks._teavm.$rt_cls;
ModAPI.util.asClass = ModAPI.hooks._teavm.$rt_cls;
ModAPI.util.wrap = function (outputValue, target, corrective, disableFunctions) {
target ||= {};
@ -413,7 +413,7 @@ globalThis.modapi_postinit = "(" + (() => {
//Magical function for making a subclass with a custom constructor that you can easily use super(...) on.
ModAPI.reflect.getSuper = function getSuper(reflectClass, filter) {
filter ||= () => true;
filter ||= (x) => x.length === 1;
var initialiser = reflectClass.internalConstructors.find(filter);
return function superFunction(thisArg, ...extra_args) {
reflectClass.class.call(thisArg);